policy.json 是 CC Safety Net 的设置文件。它用于选择安全预设、开关内置保护、添加受保护路径,以及设置审计记录的保留时间。它有两个范围:用户文件,以及可选的、提交到仓库的项目文件。
它与 rule.json 和 rulebook 分开。后两者用于定义自定义阻止规则,schema 见自定义规则。
策略文件位置
设置
CC_SAFETY_NET_HOME 后,用户文件直接位于该目录下,与 rules/ 同级。覆盖变量本身参见环境。
CC_SAFETY_NET_HOME 只作用于用户文件。项目文件始终是项目根目录下的 .cc-safety-net/policy.json,与规则范围解析的目录相同。
运行时在每次工具调用时读取这两个文件。用户文件是基线,项目文件叠加在它之上。参见项目策略。
仪表板写入用户文件时,会以 0700 创建目录、以 0600 创建文件。
项目策略
把.cc-safety-net/policy.json 提交上去,团队就能通过仓库分发一份安全策略。成员无需运行任何命令,运行时会在下一次工具调用时读取该文件,仓库的每一份检出都是如此。
项目文件是稀疏的:只写入它设置的字段,未写入的字段继续从用户策略继承。只设置了一条规则覆盖的项目文件,就只改变那一条规则。
生效策略是用户策略叠加项目策略的结果:
项目文件中的
audit 部分会被忽略,加载时报告 project policy audit settings are ignored; audit is user scope only。
报告的削弱
项目策略按写下的样子生效,没有任何机制会把它拉回用户策略的基线。相应地,它相对用户策略放宽的每个字段,都会各自报告一行:project policy lowers level: <user> -> <project>project policy disables fail_closed、project policy disables paranoid_rm、project policy disables paranoid_interpretersproject policy enables worktree mode relaxationsproject policy disables destructive command protectionproject policy disables secret protectionproject policy disables rule <id>project policy adds destructive allow path: <path>project policy adds secret allow path: <path>
status增加一行Project显示项目文件的路径,并增加一个Project policy区块列出这些行。- 只要存在任何削弱,状态行就显示
🔻。参见状态行。 doctor在 Effective Safety 下输出Project policy deltas:区块。doctor和explain会在安全预设旁标出提供它的范围,取user policy、project policy或built-in default。参见 Explain 跟踪。
策略文件保护
policy.json 在两个范围中、在每个运行时状态(ready 或 degraded)下都是受保护路径。策略文件保护在加载策略快照之前运行,因此损坏的配置无法削弱它。以下操作一律硬停止:
- 通过任何工具对该文件的写入、编辑和修补
- 以该文件作为操作数的 Shell 命令
- 指向该文件的写入重定向
- 对其所在目录或任何上级目录的递归
rm - 触及该文件的
find … -delete和find … -exec rm - 以该文件、其所在目录或上级目录为源的
mv
.cc-safety-net 目录。目录链到此为止是有意为之。再往上走就会把工作目录及其全部上级目录也纳入进来,而本防护先于其他检查运行,于是 rm -rf . 和 find . -delete 会报出这条通用原因,而不是破坏性命令规则本该给出的具体原因。
读取仍然允许。只读命令允许列表包括 [、cat、file、grep、head、jq、less、ls、more、rg、sed、stat、tail、test 和 wc。sed 仅限未使用 -i 或 --in-place 就地编辑的情况。Grep、Glob 等只读工具不受此限制。
编辑策略文件
选择以下选项之一:- **使用仪表板。**运行
cc-safety-net gui。仪表板会以正确的权限写入文件,并且能修复校验不通过的文件。文件存在错误期间,表单显示的是完整的默认值,而不是文件中那些有效的值。在修复文件之前无法保存。修复会保留每一项可识别的有效设置,并丢弃无效字段。如果不想要这种修复行为,请手动编辑文件,并用status检查。 - 直接编辑 JSON。 在编辑器中打开文件手动修改。运行时会在下一次工具调用时读取改动,无需重启任何东西。
- 应用提案。 运行
cc-safety-net policy apply <file>,在终端确认差异后,把提案文件写入其中一个范围。参见确认并应用提案。
degraded,说明文件中有字段被拒绝。npx cc-safety-net doctor 会指出具体字段。运行时从不自行重写 policy.json。在你手动修复或使用仪表板修复前,无效文件会原样保留。
确认并应用提案
policy check 和 policy apply 把同一个流程拆给智能体和你。智能体写出提案 JSON,运行 policy check 展示它会改变什么。policy apply 由你自己在终端里运行。
Effective policy (user + project merged): 这一行标明的就是这件事。稀疏的提案同样会改变会话实际运行的级别,因此确认时展示的是合并结果,而不是文件自身的内容。加上 -g, --global 后,头部变成 Scope: user (<path>),没有那一行合并说明,差异比较的是用户文件和提案本身,并且包含 audit.retention_days。
差异行在 Changes (<n>): 标题下按 <field>: <before> -> <after> 的格式排列。某一侧不存在时显示 (unset)。没有任何改动时,命令输出 No changes.。
项目提案中如果带有 audit 部分,会在输出差异之前被拒绝,报 <file>: audit settings are user scope only; remove the audit section from a project proposal。
policy apply 要求 stdin 和 stdout 都是 TTY。不是 TTY 时,它会打印出该由你运行的命令,并以退出码 1 结束:
Apply this policy to <path>? [y/N] 。只有 y 或 yes 表示接受,不区分大小写;其他输入都算拒绝,EOF 同样如此。拒绝时输出 Cancelled; nothing was written. 并以退出码 0 结束。写入成功时输出 Policy applied: <path>。没有 --yes 选项,也没有非交互模式。
智能体运行 policy apply 会被硬停止,原因文本正是:
npx、bunx、pnpx、pnpm dlx 和 yarn dlx、npm exec、pnpm exec 和 yarn exec、cc-safety-net@latest 这类带版本的写法,以及用 bun 或 node 执行入口文件;目标前面带有运行器选项时同样匹配。policy check 对智能体仍然放行。
完整的策略示例
包含每个字段及其默认值:version 是必填的。其余字段都可以省略,省略时采用上面显示的默认值。如果该文件根本不存在,CC Safety Net 就按这些默认值运行,并保持 ready。
根对象是严格的:无法识别的顶级键会报错,safety、workflow、destructive_command_protection、secret_protection 或 audit 内无法识别的键同样如此。
Schema 参考
integer
必填
Schema 版本。必须为
1。这是唯一的必填字段;值缺失或错误时的诊断信息是 version must be 1。string
默认值:"standard"
安全预设。取
"standard"、"strict" 或 "paranoid" 之一。每个预设都提供一组继承而来的能力默认值:strict 启用 fail_closed;paranoid 启用 fail_closed、paranoid_rm 和 paranoid_interpreters。各项能力具体改变了什么,参见模式。boolean
无论预设如何,都显式设置 fail-closed 能力,可调高也可调低。省略该键则从预设继承。
boolean
显式设置偏执
rm 能力,可调高也可调低。省略该键则从预设继承。boolean
显式设置偏执解释器能力,可调高也可调低。省略该键则从预设继承。
boolean
默认值:"false"
在已确认的 linked worktree 内放宽本地丢弃类 git 规则。检测采用 fail-closed:如果无法明确判定工作目录位于 linked worktree 中,仍然沿用更严格的默认规则。哪些规则会放宽、哪些永不放宽,确切列表参见模式。
boolean
默认值:"true"
已注册破坏性命令规则的总开关。设为
false 会短路所有已注册规则,但灾难性规则除外。灾难性规则始终强制执行。object
默认值:"{}"
按已注册破坏性命令规则 ID 设置的单项规则状态,值为
"on" 或 "off"。它叠加在能力推导出的状态之上,因此 "on" 可以启用预设未开启的规则,"off" 可以关闭预设开启的规则。string[]
默认值:"[]"
免于破坏性命令规则约束的路径。条目必须是绝对路径,或以
~/ 开头。boolean
默认值:"true"
机密保护总开关。设为
false 会跳过整个机密阶段,包括你配置的 deny_paths。object
默认值:"{}"
按已注册机密保护规则 ID 设置的单项规则状态,值为
"on" 或 "off"。启用机密保护时,大多数机密规则默认开启,因此通常使用 "off"。编码 CLI 配置层默认关闭,显式写 "on" 才能启用其中的规则。integer
默认值:"30"
清理删除前保留的审计历史天数。必须是
1 到 365 之间的整数。安全级别和能力覆盖
safety.level 选择预设,然后由 safety.overrides 显式设置各个能力。只有这里可以降低能力,环境标志只能提高能力。
paranoid 预设,但关闭了对所有解释器单行命令的一律阻止。最终的能力组合不匹配任何预设时,有效级别会报告为 custom。
环境可以提高策略的级别、强制开启某些能力,但反过来不行。
policy.json 与环境之间的完整优先顺序参见环境,其中包括 worktree_mode 的逻辑 OR 组合和旧版 SAFETY_NET_* 别名。破坏性命令保护
destructive_command_protection.overrides 通过 id 指定内置规则,例如:
unknown destructive command rule id "<id>";除 "on" 或 "off" 之外的任何值都会被拒绝,报 destructive_command_protection.overrides.<id> must be "on" or "off"。
灾难性规则始终强制执行,用户不可配置。 它们忽略 enabled: false,也忽略 "off" 覆盖。这些规则涵盖删除 / 或主目录、删除 Git 元数据,以及它们在 PowerShell 和 find 下的等价形式。各规则强制执行的具体行为参见被阻止的命令。
允许路径
destructive_command_protection.allow_paths 将特定位置排除在破坏性命令规则之外。验证比拒绝路径更严格:
机密保护
机密保护会阻止读写含凭证的文件。本节说明配置约定。内置规则的完整目录,包括每个 id、受保护路径和豁免,见机密保护参考。secret_protection.overrides 通过 id 指定单条内置规则,值为 "on" 或 "off"。"off" 关闭默认开启的规则;"on" 用于选择启用默认关闭层中的规则:
unknown secret protection rule id "<id>";其他任何值都会被拒绝,报 secret_protection.overrides.<id> must be "on" or "off"。
默认情况下关闭的规则
只要启用了机密保护,大多数内置机密规则都处于开启状态。有一层例外:编码 CLI 配置规则,它涵盖受支持的编码智能体的设置文件和 MCP 配置文件。这些文件可能内嵌凭证,但智能体也会把编辑它们当作日常工作,因此该层默认关闭,需要你逐条用显式的"on" 覆盖来选择启用。启用某条配置规则后,它会保护该智能体的用户级配置文件,同时也会保护任意仓库根目录下按名称匹配的项目级文件,例如任何 .mcp.json。
十个默认关闭的 id、它们默认开启的 编码 CLI 凭证 对应规则,以及每条规则保护的确切路径,都列在机密保护参考中。
拒绝路径
secret_protection.deny_paths 在内置敏感路径之上添加你自己的受保护位置。拒绝路径会先于内置规则检查,一旦命中即为硬停止,归因于规则 ID secret.deny-path。
验证:
相对条目会按各会话的工作目录解析,因为保存策略时无法确定会话目录。主目录、主目录的上级路径和
/ 会被拒绝。这些路径会阻止主目录下几乎所有工作区中的命令。
有效的拒绝路径保护什么:路径本身及其所有后代。比较之前,目标按执行工作目录规范化,每个配置的路径按配置工作目录规范化。
有两个限制值得了解:
- 拒绝路径仅在
secret_protection.enabled为true时生效。设为false会连同机密阶段的其他一切一起关闭它们。 secret.deny-path不是已注册的机密规则 ID,因此secret_protection.overrides无法禁用它。只有secret_protection.enabled: false可以。
机密允许路径
secret_protection.allow_paths 把精确的文件或目录及其所有后代从内置的 basename、主目录、密钥变体和扩展名规则中豁免出来。它适用于你有意管理的文件,例如仓库中的 .env.test,或包含形似凭证但并非机密的文件名的 fixture 目录。
优先顺序是固定的:
- 配置的拒绝路径始终优先。如果同一目标同时出现在两个列表中,结果是
secret.deny-path。 - 编码 CLI 凭证和配置规则(
secret.cli.*)始终优先。允许路径无法暴露智能体自身的凭证或配置。 - 命中允许路径会抑制该目标上的其他任何内置机密规则。
条目是字面路径,而不是 glob 模式。目标按执行工作目录解析,相对的允许条目按配置工作目录解析。在进行相同或后代比较前,两边都会跟随现有符号链接,因此允许根目录也涵盖通过符号链接到达的目标。
运行时会在解析后再次检查安全边界。解析结果为主目录或主目录上级的条目会被忽略。位于生效的防护配置根目录之下的目标永远不会被豁免,包括
CC_SAFETY_NET_HOME 改变了该根目录时,以及主目录或 ~/.cc-safety-net 是符号链接时。
审计保留
audit.retention_days 控制审计记录在保留期清理将其删除之前能保留多久。默认值为 30 天,接受的范围是 1 到 365。
保留期独立于策略的其余部分解析。清理扫描直接从文件中读取这一字段,因此即使策略的其他部分验证失败,清理仍会照常进行。缺失、非整数或不可用的值会回落至 30;低于
1 的值被限制到 1,高于 365 的值被限制到 365。因此,超出范围的值会同时引发两件事:schema 拒绝它们,使运行时降级;而清理扫描把它们限制在范围内。"retention_days": 1000 既会作为诊断出现,又会按 365 天清理。无效策略的行为
无效的policy.json 永远不会阻止正常工作。它会把运行时置为 degraded 并改用回退值。下表描述的是单个文件。两个范围走同一套挽救流程,每条诊断都以来源文件的路径作为前缀。
回退过程优先保留保护,因此损坏的文件通常会产生比原配置更多的拒绝:
损坏的项目文件也按同样的方式挽救:被拒绝的部分丢弃,两个文件中的其余内容继续生效。用户文件无法读取、而项目策略仍然提供了字段时,这些项目字段是生效的,因此报告的是挽救而不是内置默认值。只要项目文件存在,无论是否有效,都会记录字段来自哪个范围,所以
status 会一直打印 Project 行。
配置恢复是 degraded 状态的完整契约,包括它如何上报,以及如何回到 ready。
相关页面
模式
每种安全能力改变了什么,以及 worktree 模式放宽了哪些规则。
环境
全部变量,包括那些能提高策略级别的变量。
自定义规则
用于自定义阻止规则的独立
rule.json 与 rulebook schema。配置恢复
ready 与 degraded、回退矩阵和修复步骤。