/** Display-only redaction. Raw event payloads must never cross this boundary. */ const CONTROL_CHARACTERS = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g; const PEM_BLOCK = /-----BEGIN [^-]+-----[\s\S]*?-----END [^-]+-----/gi; const AUTH_VALUE = /\b(password|passwd|token|api[-_ ]?key|secret|authorization|cookie)\b\s*[:=]\s*[^\s,;]+/gi; const BEARER = /\bbearer\s+[A-Za-z0-9._~+/-]+=*/gi; const JWT = /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g; const CREDENTIAL_BLOB = /\b(?=[A-Za-z0-9_+/#.-]{40,}\b)(?=[A-Za-z0-9_+/#.-]*[A-Za-z])(?=[A-Za-z0-9_+/#.-]*\d)[A-Za-z0-9_+/#.-]+\b/g; const URI_USERINFO = /\b([a-z][a-z0-9+.-]*:\/\/)[^\s/@:]+:[^\s/@]+@/gi; /** Return bounded plain text or a safe fallback; objects are never stringified. */ export function safeText( value: unknown, fallback: string, maxLength = 280, ): string { if (typeof value !== "string") return fallback; const limit = Math.max(1, maxLength); const redacted = value .replace(PEM_BLOCK, "[redacted credential]") .replace(AUTH_VALUE, "$1=[redacted]") .replace(BEARER, "Bearer [redacted]") .replace(JWT, "[redacted credential]") .replace(URI_USERINFO, "$1[redacted]@") .replace(CREDENTIAL_BLOB, "[redacted credential]") .replace(CONTROL_CHARACTERS, " ") .replace(/\s+/g, " ") .trim(); if (!redacted) return fallback; return redacted.length <= limit ? redacted : limit === 1 ? "…" : `${redacted.slice(0, limit - 1).trimEnd()}…`; } const EVIDENCE_LABELS: Readonly> = { message: "Message", tool_call: "Tool call", tool_result: "Tool result", artifact_version: "Artifact version", source: "Source", passage: "Supporting passage", memory: "Memory record", approval: "Approval", run: "Run", url: "Website", file: "File", build: "Build", flux: "Flux reconciliation", pod: "Workload", }; /** Evidence labels are deliberately detached from IDs, URIs, and payloads. */ export function safeEvidenceLabel( kind: unknown, ): { kind: string; label: string } | null { if (typeof kind !== "string" || !(kind in EVIDENCE_LABELS)) return null; return { kind, label: EVIDENCE_LABELS[kind] }; } export function isRfc3339Utc(value: unknown): value is string { return ( typeof value === "string" && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,6})?Z$/.test(value) && !Number.isNaN(Date.parse(value)) ); } export function isOpaqueId(value: unknown, prefix?: string): value is string { if (typeof value !== "string") return false; if (!/^[a-z]{2,6}_[A-Za-z0-9._-]{4,80}$/.test(value)) return false; return !prefix || value.startsWith(`${prefix}_`); }