/** * A18 — diagnostics data minimization + secret redaction (verdict #2 item 21). * * Diagnostics (status lines, notify strings, recovery give-up events) may carry * protocol identifiers (conversation ids, session sid, capability HASHES) — those * are identity, not secrets, and status is allowed to show them. What diagnostics * must never carry is anything that grants authority or reveals message content: * capability objects, grant/token values, message payloads, cookies, raw DOM. * * redactForDiagnostics() is the single scrubber for error/note text that enters * diagnostics. The rule is CONTEXTUAL so that protocol identity survives: * - `sk-…`, `Bearer …`, `Authorization: …` — always masked * - long hex runs (>= 24) that sit next to token/key/secret/api_key/authorization * or in a URL query (?token=, &api_key=) — masked * - bare UUIDs / conversation ids — left intact (they are display identity) */ const BEARER = /\b(Bearer\s+|sk-[A-Za-z0-9_-]{8,}|Authorization:\s*)[A-Za-z0-9._~+/=-]{12,}/gi; const QUERY_TOKEN = /([?&](?:token|api[_-]?key|secret|access[_-]?token|session[_-]?token)=)[^&\s]{6,}/gi; const CONTEXTUAL_HEX = /([a-zA-Z0-9_-]*(?:token|key|secret|auth)[a-zA-Z0-9_-]*\s*[=:]\s*)[0-9a-fA-F]{24,}/g; // B 轮合规整改(数据流声明 B8):cookie 从不进入诊断正文,即使进了也在此掩码。 const COOKIE_HEADER = /\b((?:set-)?cookie\s*:\s*)[^\n]{6,}/gi; export function redactForDiagnostics(text: string): string { let out = String(text ?? ""); out = out.replace(BEARER, "$1••••••(已净化)"); out = out.replace(QUERY_TOKEN, "$1••••••"); out = out.replace(CONTEXTUAL_HEX, "$1••••••"); out = out.replace(COOKIE_HEADER, "$1••••••(已净化)"); return out; }