统一错误事件同步留痕到 AppData 应用日志 #453
Reference in New Issue
Block a user
Delete Branch "feat/log-the-dianosis"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
统一错误事件的同一份已脱敏诊断投影成应用日志
- metadata 之前直接以 {metadata} 插值进日志行,只靠 Value::to_string() 的转义保证单行,和函数「每个字段都先压平」的约定不一致 - 改为与其他字段一样走 single_line_log_field,日志行完整性不再依赖序列化器的转义行为 - 验证:cargo test runtime_error(7 passed)- 生产是把两行分别交给 append_application_log_line 脱敏截断,原用例先 join(" ") 再 sanitize,测不到逐行截断与「只该脱敏其中一行」的情况 - 改为逐行 sanitize,并分别断言身份行(eventId/code/detailRef/summary)与详情行(detail 脱敏、metadata 无凭据) - 验证:cargo test runtime_error(7 passed)1 身份行 summary 只压行未脱敏(security · medium)
agent_runtime_error_app_log_lines对public_text只做single_line_log_field;身份行summary=原样进app_log!。现在该行:runtime_error.rs:173。app_log!(main.rs:73)先format!再eprintln!,stderr 这条路径没有sanitize_diagnostic_message;而direct_tool_bridge.rs:3348把工具错误原文result.pointer("/content/0/text")同时当public_text与detail传进来,内容不可控。落盘那份虽有兜底,但 stderr 会漏原文。AGENT_RUNTIME_ERROR_APP_LOG_SUMMARY_CHARS = 320(与 sidecar 摘要预算同口径),summary 先redact_agent_runtime_error再压行;函数合同改为「summary / detail / metadata 三类外来文本都在这里脱敏」,不再只是压平换行。同步了两份技术文档与 decision-log 的预算口径。2 metadata 没走压行(maintainability · low)
metadata={metadata}插值,只靠Value::to_string()的 JSON 转义保证单行。现在该行:runtime_error.rs:190。metadata与其他字段一样过single_line_log_field。3 用例先 join 再 sanitize,测不到逐行行为(test · low)
join(" ")后只 sanitize 一次。现在该用例:runtime_error.rs:262。app_log!→append_application_log_line逐行脱敏与逐行截断(chars().take(2_048)),拼接后测不到「只该脱敏其中一行」「身份行被截断」这两类。5 「只再截一次」的注释与实现不符(maintainability · low)
detail跑完整redact_agent_runtime_error(含root.canonicalize()与标记保留逻辑)。现在注释:runtime_error.rs:137。[redacted-secret]这类标记切开,不能假设截断后的文本仍满足前置条件;② 这是pub(crate)边界,不应把安全性绑定在调用方自觉上;③ 代价只是一次可忽略的 canonicalize(只在终态失败时发生)。6 用例传的是未脱敏原文,与前置条件不符(test · low)
token=secret的原文 detail,而生产persist_agent_runtime_error传的是已脱敏的safe_detail。现在该用例:runtime_error.rs:268。redact_agent_runtime_error造出safe_detail再传入(与生产一致),metadata仍按生产原样传未脱敏 JSON,脱敏覆盖不丢。4 身份行仍可能被整行脱敏吃掉(bug · medium)— 已按方案 A 修复(提交 74e6ac90a)
agent.runtime.error eventId=… source=… stage=… code=… retryable=… clientTurnId=… elapsedMs=… detailRef=… summary=<public_text>。其中 source / stage / code 是调用方给的常量,clientTurnId / detailRef / eventId / elapsedMs 由程序生成,自由文本只有 summary 这一处。
sanitize_diagnostic_message(main.rs:1922-1946)的判定是「整行 lowercase 命中authorization/bearer/api_key/apikey/api key/x-api-key/token=/token:/credential任一 → 整行替换成<sensitive diagnostic details redacted>(信息全丢)」。第 1 条的脱敏能消掉赋值形式与 bearer+value,但裸词消不掉:例如工具错误原文里出现 “credential rotation failed” 或 “authorization header missing”,summary 原样保留该词,身份行连 eventId / detailRef 一起消失——正是拆两行想避免的那种失败,在身份行自己身上重演。summary移到详情行(hint / summary / detail / metadata);自由文本从此只出现在详情行,整行替换最多吃掉详情行。同步了两份技术方案、决策记录与踩坑记录的两行字段口径。summary = "credential rotation failed"时断言身份行仍含eventId/code,且详情行确实被替换成<sensitive diagnostic details redacted>。验证:cargo test -- runtime_error direct_tool_bridge(41 passed)。source/stage/code/clientTurnId。