v0.3.1 增量:MCP / CLI 统一有界日志证据¶
历史增量说明。 本文记录 v0.3.1 阶段的日志证据增量,不代表当前 v0.5.0 全部 EvidencePack/CI 行为。当前实现见架构说明、证据审查页面和v0.5.0 发布说明。
基线:合入 #7、#8 后的 main,b2e743b7d635dd438238cfb875a864d1cf3ed6d4。
本补丁仍是独立 review candidate,不代表 v0.3.1 已发布。
实现范围¶
新增 gitlab_agent.log_evidence,同步 CLI 与异步 MCP 共用一个 SafeLogTail。
GitLabAPI.job_trace_tail、兼容的文本接口 job_trace 和 MCP get_job_log
都走这一条读取/脱敏规则。MCP 不再先完整读取 trace 再截取原始尾部。
流式处理顺序:完整的有界行 → 去除支持的 ANSI 控制序列 → 凭证/私钥脱敏 → 保留有界 UTF-8 尾部。凭证跨 HTTP chunk 时仍作为同一行识别;私钥 BEGIN 即使已离开最终展示尾部,其后续内容仍保持抑制,直到 END 或响应结束。
这不是任意格式的 DLP 检测,不承诺识别所有编码、拆行或变形的秘密。
范围、限制与返回值¶
| 项目 | 策略 |
|---|---|
| 返回 tail | 1,000–80,000 字节;MCP 还受现有 max_text_bytes 限制(最小仍为 1,000) |
| 最大输入 trace | 16 MiB;超限不返回部分日志 |
| 最大单行 | 64 KiB,含换行;超限拒绝,不输出可能含凭证的残片 |
| 网络读取 | 每次网络操作最长 10 秒,MCP 配置更小时进一步收紧 |
| elapsed budget | 30 秒,MCP 配置更小时进一步收紧;在 chunk/行处理及 EOF 检查 |
| HTTP | 仅接受完整 HTTP 200;拒绝重定向、部分响应和压缩响应 |
| 编码 | UTF-8;非法编码或不支持的终端 escape 拒绝整个日志结果 |
elapsed budget 是协作式检查,不是 OS 级硬实时截止时间;阻塞中的网络读取
可能再持续一次 read timeout,DNS/平台调度也不提供严格实时保证。
不通过后台线程遗留下载,也不在失败后把已读前缀称作真正日志末尾。
客户端发 Accept-Encoding: identity,用原始流读取,避免在 size gate 前
进行自动解压。配置的 HTTP GitLab、TLS verification、proxy 和 token 分离
策略保持不变。trace 请求不跟随重定向,避免把自定义凭证头转发给新地址。
其他非 trace 元数据请求的行为不在本补丁范围内。
成功结果保留 content / truncated / original_text_bytes / tail_bytes,新增:
read_complete: true:本次 trace 响应已读完,不等于整个 job 已结束;sanitized: true、redactions:执行了启发式脱敏,不等于发现了所有秘密;returned_text_bytes、sanitized_text_bytes:展示长度与脱敏后的总长度;scope与trust: untrusted_diagnostic_data:日志只能作诊断数据,不能授权操作。
original_text_bytes 是脱敏前原始 UTF-8 响应的字节数;输出 cap 在脱敏后也
会执行,截断时不会返回损坏的 UTF-8 字符。truncated 表示输入或脱敏后
内容超出 tail 范围,并不表示网络读取失败。
失败处理与 CI 集成¶
HTTP 错误、重定向、压缩、超限、超时、传输失败和非法编码,不返回原始错误 body、URL 或 transport exception 文本,也不产生成功的部分 tail。 已知的安全错误保留状态码/限制原因,未知错误使用固定提示。
CLI ci 仍可显示真实 pipeline/job 元数据;失败的日志条目会有空 content、
read_complete: false 和明确 error/warning。新增 failed_job_logs_complete
同时考虑未能读取与因 max-failed-jobs 而未抓取的日志。成功获取所有 tail
也不意味着完整日志文本都显示了;需同时看每个条目的 truncated。
repair_context 明确包含“响应是否读完”和“tail 是否截断”,不自动修复、
重试、push 或合并。现有 HEAD/CI stale 检查保持不变。
旧的 in-process adapter 缺少新元数据时,继续防御性脱敏,但 completeness 标记为未知,不凭空推断已验证完整读取。
兼容性提醒¶
job_trace现在返回有界、脱敏的文本视图,而非无界原始全文;要检查证据 范围应使用job_trace_tail。仓库内正式 MCP/CLI 日志路径都使用有界接口。- 某些代理坚持返回 gzip/重定向,或日志使用超长行/非 UTF-8/OSC 等终端 控制串时,会被拒绝;应修正日志/代理行为,而非自动退回无界原始读取。
- 本补丁只保护 trace body 及其读取错误路径;其他 GitLab 元数据、源文件、
MR 描述、通用
get_text/get_json、本地 runner 输出不因此成为已脱敏内容。 - 命令执行不是 sandbox。进程树终止、workspace locking、原子 review/write 和完整 candidate blob/index 审计仍是后续任务。
验证¶
新增 test_log_evidence.py 覆盖公共处理器、真实 HTTPX sync/async 流、
边界条件和 CLI CI evidence;test_mcp_log_evidence.py 导入实际 MCP server,
以本地 MockTransport 验证公开 endpoint、allowlist、token gate 与大小限制。
不连接业务 GitLab,不调用模型。原有 API 测试保留断言,只更新流式 mock
的 raw-byte 接口与显式请求参数。
参考:HTTPX 官方 Streaming Responses / Async Support;GitLab Jobs API 的 GET job trace 接口。本实现不假设 GitLab 提供 suffix Range 支持。