Skip to main content
CC Safety Net 会为命令决策写入结构化审计记录。你可以查看智能体尝试执行的操作及其结果。日志使用 JSON Lines(JSONL)格式,每行一个 JSON 对象,并存储在本机。 本页定义文件布局、记录模式、范围、保留以及脱敏的边界。要在 UI 中查看日志,请参阅 Dashboard。要在终端中查看,请参阅 logs

日志布局

记录写入按项目、按月划分的路径:
会话 ID 写入文件名前会先清理:A-Za-z0-9_.- 之外的连续字符折叠为 _,开头和结尾的 .-_ 会被删除,结果截断到 128 个字符。如果清理后是空字符串、...本次写入会被放弃。这是为了防止路径遍历。 目录以模式 0700 创建,日志文件以模式 0600 追加。 写入失败会被忽略。审计日志记录不会改变允许或阻止的决策。
直接位于 ~/.cc-safety-net/logs/ 下的平面文件是早期版本的旧版布局。logs 仍会读取它们,保留清理也仍会扫过它们,logs --prune-legacy 针对的正是它们。新记录不会再写入那里。

每条记录包含一个决策

每行恰好记录一条允许或阻止的命令决策:命令、促成该决策的片段、原因,以及匹配的规则。
  • 写入路径上的任何环节都不会读取或存储命令输出、模型提示词、工具结果或对话内容。
  • 拒绝始终会被记录。
  • 允许的决策只有在工具调用确实路由到命令时才会记录。被允许的非命令工具调用完全不产生记录。
  • 来自 fail-closed 路径的阻止被记录,并带上 failureStageerrorCode 标记。这表示分析器出错后,防护选择拒绝而不是猜测。logs --suspect 就建立在该字段之上。

记录模式

示例记录:

长度上限和截断标志

上限在脱敏之后才应用,因此脱敏不会在某个令牌中途被切断。 failureStage 的条目是诊断 fail-closed 事件的主要记录,因此它保存完整命令,而不是截断后的命令。工具输入的字节上限在上游已经限定了这个长度。segmenttoolNamecwd 的上限不变,同样适用于这类条目。 只要 commandsegmenttoolNamecwd 中有一个超出上限,记录就会带上 truncated: true。在带 failureStage 的条目中,命令没有可超出的上限,因此命令再长也不会单独触发该标志;segmenttoolNamecwd 仍然会。该标志不会写成 false。它不出现就表示没有内容被截断。logs --id 会把它显示为 truncated: yes-

记录内容:审计范围

CC_SAFETY_NET_AUDIT_SCOPE 决定允许的命令决策是否与拒绝一起记入日志。 无效值不会被悄悄放过。doctor 会以警告严重级别报出 environment.audit-scope-invalid,说明审计范围值无效,并给出修复提示:把该变量设为 allblocked,然后重启集成。有问题的值本身刻意不会回显出来。 范围永远不会抑制拒绝,它只对允许分支起作用。

保留

audit.retention_days 必须是 1 到 365 之间的整数;其他任何值都会在校验时被拒绝,而完全无法使用的值会回退到 30 天的默认值。保留期是单独直接从策略文件读取的,因此即使策略的其余部分校验失败,清理仍能正常工作。 同一个值也限定了 logs --since 的上限,以及 GUI Activity 视图提供的窗口。
缩短保留期不可逆。清理扫描每次运行都会重新计算截止时间,因此调低该值会让已有记录立刻符合删除条件并被直接删除。没有归档或回收站,也无法撤销。正因如此,GUI 在调低该值之前会要求你确认。

清理是伺机进行的

没有任何定时任务。保留清理由活动触发:
  • 每次审计写入之后(刻意放在写入之后,这样清理失败绝不会连累记录本身),
  • logs 读取之前,
  • doctor 构建其活动摘要之前,
  • 在 GUI 活动信息流加载之前。
清理扫描对每个审计根目录每个 UTC 日最多遍历一次,由审计根目录中零字节的 .last-prune 标记来节流。它从不抛出异常,从不创建审计根目录,从不跟随符号链接,任何它不认识的文件形态都原样保留。空的月份目录和空的项目目录会被回收,但当前月份会保留,以避免与正在进行的写入发生竞争。旧版平面文件只有在文件时间戳和其中每一条记录都证明它已整体过期时才会被删除;记录新旧混杂的文件绝不会被重写或拆分。 CC Safety Net 空闲期间,过期记录可能一直留在磁盘上,因为没有任何东西会启动清理扫描。logs --id 搜索的是磁盘上现存的记录,如果清理还没轮到它,就仍可能返回一条已过保留期的记录。

删除旧版日志

cc-safety-net logs --prune-legacy立即且不可逆地删除审计根目录中所有旧版平面 *.jsonl 文件。没有确认提示,也没有 --yes 标志;唯一的预览方式是 --dry-run,它会准确报告将被删除的文件集合,而不删除任何东西。是否属于该集合仅由文件位置决定,与年龄、模式是否有效或行是否格式错误无关。
这不是保留清理。保留清理只在旧版文件整体过期时才删除它们;--prune-legacy 则不论年龄一律删除。它绝不会进入嵌套的按项目日志目录,也绝不会触碰那里的文件,命令的输出中也会说明这一点。有关该标志的退出行为及它拒绝的参数组合,请参阅 logs --prune-legacy

计数和返回的条目

计数覆盖整个窗口,而条目列表有数量上限,因此两个数字可能对不上。 logs 扫描日志时,每个被丢弃的来源都会计入统计,包括不可读的目录、不可读的文件或格式错误的记录。stderr 会输出警告:warning: N audit log sources could not be read; these results are incomplete(N 为 1 时用 source)。警告不会给出任何路径,stdout 和退出码也保持不变,因此 --json 输出仍可解析。日志目录不存在意味着历史为空,而不是有来源被丢弃,因此不会产生警告。 普通的列表窗口和 GUI 窗口都不会回溯到保留期之前。GUI 的窗口选项由你的保留期推导得出,而不是一份固定列表。只要过期记录还在磁盘上、清理尚未删除它,直接用 logs --id 查询仍可能把它返回。各保留期设置下可选的窗口,请参阅 Dashboard

机密脱敏

命令、片段、工具名称和工作目录会在记录序列化之前经过机密脱敏。识别出的值会被替换为 <redacted>
  • 其名称包含 TOKENSECRETPASSWORDPASSKEYCREDENTIALS 的环境变量赋值
  • 数据库连接变量(DATABASE_URLPOSTGRES_URLMYSQL_URLREDIS_URLMONGODB_URL,以及其他 DSN/URL/URI/连接字符串变量)
  • PEM 私钥块(-----BEGIN ... PRIVATE KEY-----
  • 携带机密的 HTTP 标头(AuthorizationCookieX-API-KEYAPI-KEY
  • URL 凭证(scheme://user:pass@hostscheme://token@host)以及 -u user:pass
  • 预签名 URL 的签名查询参数,即 x-amz-signaturex-goog-signaturesigsignature 的值;当参数名紧跟在文本开头、空白、?&;| 之后时,按不区分大小写匹配
  • 一份固定的提供商令牌格式列表(ghp_...gho_...xoxb-...npm_...sk_live_...rk_live_...pypi-... 等)
  • JWT(eyJ...)和 AWS 访问密钥 ID(AKIA... / ASIA...
脱敏是有边界的。 它只是一份固定的模式列表,而不是分类器。凡是它不认识的内容都会原样保留:绝对文件系统路径、项目和目录名称、主机名、IP 地址、用户名、工单 ID、文件名,以及任何形式不在列表中的凭证。reason 字段在写入时完全不做脱敏。请把审计日志当作敏感的本地数据,把任何摘录粘贴到 issue 或聊天之前先检查一遍。
GUI 在发送误报报告前会去掉主目录前缀。其他路径仍可能留在报告里。 权限(目录 0700、文件 0600)和本地存储限制的是访问权。它们不会对日志脱敏,也不会让日志变得可以安全分享。

相关页面

  • CLI 命令logs 命令、它的过滤器和 JSON 输出。
  • Dashboard:在 GUI 活动信息流中读取同一批记录。
  • 策略audit.retention_days 字段及其校验。
  • Explain 跟踪explain 输出也适用同样的脱敏边界。
  • 安全模型:审计日志在整体威胁模型中的位置。
最后修改于 2026年8月31日