# AGENT-GUARD [![CI](https://github.com/mokuyoaxis/agent-guard/actions/workflows/ci.yml/badge.svg)](https://github.com/mokuyoaxis/agent-guard/actions/workflows/ci.yml) [![npm 版本](https://img.shields.io/npm/v/%40mokuyoaxis%2Fagent-guard.svg)](https://www.npmjs.com/package/@mokuyoaxis/agent-guard) [![License](https://img.shields.io/github/license/mokuyoaxis/agent-guard)](LICENSE) [![Python 3.9+](https://img.shields.io/badge/Python-3.9%2B-3776AB?logo=python&logoColor=white)](https://www.python.org/) [![v0.2.3-rc2 源码](https://img.shields.io/badge/%E6%BA%90%E7%A0%81-v0.2.3--rc2-5B6B7A)](docs/release-notes-0.2.3-rc2.md) **让 AI Agent 的破坏性操作默认可逆。** · [English](README.md) Agent Guard 是给编码 Agent 用的可靠性工具:让受支持的高风险操作尽可能 可恢复,而不是一次失手就永久损失;日常工作则尽量不被打断。 - **删除文件**:可先迁入 `.agent-trash/`,留下恢复清单,而非直接销毁。 - **破坏性 Git 操作**:可先保存可恢复的状态,再覆盖工作树。 - **意外外发**:合作式文本 CLI 可检查已知凭据和带本机标识的绝对路径; 持有载荷的调用方按判决应用脱敏计划、请求人工处理或阻断。 - **合成蜜罐验测**:用零 Token 正负对照检查明确列出的本地信道;证据健康 不足时只报 `INCONCLUSIVE`,不猜测通过。 共享 Core 支持 Python 3.9+ 和 Git,不依附某个 harness。能否自动拦截, 仍取决于宿主有没有兼容 hook;仅安装 Skill 不会自动拦截工具调用。 Core、决策协议与 Skills 是产品本体,适配器只是可替换的接入桥。 > **能安全恢复的操作尽量自动完成;不能安全代办时再交给人。** > Agent Guard 是可靠性基础设施,不是安全沙箱:它防范失误, > 不承诺抵抗拥有相同系统权限的恶意 Agent。 ## 它会怎样处理 ```text rm -rf build/ → RELOCATE # 工作区内目录先迁入隔离区 rm -rf . → BLOCK # 保护工作区根目录 git reset --hard → SNAPSHOT # Git 状态允许时先做快照 git push --force → BLOCK # 不自动改写远端历史 ``` 这是受支持输入的**示意判决**,不是让你执行这些命令,也不表示所有宿主都会 自动拦截。被忽略且可再生的目标可能判为 `ALLOW`;Git 快照无法建立时会 保守拒绝。能恢复或安全改写时,Agent 可以继续工作;否则交给人或阻断。 ## 让编码 Agent 帮你接入 可以在 npm registry 可用后安装带作用域的包,也可以保留一个稳定的 Git checkout。不要误装无作用域的同名 `agent-guard` 包。 把固定版本安装到用户选择的稳定路径: ```sh npm install --prefix /absolute/path/to/agent-guard-install @mokuyoaxis/agent-guard@0.2.2 ``` `0.2.2` 仍是稳定版推荐。已发布的预览版 `@mokuyoaxis/agent-guard@0.2.3-rc1` 也可通过 npm `@rc` 安装,但它不含 guard-lab。当前 checkout 是 `0.2.3-rc2` 源码候选;是否已经发布,请以 Releases 与 npm 为准。预发布不会替换 npm `latest`。 安装后的包根目录是 `/absolute/path/to/agent-guard-install/node_modules/@mokuyoaxis/agent-guard`。 也可以克隆源码;如果已有 checkout,跳过克隆: ```sh git clone https://github.com/mokuyoaxis/agent-guard.git cd agent-guard ``` Core 需要 Python 3.9+ 和 Git;是否能自动拦截取决于宿主是否提供相应 hook。 把下面这段交给编码 Agent,先替换为你的仓库路径: ```text 请为当前工作区接入 agent-guard。只使用现有 Git checkout,或精确的 scoped npm 包 @mokuyoaxis/agent-guard@0.2.2;不要安装无作用域的同名 agent-guard。 安装前先让我选择并批准一个稳定的用户目录,然后把 checkout 或 npm 安装后的 包根目录作为下文的 /absolute/path/to/agent-guard。 先识别当前 harness 实际支持的 hook 与 Skill,阅读本 README 和对应 adapter 说明,并检查 Python、Git。安装适用的 Skills;只有宿主确实支持时才配置 原生 shell hook。保留现有设置;修改用户级配置或安装依赖前先展示差异并征求确认。 Claude Code 参考 adapters/claude/README.md,Kimi Code 参考 adapters/kimi-code/README.md,DSH 参考 adapters/dsh/README.md。 其他宿主先读 adapters/INTEGRATION.md,不要凭空假设原生 hook;没有已验证的 调用前阻断能力时只接入 Skill/CLI,并明确说明没有自动拦截。 用无害命令和仅作为数据传给 check.py 的 BLOCK 样例验证;不要真正执行 破坏性测试命令。Claude/Kimi 可运行本地 doctor,但不能把其 PASS 当成宿主 拦截证明。最后报告宿主版本、工具范围、实际安装内容、确实拦截的调用和未验证路径。 ``` 手动接入与证据边界见 [harness 能力矩阵](docs/harness-capabilities.md) 及对应的 adapter README。 ## 设计原则 | 原则 | 做法 | |---|---| | **守住边界** | 操作进入 Guard 时,阻断工作区根、`.git` 和外部路径的删除 | | **先保留退路** | 受支持的删除先迁入 `.agent-trash/` 并记 manifest;破坏性 Git 覆写先做快照 | | **约束授权** | 授权只在会话内有效;否决会单向降权,只有人能恢复 | | **留下记录** | 强制判决、补偿 intent、结果和恢复写入追加式 JSONL;intent 无法持久化时拒绝修改 | 贯穿四项原则的一条规则是:**越不确定,限制越严格。** ## 决策协议 每个进入 Guard 的操作都会按效果分类,再选择足以维持安全或恢复承诺的 最宽松判决。稳定的跨 harness 接口不是简单的 allow/block,而是一套 Decision Protocol: ``` 效果 → 分类器 → 策略 → Decision ∈ { ALLOW, SANITIZE, RELOCATE, SNAPSHOT, ASK, BLOCK } + ReasonCode (稳定机器码) + Explanation (面向人类的解释) + RecoveryPlan (txid 与补偿策略) ``` | 层级 | 判决 | Agent 的体验 | |---|---|---| | **SAFE** | `ALLOW` · `SANITIZE` · `RELOCATE` · `SNAPSHOT` | 尽量不中断工作;需要时先补偿,可恢复的修改凭 txid 找回。`SANITIZE` 返回由**载荷持有方**应用的脱敏计划,不改写命令 | | **AMBIGUOUS** | `ASK` | 单次执行授权(`ASK_ONCE`)——例如 Guard 无法安全代办的复合形态 | | **FORBIDDEN** | `BLOCK` | 附理由与修正建议拒绝;永不升级为询问 | 当一个操作同时命中多个判决时,由弱到强的优先级为: ``` ALLOW < SANITIZE < RELOCATE < SNAPSHOT < ASK < BLOCK ``` `SANITIZE` 排在 `ASK` **之下**是有意的:它属于自动化的 SAFE 层, 而 `ASK` 需要人处理。载荷里同时有可脱敏的密钥和无法改写的部分时, 不能只处理前者便静默放行。 真正无法确定效果的命令(如 `$VAR` 目标、`bash -c`、`find -delete`) 会被拒绝;放行它们就无法守住边界。适配器再把判决映射到宿主机制: DSH 的 `PreToolDecision`、Claude Code PreToolUse 的 `ask`,或在不支持 询问的宿主中附带解释的拒绝。 ## Agent Guard 包含什么 ### `delete-guard` 回答“删了还能找回来吗?”通过受支持的适配器或 CLI 调用时, 它在删除或破坏性 Git 操作前检查,并在可恢复时先做补偿。 ### `exfil-guard` 回答“这份内容本该离开本机吗?”载荷持有方主动调用其合作式 CLI 时, 它在发出前检查文本,并针对受支持的模式返回脱敏或升级判决。 ### `recovery-audit` 如果预防没有运行或没有覆盖那条路径,它负责事故后的证据整理: 区分原文恢复、依据重建与确认缺失,审计回放工具,并把落地、提交、 推送和发布保留为独立授权门。 `delete-guard` 和 `exfil-guard` 是两条预防分支; `recovery-audit` 负责事后的证据驱动恢复。 ## recovery-audit 有时预防根本没有机会运行:harness 没有 adapter、子代理绕开预期路径,或范围过大的 命令在人工介入前删掉了 workspace。工作树可能已经消失,但编码 Agent 的会话缓存里 仍可能保存成功 patch、文件快照、工具结果、diff 与命令上下文。 `recovery-audit` 把这些残留,与 Git remote/reflog/stash、编辑器或工具缓存、构建产物 和项目计划一起组织成证据驱动的恢复流程: - 每个单元明确标记为**原文恢复(recovered)**、**依据重建(reconstructed)**或 **确认缺失(missing)**; - 按真实时间顺序回放工具效果,并检查记录与回放是否分歧; - 同一份冻结证据重复回放,必须得到逐字节一致的树; - 落地、commit、push 与 release 始终是互相独立的授权门。 它不是文件系统 undelete,也不能创造任何幸存来源从未保存过的字节。它承诺的是: 尽快恢复到证据真正支持的最强项目状态,并把缺口写清楚,而不是藏起来。 ## exfil-guard `exfil-guard` 检查 Agent 即将写入、发送、提交或推送的文本,前提是 **载荷持有方主动调用它的 CLI**。它还提供对指定 JSON/dotenv 配置文件的 显式只读安全视图。文本扫描针对两类意外外发:**已知凭据**和 **带本机标识的绝对路径**。依据信道,Guard 可放行、返回脱敏计划、 请求人处理或阻断。 DSH 另有[默认关闭的文本 `read` 脱敏原型](adapters/dsh/README.md#experimental-text-read-redaction), 仅覆盖版本门控下的完整原生读取。它复用同一 Core,并让 DSH 同时重新生成 返回文本和展示元数据;零模型原生验证已覆盖下一次请求和 JSONL 落盘。 另一次[官方 Flash 真实直接读取对照](docs/test-report-dsh-real-followup.md) 观察到支持规则的合成秘密被脱敏,同时保留有用配置;这不是提示注入 L2 结论。 它做的是预防和脱敏,不是补偿:内容发出去后就不能撤销。它也**不是 安全沙箱**,不负责抵抗拥有相同系统权限的 Agent 蓄意外泄。 ### exfil-guard 的四种判决 完整决策协议仍然适用,但文本载荷只会落到其中四类 (`RELOCATE`/`SNAPSHOT` 属于 delete-guard——Guard 无法改写自己没写过的东西): | 判决 | 含义 | 示例 | |---|---|---| | `ALLOW` | 无匹配,或命中受控占位符、工作区内相对路径 | `echo "hello" \| check_span.py` | | `SANITIZE` | 返回脱敏计划;由**载荷持有方**改写后再发出 | `file-write` / `llm-request` 上的真实密钥 | | `ASK` | 信道既不能改写也无法收回 | `shell-stdout` 上的本机路径 | | `BLOCK` | 拒绝:不可变/远端历史、载荷无法扫描、配置非法 | `git-push-payload` 中的凭据 | ### 检测什么 **T1 厂商凭据特征**(`secret/*`,确定性,误报接近零)。rule id 包括: `secret/openai-key`、`secret/github-token`、`secret/aws-access-key-id`、 `secret/gitlab-token`、`secret/slack-token`、`secret/stripe-key` (仅 live key,`sk_test_` 豁免)、`secret/jwt`(结构化:头部必须 base64 解码为含 `alg` 的 JSON),以及 `secret/private-key-block` (整段 `-----BEGIN ... PRIVATE KEY-----` 一次性脱敏)。冻结规则表见 [skills/exfil-guard/references/rules.md](skills/exfil-guard/references/rules.md)。 **不读值的密钥引用**(`secret/source-reference`)。Guard 只对变量**名** (`*KEY*`、`*TOKEN*`、`*SECRET*`、`*PASSWORD*`、`*CRED*`、`*AUTH*`)与 密钥库**文件名**(`.env`、`*.pem`、`id_rsa*`、`.netrc`、`kubeconfig` 等) 分类,并识别整环境展开(`printenv`、`env | ...`、 `cat /proc/self/environ`)。这个扫描器**不解析变量的值**;这不代表其他 Guard 输出或已有审计记录都已证明不含秘密。 **带本机标识的路径**(`path/*`)。`path/workspace-relative` 为 `ALLOW` (工作区豁免);`path/system`(`/usr`、`/etc`、`C:\Windows`)为 `ALLOW`; `path/host-absolute`(位于 `HOME`/`TEMP`、CI 根或工作区祖先之下)为 `SANITIZE`;`path/generic-absolute`(与本机无关联)为 `ASK`; `path/device`(UNC、`\\?\`、管道)为 `SANITIZE`。 ### 信道决定处置 信道由两个事实定义:能否**改写**、发出后是否**留存**。`rewritable` 决定了 `SANITIZE` 是否有意义;`persistence` 决定了 `BLOCK` 是否成立。 | 信道 | 可改写 | 留存 | 默认 | |---|---|---|---| | `llm-request` | 是 | 远端 | SANITIZE | | `file-write` | 是 | 工作区 | SANITIZE | | `forge-comment` / `issue-body` / `pr-description` | 是 | 公开 | SANITIZE | | `git-commit-message` | 是(改 argv) | 远端历史 | **BLOCK** | | `git-push-payload` | 否 | **远端** | **BLOCK** | | `shell-stdout` | **否** | 本地记录 | ASK | | `shell-file-redirect` | 是 | 本地 | ASK | | `archive-upload` | 是 | 远端 | ASK | | `process-argv` | 是 | 本地 | ASK | 信道名未知属于配置缺陷,而非"无风险":`check_span.py` 返回 `BLOCK_OUTPUT_UNSCANNABLE`,绝不隐式放行。 ### 使用示例 `check_span.py` 从 **stdin** 读取载荷,是纯函数——不写文件、不改写、 也不打印匹配内容。`sanitize.py` 应用 Guard 返回的计划。 ```bash # 可改写信道上的凭据 -> SANITIZE,退出码 0 echo 'config: sk-proj-AbCdEf…' | python3 skills/exfil-guard/scripts/check_span.py --channel file-write # 即将进入远端历史的凭据 -> BLOCK,退出码 2 echo 'token=ghp_abcdefghijklmnopqrstuvwxyz…' | python3 skills/exfil-guard/scripts/check_span.py --channel git-push-payload # 应用脱敏计划(保留格式:sk-) echo 'config: sk-proj-AbCdEf…' | python3 skills/exfil-guard/scripts/sanitize.py --channel file-write ``` 退出码契约:`0` = ALLOW/SANITIZED · `2` = BLOCK · `3` = ASK · `1` = ERROR。 `--json` 输出机器可读判决(仅偏移、rule id 与占位符——**绝不含匹配到的 字节**);`--path` 为即将写入的文件启用仓库本地豁免文件。 ### 不打印值地查看配置 此 CLI 从 `0.2.0` 源码开始提供,**不属于**此前的 `0.2.0-rc2` 源码预览标签。 ```bash python3 skills/exfil-guard/scripts/view.py --workspace /path/to/workspace .env python3 skills/exfil-guard/scripts/view.py --workspace /path/to/workspace config.json ``` 文件路径必须相对该工作区。JSON 结果保留字段名与结构,以及标量类型和 `set`/`empty` 状态,**不返回标量值**;已知密钥形态的字段名也会隐藏, 但未知秘密藏在字段名中仍是局限。仅支持 UTF-8 JSON 与严格的单行 dotenv 子集(最多 256 KiB、16 层、2048 个节点)。符号链接、硬链接、特殊文件、 越界路径、无效格式或平台缺少安全的相对目录描述符读取能力时一律拒绝。 退出码 `0` 表示产生视图,`2` 表示拒绝,`1` 表示内部错误。视图仅供诊断, 不能写回覆盖原配置;它也不会拦截 harness 的普通文件读取工具。 ### 与 delete-guard 的关系 它们是同一承诺在动作两侧的两半: | | `delete-guard` | `exfil-guard` | |---|---|---| | 问题 | "还能回头吗?" | "这份内容本该离开吗?" | | 把守 | **删除之前** | **发出之前** | | 响应 | 先补偿,再执行 | 先脱敏,再发出 | | 失误代价 | 可凭 txid 恢复 | **不可逆** | | 入口 | `check.py -- ` | `check_span.py`(stdin) | 二者共享词汇表(`core/policy.py`)、聚合逻辑(`worst()`)、豁免纪律与审计 日志。`worst()` 由两个 Guard 共用,这正是 `SANITIZE` 的排序只需定义一次的原因。 ### 覆盖范围与局限 这里如实说明,因为一个夸大自身能力的可靠性工具就是一份虚假的安全声明: - **不是沙箱。** 它不阻止对抗性外泄。把密钥混淆以绕过扫描的 Agent 不在 范围内;它抓的是**意外**。 - **没有 hook 的信道在结构上不可达。** 无代理的托管模型调用、模型自身的 工具调用、程序内部产生的内容、人类剪贴板,一律**不给判决**——不作任何 覆盖声明。详见 `references/channels.md` 与 [docs/secret-guard-analysis.md](docs/secret-guard-analysis.md) §2.4 的 可达性表。 - **不是文件扫描器。** 它不是 gitleaks 的替代品;它扫描 Guard 在**发出 路径上**能看到的内容。 - **不改写历史。** 检测到已经进入 git 历史的密钥最多只是一份报告。 改写历史是需要人类执行、且自带风险的动作。 - **本版本不含 T3 熵检测器。** 它是最大的单一误报来源,而目标场景并不需要它。 ## 手动使用(不依赖特定 harness) Core 没有第三方依赖。需要 Python 3.9+、POSIX shell 和 Git。 ```bash # 删除文件/目录/glob —— 进入隔离区而非销毁: python3 skills/delete-guard/scripts/safe_delete.py build/ --reason "stale" # 查看状态与恢复: python3 skills/delete-guard/scripts/status.py python3 skills/delete-guard/scripts/restore.py list python3 skills/delete-guard/scripts/restore.py # 隔离区维护(默认只出计划,不动数据): python3 skills/delete-guard/scripts/gc.py ``` 受支持的 harness 适配器可在 shell 命令执行前调用 Guard,再将退出码映射 为宿主自己的工具判决: ```text python3 skills/delete-guard/scripts/check.py --enforce -- "$COMMAND" 退出码 0 → 宿主可以执行原命令 退出码 2 → 拒绝 退出码 3 → 宿主支持时询问用户;否则拒绝 退出码 1 → Guard 出错,保守拒绝 ``` ## 受保护行为一览 下列是命令确实进入 Guard、且目标符合所述条件时的示意结果;各宿主实际 验证到的范围见 [能力矩阵](docs/harness-capabilities.md)。 ```text rm -rf build/ → RELOCATE (整树隔离后放行) rm -rf . → BLOCK (workspace 根) rm -rf $DIR/ → BLOCK (目标无法解析:fail-closed) rm *.log → BLOCK (不透明通配;safe_delete 会显式展开) cd X && rm -rf build → ASK_ONCE (COMPOUND_CWD_DELETE) touch f && rm f → ASK_ONCE (COMPOUND_CREATE_DELETE) git clean -fd → RELOCATE (先 -n 枚举迁移再放行) git reset --hard → SNAPSHOT (Git 状态允许建立快照时) git push --force → BLOCK (远端历史不交给 Agent 自动处理) node_modules/(已 ignore) → ALLOW (可证明可再生) 隔离区写满 → BLOCK (绝不回退到永久删除) ``` ## 接入与验证矩阵 [![Node.js 20 smoke](https://img.shields.io/badge/Node.js-20%20smoke-339933?logo=nodedotjs&logoColor=white)](.github/workflows/ci.yml) [![Codex Skill/CLI tested](https://img.shields.io/badge/Codex-Skill%2FCLI%20tested-000000?logo=openai&logoColor=white)](docs/test-report-codex-gpt-6-astra-high.md) [![DSH 0.1.5-rc.1 宿主 BLOCK 实测](https://img.shields.io/badge/DSH%200.1.5--rc.1-%E5%AE%BF%E4%B8%BB%20BLOCK%20%E5%AE%9E%E6%B5%8B-4D6BFE)](docs/test-report-dsh-0.1.5-rc.1.md) [![ZCode win32 CLI evaluated](https://img.shields.io/badge/ZCode-win32%20CLI%20evaluated-7C5CE0)](docs/test-report-zcode-glm-flash.md) [![Claude Code hook tested with scripted model](https://img.shields.io/badge/Claude%20Code-hook%20tested%20%28scripted%20model%29-D97757?logo=anthropic&logoColor=white)](docs/test-report-claude-code-harness.md) [![Kimi Code 2.1.1 K3 Bash BLOCK](https://img.shields.io/badge/Kimi%20Code%202.1.1-K3%20Bash%20BLOCK-5B9BD5)](docs/test-report-kimi-code-block.md) “Core 可用”、“受 Skill 引导的 Agent 使用过”和“harness 会强制拦截每次匹配的 工具调用”是三种不同强度的结论: | Harness/实测版本 | 接入路径 | 证据与边界 | |---|---|---| | **Claude Code 2.1.270 / 2.1.273** | [Bash 原生 `PreToolUse`](adapters/claude/README.md) | [真实 CLI+脚本模型](docs/test-report-claude-code-harness.md):抽样 allow/ask/deny 与 Python 启动故障;其他工具未验证。 | | **DSH 0.1.5-rc.1** | [原生 pre-execute adapter](adapters/dsh/README.md) | [真实宿主打包插件探针](docs/test-report-dsh-0.1.5-rc.1.md):执行级 `BLOCK` 与已加载 adapter 的 Core 故障拒绝。另一次[真实模型 Lab 基线](docs/test-report-dsh-guard-lab.md)在 guard-off 下未触发诱饵,故没有 L2 缓解结论;模型主动提出破坏性 `bash` 时的强制执行仍未验证。单独开启的读取脱敏路径见下一行。 | | **DSH CLI rc.1/工具与 FS rc.2/Node 22** | [实验性文本读取脱敏](adapters/dsh/README.md#experimental-text-read-redaction),默认关闭 | [零模型原生验证](docs/test-report-dsh-read-redaction.md):下一次请求和 JSONL 落盘。[官方 Flash 真实读取 off/on](docs/test-report-dsh-real-followup.md):支持规则的合成秘密在工具内容/元数据/会话中被脱敏,有用配置保留;无提示注入 L2 结论。 | | **DSH 0.2.0-rc.2/Node 22** | [默认删除与可选文本读取 adapter](adapters/dsh/README.md) | [最新契约复核](docs/test-report-release-readiness-0.2.3.md):原生删除阻断、已审阅本地/沙箱 FS 的读取脱敏、下一次合成请求与 JSONL 落盘。原生 v4 Lab 支持仍有范围限制;没有新的真实模型 L2 结果。 | | **Codex CLI 0.154.0(所测会话)** | [Skill + 生产 CLI](docs/test-report-codex-gpt-6-astra-high.md) | 较早源码的合作式验收;不声称原生 hook。 | | **ZCode(版本未记录;win32)** | [历史 Skill/CLI+hook 试次](docs/test-report-zcode-glm-flash.md) | 旧报告记录了持久许可绕过 hook;当前版本未验证。 | | **Kimi Code 0.42.0 / 2.1.1** | [Bash 原生 `PreToolUse`](adapters/kimi-code/README.md) | [有界实测](docs/test-report-kimi-code-block.md):2.1.1 在 OAuth 官模和维护者确认的官方 K3 可信中转上均取得根 Bash PASS;0.42.0 另有主/子代理 BLOCK、ASK 硬拒绝和 Python 故障拒绝。hook 缺席/超时仍可能放行。 | | **其他/未列出宿主** | [自适配指南](adapters/INTEGRATION.md) | 未独立验证调用前阻断与目标未执行前,不作原生支持声明。 | 由 Agent 协助接入时,先识别真实宿主版本与工具名称,阅读上表对应指南, 保留已有配置,并分别报告配置、本地探针、真实宿主三层证据。未列出的宿主 依照[自适配清单](adapters/INTEGRATION.md)操作;提示词或 adapter 退出码 本身不是拦截证明。修改用户级设置、安全策略或依赖前先征求确认。 `tests/test_conformance.py` 覆盖共享 Core 和 Claude adapter;DSH 有 smoke 测试, Kimi 有针对性 adapter 测试。上述 Kimi 观察只覆盖实测调用,不构成所有 Shell 语法或一般并发子代理安全保证。 Kimi 或 Claude 安装可分别运行 `python3 doctor.py kimi --probe`、 `python3 doctor.py claude --probe`,无需模型调用即可检查所选配置文件与 本地 shell 桥。加 `--json` 可获取 `configuration`、`local_probe`、 `host_interception` 机器可读状态;最后一项始终为 `UNVERIFIED`, 因为本工具不能证明实际会话加载或强制执行了 hook。参见 [Kimi](adapters/kimi-code/README.md) 与 [Claude](adapters/claude/README.md) 适配指南。加 `--check-drift` 会在本机查询宿主版本,并对所选 hook 结构与 Agent Guard 运行路径生成去敏指纹;结果使用 `CURRENT`、`STALE`、 `DRIFTED`、`BROKEN` 或 `UNVERIFIED`。即使是 `CURRENT` 也只代表静态预检, 不是实时拦截证明。可选基线只保存解析后的版本和 SHA-256 指纹,详见 [宿主漂移检查说明](docs/host-drift.md)。显式 `--live-sentinel` 可在私有空白 夹具中消耗一次已配置模型调用,按 `PASS`、`FAIL`、`INCONCLUSIVE` 返回 `NONE`/`NOTICE`、`CRITICAL` 或 `WARNING` 报警;仅仅“标记不存在”绝不算 通过。它保留哈希化/去敏结果而不保留模型原始输出。这是可信提供方下的 可靠性探针,不是针对恶意模型的沙盒。Kimi 的可选 doctor 因 TOML 解析需要 Python 3.11+;Core 与 hook adapter 仍支持 Python 3.9+。 各宿主的覆盖范围、证据等级和执行级验收条件见 [harness 能力矩阵](docs/harness-capabilities.md)。 ## 目录结构 ``` agent-guard/ ├── skills/delete-guard/ # Agent 行为层:SKILL.md + CLI 脚本 ├── skills/exfil-guard/ # 出口侧技能:check_span.py · sanitize.py ├── skills/recovery-audit/ # 证据驱动的仓库审计与恢复 ├── core/ # classifier · policy · recovery · audit · redaction ├── doctor.py # 本地配置、探针与宿主漂移预检 ├── live_sentinel.py # 可选实宿主哨兵与报警证据 ├── guard_lab.py # 用户控制的离线合成蜜罐实验 ├── adapters/INTEGRATION.md # 未列出宿主的自适配检查清单 ├── adapters/claude/ # Claude Code PreToolUse hook 适配器 ├── adapters/kimi-code/ # Kimi Code PreToolUse hook 适配器 ├── adapters/dsh/ # DeepSeek Harness 接入桥 ├── adapters/codex/harness/# CLI 验收 driver;不是原生 hook ├── tests/ # unittest 测试套件,含跨 harness 一致性 └── docs/ # architecture · threat-model · friction log ``` Skill 负责 Agent 行为引导,约束全部下沉 Core。未来的 `git-guard`、 `database-guard`、`cloud-guard` 直接挂同一补偿引擎,无需重构仓库。 ## 文档 | 阅读 | 内容 | |---|---| | [CONTRIBUTING.md](CONTRIBUTING.md) | 如何提出 Issue 与提交范围清晰的 Pull Request | | [docs/architecture.md](docs/architecture.md) | 四柱↔组件映射、数据流、关键设计决定 | | [docs/host-drift.md](docs/host-drift.md) | 零 Token 宿主/版本漂移状态与最小化基线 | | [docs/guard-lab.md](docs/guard-lab.md) | 合成 Lab 流程、证据语义与不支持的信道 | | [docs/release-notes-0.2.3-rc2.md](docs/release-notes-0.2.3-rc2.md) | 离线 guard-lab 源码候选 | | [docs/release-notes-0.2.3-rc1.md](docs/release-notes-0.2.3-rc1.md) | Windows Core fail-closed 候选版与预发布通道 | | [docs/release-notes-0.2.2.md](docs/release-notes-0.2.2.md) | 0.2.2 宿主漂移、实时哨兵与 DSH 打包验收 | | [docs/release-notes-0.2.1.md](docs/release-notes-0.2.1.md) | 0.2.1 adapter/doctor 变更与证据边界 | | [docs/release-notes-0.2.0.md](docs/release-notes-0.2.0.md) | 0.2.0 变更、证据等级与已知限制 | | [adapters/INTEGRATION.md](adapters/INTEGRATION.md) | 未列出宿主的自适配检查清单 | | [docs/threat-model.md](docs/threat-model.md) | 诚实边界:它是什么、不是什么 | | [docs/friction.md](docs/friction.md) | 真实 Agent 与宿主进程撞出来的教训(F1–F20) | | [docs/development-note-unguarded-deletion.md](docs/development-note-unguarded-deletion.md) | 去标识化事故探索与面向恢复的后续方向 | | [docs/test-report-codex-gpt-5.6-sol.md](docs/test-report-codex-gpt-5.6-sol.md) | v0.1.1 Codex 评估(medium + high) | | [docs/test-report-dsh-0.1.5-rc.1.md](docs/test-report-dsh-0.1.5-rc.1.md) | 当前 DSH 打包插件与执行级 `bash` 验收 | | [docs/test-report-dsh-guard-lab.md](docs/test-report-dsh-guard-lab.md) | DSH 真实模型有界 Lab 基线;无 L2 结论 | | [docs/test-report-dsh-v0.1.1.md](docs/test-report-dsh-v0.1.1.md) | v0.1.1 DSH 真机测试(DeepSeek V4 Pro high,极简模式) | | [skills/recovery-audit/SKILL.md](skills/recovery-audit/SKILL.md) | 证据优先级、确定性回放、恢复与落地门禁 | | [skills/delete-guard/references/policy.md](skills/delete-guard/references/policy.md) | 完整规则表与判决码 | | [skills/exfil-guard/references/rules.md](skills/exfil-guard/references/rules.md) | exfil 规则表、reason code、豁免格式与审计结构 | | [skills/exfil-guard/references/channels.md](skills/exfil-guard/references/channels.md) | 出口信道分类与不可达信道 | ## 状态与路线图 当前源码版本为 **v0.2.3-rc2**,最新稳定版仍为 **v0.2.2**。已发布的 `v0.2.0` 基线包含可恢复的破坏性 操作、cmd/PowerShell 方言解析、`exfil-guard` 文本 CLI、只读配置安全视图 和 `recovery-audit`。后续源码版新增 Claude/Kimi POSIX hook 桥、有界宿主 证据、`doctor`、宿主漂移检查、可选实时哨兵与当前 DSH 打包验收;rc2 源码另含 下述离线 guard-lab MVP。准确范围见 [0.2.3-rc2 说明](docs/release-notes-0.2.3-rc2.md)记录源码候选范围, [0.2.3-rc1 说明](docs/release-notes-0.2.3-rc1.md)记录已发布候选范围, [0.2.2 说明](docs/release-notes-0.2.2.md)记录稳定版范围;是否已正式发布以 [GitHub Releases](https://github.com/mokuyoaxis/agent-guard/releases) 为准, 源码版本号本身不代表已有 Release。 该版本的项目身份与 harness 无关。现有 DSH、Claude adapter,Codex/ZCode 验收证据,以及有边界的 Kimi 实测,只是不断扩展的兼容矩阵,不分别定义产品。 Kimi 结果包含所测调用的 hook 补偿与执行级 BLOCK 证据,不证明宿主强制执行 所有 `BLOCK`,也不意味着任意 Agent 操作都受保护。实测旧的直连 Python hook 启动故障会放行;可选 shell 桥在一次 Kimi 宿主故障注入中将其转为拒绝, 但前提是桥自身成功运行;单凭配置校验无法证明 hook 在线。候选版为 Issue #7 新增了聚焦的真实 Windows Core 门,但各 harness 下的原生 cmd/PowerShell 执行与一般并发子代理安全仍是明确缺口。 后续 `git-guard`、`database-guard`、`cloud-guard` 继续复用同一协议与补偿引擎。 ## 0.2.3-rc2 源码候选:guard-lab 合成蜜罐 当前源码加入了可选的离线蜜罐 MVP:在一次性项目中放入不具备认证能力的合成 标记。`clean`、`mock-positive`、`mock-injection` 与 `snapshot-positive` 四组 对照不调用模型,也不访问外网;限时回环观察器记录假 Lab 工具、诱饵 URL 或 经验证的合成快照,用户还可在试次结束后显式扫描选定输出,只保留哈希、阶段与 命中的 bait id,不保存原值。 真控制器与证据由用户保管,和交给受测 Agent 的夹具分开。观察器、控制文件或 事件链有问题时只报 `INCONCLUSIVE`。首版不能看到普通文件读取,不能证明数据 已经外发,不能普遍封禁 LLM 调用,也不能抵抗同一系统用户权限下的对手。 涉及真实 harness 前,请先跑零 Token 对照并阅读 [guard-lab 指南](docs/guard-lab.md)。 这些内建 case 只报 `CALIBRATION_ONLY`。另设的手动 `injection-probe` 会把诱饵 命中记为 `EXPOSURE_OBSERVED`;只有未防护基线确实中招,并与相同协议、 harness/版本/模型、实验组和任务哈希的开启防护试次配对,`compare` 才可能给出 缓解成立。手动真实模型试次还必须由用户确认宿主确实完成,避免把“进程退出 0、 但模型/配置已失败”误算成安静成功。基线没触发时只能报 `INCONCLUSIVE`,任何 结果都不是对模型或厂商的通用安全认证。 ## 参与贡献 欢迎缺陷报告、设计提案、兼容性证据、文档修订与范围明确的代码改动。非小型或 涉及安全边界的变更请先发 [Issue](https://github.com/mokuyoaxis/agent-guard/issues),实现请通过范围清晰的 [Pull Request](https://github.com/mokuyoaxis/agent-guard/pulls) 提交。分享日志或 测试证据前请先阅读[贡献指南](CONTRIBUTING.md);不得公开凭据、私有配置或未经 去敏的事故资料。 ## 社区友链 [![LINUX DO 社区友链](assets/linux-do-community.svg)](https://linux.do/t/topic/2942799) 这张自制横幅直达我们的 [LINUX DO 项目帖](https://linux.do/t/topic/2942799),不代表社区官方推荐。 ## 许可证 MIT —— 见 [LICENSE](LICENSE)。