aldegad/safedeps

GitHub: aldegad/safedeps

safedeps 是一个面向 Claude Code 和 Codex CLI 的依赖安全网关,通过安装前漏洞咨询预审和安装后实际 lockfile 效果强制执行,阻断 AI agent 引入有风险的第三方依赖。

Stars: 17 | Forks: 3

# safedeps - **预先批准** — 每一个 `pkg@version` 及其在 npm 中的完整传递闭包,在安装*之前*都会通过 OSV(权威源)、CISA KEV 和 GitHub Advisory 进行 clearance。 - **强制执行实际效果** — 安装完成后,会重新检查实际的 `package-lock.json` 闭包,因此被包装或混淆的命令无法将软件包偷偷越过关卡。 - **回滚** — 任何未经批准或新发现存在漏洞的内容都会恢复到上一个确认安全的状态快照。在 Claude Code 上,安装会以惰性模式运行(`--ignore-scripts`),因此被拒绝的软件包的生命周期脚本永远不会执行。 ## 快速开始 ``` # 1. 安装 CLI — 该 npm 包是 scoped 的,请注意 @aldegad/ 前缀 npm install -g @aldegad/safedeps # 2. 将 hooks 接入 Claude Code / Codex(幂等) cd "$(npm root -g)/@aldegad/safedeps" && node scripts/install/install-safedeps-hooks.mjs # 3. 完成 — 你的 agent 运行的每个依赖安装现在都已被 gated。 ``` ![safedeps 拦截存在漏洞的安装,随后放行已修复的版本](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/d8d897e390122959.gif) ## 分发模型 Safedeps 有两个分发面: 1. **Agent 技能 + hooks(权威来源)** -- 代码仓库本身就是技能文件夹。`SKILL.md`、hook 脚本、provider/ledger 库和安装辅助工具都保留在同一个目录中。 2. **npm 包(CLI 便捷工具)** -- `@aldegad/safedeps` 安装了 `safedeps` 命令。npm **不会**让 Claude Code 或 Codex 自动发现该技能;在通过 npm 安装后,用户仍需要运行 hook/技能安装程序或手动注册技能文件夹。 当你希望将完整的技能/hook 源码树作为权威制品时,请使用 GitHub release。当你主要想要一个带有版本号的全局 CLI 时,请使用 npm。 术语说明:safedeps 是一个由 Claude/Codex hooks 和本地 CLI 支持的 agent 安全技能。除非后续通过 plugin manifest 进行包装,否则它不是 Codex plugin bundle。 ## 两条通道 `safedeps` 拥有两条安全通道(完整设计见 [`ARCHITECTURE.md`](./ARCHITECTURE.md) §1): - **安装时**(本 README 的重点)— 漏洞咨询检查 + 批准规范账本 + 快速 PreToolUse 防护 + PostToolUse 效果强制执行 + 安装后重组。针对单个软件包,围绕安装命令及其实际 lockfile 效果进行。 - **发布时** — `safedeps gates run`、`safedeps scan secrets [--repo|--worktree|--staged]`、`safedeps audit npm`、`safedeps hooks install|check`。代码树级别的机密扫描、依赖审计、在 push/release 之前安装/检查仓库本地的 git hook,以及可选的远程仓库安全态势检查。特定于仓库的策略(gitleaks 配置、隐私路径)保留在目标仓库中;safedeps 负责本地执行。*(吸收了之前的 `security-release-gates`。)* 发布时通道中防范机密泄露的部分是**按仓库划分且为可选的**。`safedeps doctor` 是其仓库准入检查:它诊断仓库的 `.gitleaks` 策略、`.githooks/pre-commit`、处于激活状态的 `core.hooksPath` 以及扫描器可用性(并报告全局安装时关卡),随后 `safedeps doctor --fix` 会搭建一个初始策略(`safedeps hooks init`)并将其激活(`safedeps hooks install`)。一旦你选择了 `--fix`,该本地 pre-commit 设置就会自动完成;它不会消耗远程 CI 的运行分钟数。搭建过程是非破坏性的 —— 绝不会覆盖仓库现有的 `.gitleaks.toml` —— 并且 pre-commit hook 会运行机密扫描(`safedeps scan secrets --staged`),此外在 npm 仓库的每次提交时还会运行依赖审计(`safedeps audit npm`):发现真实结果会阻止提交(fail-closed,即失败即封闭),而如果漏洞数据库无法访问,则只会发出警告并放行提交(可观察的离线故障转移)。强制执行在远程被拆分:建议使用禁止直接 push 到 `main` 分支的分支规则作为无需 runner 的基础态势,而 GitHub Actions 工作流和必需的状态检查仍然是明确的、带有成本的 opt-in 选项,因为托管 runner 会产生费用。详情请参阅[机密泄露通道(按仓库划分)](#secret-leak-lane-per-repo)。 ## 工作原理 `safedeps` 在每次安装时分为两个步骤进行工作: - **之前** — `safedeps check` 根据 OSV(权威源)、CISA KEV 和 GitHub Advisory 对软件包进行 clearance,然后将批准记录在本地账本中。对于 npm,它会解析该软件包完整的依赖闭包,并检查每一个传递依赖。 - **之后** — PostToolUse hook 会重新读取实际写入 `package-lock.json` 的内容,并重组(回滚)任何不在账本中或现在被漏洞数据库标记的内容。 安装前命令 hook(PreToolUse)是一个快速的咨询性提醒 —— 它会阻止明显的未批准安装和危险的命令形式,以便 agent 能立即得到反馈。但对于 npm 来说,真正的权威在于安装后的效果关卡:它评判的是*实际安装*了什么,而不是命令看起来是什么样子,因此被包装或混淆的安装命令无法让软件包蒙混过关。 **脚本安全性(惰性安装)。** 在 Claude Code 上,PreToolUse hook 会重写 npm install 命令以添加 `--ignore-scripts`,因此安装以**惰性**模式运行 —— 软件包被写入磁盘,但不会运行任何生命周期脚本。效果关卡随后验证其闭包;只有验证通过后,PostToolUse hook 才会运行 `npm rebuild` 来执行现已验证的脚本。被关卡拒绝的软件包会在其任何脚本运行之前被重组回滚。(这使用了 Claude Code hook 的 `updatedInput` 功能。Codex CLI 没有公开此功能,因此在 Codex 上安装正常运行,效果关卡采取的是检测并回滚策略 —— 恶意的安装脚本可能会在回滚前运行一次。) 这种以效果为主导的模型目前仅适用于 npm。`pip`、`cargo`、`go`、`gem`、`maven` 和 `nuget` 在其闭包解析器推出之前,仍将采用 v2.1 的命令关卡 + 重组模型。 ``` PreToolUse PostToolUse (safedeps-pre-guard.sh) (safedeps-post-verify.sh) | | install cmd ──> [ Advisory/ledger UX ] ──> [ Execute ] ──> [ npm effect gate ] | | | | Block obvious Snapshot Clean? Suspicious? misses/risk lock/manifest files, | | package listings Confirm REORG | | | v v +--- parent_snapshot_id ──> confirmed | Rollback to last confirmed snapshot ``` ### 第一阶段:漏洞咨询检查(`safedeps check`) 在 agent 安装依赖项之前,它应该运行: ``` safedeps check @ --json ``` 该命令会查询 OSV(权威源)、CISA KEV(高风险叠加)和 GitHub Advisory(数据补充)。对于 npm,它首先使用 `npm install --package-lock-only --ignore-scripts` 创建一个无脚本的临时 lockfile,提取完整的依赖闭包,并查询 OSV `/v1/querybatch`。干净的或被安全收窄的规范会被写入 `~/.safedeps/approved-specs/`;npm 条目还会记录 `transitive_specs`。 ### 第二阶段:快速命令防护 + 快照(PreToolUse) 当 Claude Code 或 Codex CLI 即将运行 `npm install`、`pip install`、`cargo add`、`go get`、`gem install` 或类似命令时,防护 hook 会提供一个快速的咨询性/UX 层: 1. **快照**当前的 `package-lock.json`、`pnpm-lock.yaml`、`yarn.lock` 和 `package.json` 到 `~/.safedeps/snapshots/`。 2. **记录元数据**,包含一个 `parent_snapshot_id` 链接到上一个已确认的快照(形成一个链条,就像区块一样)。 3. **捕获** `node_modules` 的安装前状态(软件包列表和二进制文件列表),用于稍后基于 diff 的检测。 4. 对显式的 `pkg@version` 安装命令**快速检查** approved-spec 账本。 5. **运行预检查**,如果检测到以下情况则完全**阻止**命令执行: - 仿冒(Typosquatting)的包名(`lod_sh`、`reacct`、`axois` 等) - 非标准的 `--registry` URL(`registry.npmjs.org` 和 `registry.yarnpkg.com` 之外的任何来源) - 管道远程执行模式(`curl ... | bash`) - 显式禁用安装脚本安全机制(`npm config set ignore-scripts false`) 如果账本关卡或预检查失败,该命令会在**执行前被阻止** —— 什么都不会被安装。此命令防护是故意的“尽力而为”;它改善了 agent 循环并捕获直接的失误,而 npm 的权威性则体现在安装后的效果关卡中。 ### 第三阶段:安装后效果强制执行(`safedeps-post-verify.sh` -- PostToolUse) 在安装命令完成后,验证 hook 会分析发生了什么变化。对于 npm,这是主要的强制执行面:它读取实际的 `package-lock.json` 闭包,根据批准的直接条目及其 `transitive_specs` 验证每个软件包,并使用 OSV 批量重新检查闭包。 1. **npm 效果关卡** -- 如果任何 lockfile 中的包未获批准、被 KEV 阻止、存在漏洞或无法以 fail-closed 方式验证,则执行重组。 2. **安装脚本分析** -- 扫描新添加的软件包中是否包含具有以下内容的 `preinstall`、`install` 和 `postinstall` 脚本: - 网络访问(`curl`、`wget`、`fetch`、`http`、`socket`、`dns`) - 动态代码执行(`eval`、`exec`、`spawn`、`child_process`、`Function()`) - 敏感路径访问(`~/.ssh`、`.env`、`.aws`、`credentials`) - 混淆内容(`base64`、`atob`、`Buffer.from`、hex/unicode 编码) 3. **Lock file diff 分析** -- 将快照的 lock file 内容与安装后的版本进行比较: - 指向非标准 registry 的已解析 URL - 已解析 URL 中的不安全协议(`http://`、`git://`) - 异常庞大的依赖项添加(>50 个新解析条目,表明存在潜在的依赖项混淆) 4. **二进制文件检查** -- 检查 `node_modules/.bin/` 是否有新添加的原生二进制文件(ELF、Mach-O、共享对象),这些文件不应出现在 JavaScript 项目中。 ### 确认或重组 - **所有检查通过** -- 该快照在 `~/.safedeps/confirmed` 中被标记为**已确认**。这将成为新的安全基线。 - **任何检查失败** -- 触发**重组**: 1. Lock file 将从上一个已确认的快照中恢复。 2. 如果 `package.json` 被修改过,也会将其恢复。 3. 通过 `npm ci`(或回退到 `npm install`)重建 `node_modules`,以清除任何恶意制品。 4. 该事件被记录到 `~/.safedeps/reorg.log`。 5. Claude Code 会收到一条系统消息,详细说明检测到的威胁和回滚操作。 ## 为什么叫“reorg”? 这个名字借用了区块链,在区块链中,**重组**会使一系列未确认的区块无效,并将链恢复到上一个确认的安全状态。`safedeps` 以同样的方式对待每一次安装:在通过一系列供应链检查之前,它都是一个未确认的区块候选者。如果安装的效果发生偏离,该工具将执行一次**重组** -- 将 lock file、`package.json` 和 `node_modules` 回滚到上一个确认的安全快照。 但重组是**兜底防线,而不是第一道防线。** 大多数糟糕的安装永远达不到这一步:预批准关卡会在其运行*之前拒绝*未批准或被标记的软件包,并且在 Claude Code 上,安装以**惰性**(`--ignore-scripts`)模式运行,因此在闭包验证干净之前,生命周期脚本不会执行。重组针对的是残余情况 —— 一个已批准的直接包引入了未批准或存在漏洞的传递依赖,或者一个包装过的命令绕过了咨询层 —— 即便如此,它回滚的也是那些从未有机会运行的文件。 快速的咨询性反馈、可观察的回滚,且没有隐藏的回退机制。命令防护是“尽力而为”的 UX;安装后的效果才是兜底防线。 ## 区块链类比 | 区块链概念 | Safedeps 对应概念 | |---|---| | **区块候选者** | 在 `npm install` 之前获取的快照 | | **区块验证** | 安装后效果检查(npm 闭包、脚本、lock diff、二进制文件) | | **最终性 / 确认** | 写入 `~/.safedeps/confirmed` 的快照 ID | | **链重组** | 回滚到最后一个确认的快照 + 重建 `node_modules` | | **父哈希链接** | 每个快照 `_meta.json` 中的 `parent_snapshot_id` | | **链修剪** | 清理旧的未确认快照,保留已确认的链## 检测规则 | 类别 | 捕获内容 | 阶段 | 动作 | |---|---|---|---| | 仿冒 | 流行软件包已知的拼写错误模式 | PreToolUse 咨询防护 | **阻止** | | 管道执行 | `curl \| bash`, `wget \| sh` | PreToolUse 咨询防护 | **阻止** | | Registry 劫持 | 指向非官方来源的 `--registry` | PreToolUse 咨询防护 | **阻止** | | 脚本安全绕过 | `npm config set ignore-scripts false` | PreToolUse 咨询防护 | **阻止** | | 命令间接执行 | `eval "npm install ..."`、子 shell 展开、变量间接引用 | PreToolUse 咨询防护 | **防护** | | npx/dlx 执行 | `npx`、`pnpm dlx`、`yarn dlx` 包执行 | PreToolUse 咨询防护 | **防护** | | 未批准的传递依赖 | npm `package-lock.json` 中缺失于直接账本或 `transitive_specs` 的包 | PostToolUse npm 主要效果关卡 | **重组** | | 存在漏洞的闭包包 | 匹配到 OSV/KEV 的 npm 直接/传递包 | PostToolUse npm 主要效果关卡 | **重组** | | 恶意安装脚本 | hook 中的网络调用、`eval`/`exec`、敏感路径访问 | PostToolUse 效果验证 | **重组** | | 混淆代码 | 安装脚本中的 Base64、hex 编码、`Buffer.from` | PostToolUse 效果验证 | **重组** | | Lock file 篡改 | 来自非标准 registry 的解析 URL | PostToolUse 效果验证 | **重组** | | 不安全协议 | `http://` 或 `git://` 的解析 URL | PostToolUse 效果验证 | **重组** | | 依赖项混淆 | 单次安装中新增 >50 个新依赖项 | PostToolUse 效果验证 | **重组** | | 原生二进制文件 | `node_modules/.bin/` 中的编译后可执行文件 | PostToolUse 效果验证 | **重组** | ## 机密泄露通道(按仓库划分) 安装时的关卡是全局的,但阻止机密或真实的 `.env` 被提交是**按仓库划分的**,并且保持 opt-in —— 它的检测策略存在于每个仓库中,而不是 safedeps 中。`safedeps doctor` 是填补这一空白的入口点。 ``` # 诊断此 repo 的安全态势(只读)。如果 secret lane 存在缺口,则以非零状态退出。 $ safedeps doctor safedeps doctor — repo security posture repo: /path/to/repo profile: public Secret-leak lane (per-repo) ✓ git worktree ✗ gitleaks config (.gitleaks.toml) → safedeps hooks init --root "/path/to/repo" ✗ .githooks/pre-commit (present) → safedeps hooks init --root "/path/to/repo" ✗ git hooks active (core.hooksPath=) → safedeps hooks install --root "/path/to/repo" ✓ secret scanner available (gitleaks) Dependency-install gate (global, all repos) ✓ dependency-install gate installed (~/.claude/skills/safedeps) Remote repository governance (opt-in; no-runner vs CI-cost) ! remote PR security workflow (opt-in; may spend CI minutes) → safedeps gates run --root "/path/to/repo" --strict – main direct-push protection for main (no runner minutes; opt-in) → no-runner opt-in: require pull requests before updating main; do not require status checks unless CI cost is accepted – required PR status checks for main (CI-cost opt-in) → cost-bearing opt-in: add a safedeps workflow, then require it before merging main 3 gap(s) in the secret-leak lane. Fix all at once: safedeps doctor --fix --root "/path/to/repo" # Scaffold 入门 policy 并激活 hooks(非破坏性)。 $ safedeps doctor --fix ``` 该通道的组成部分: - **`safedeps hooks init`** 搭建一个初始的 `.gitleaks.toml`(如果是私有仓库则为 `.gitleaks.private.toml`)和一个 `.githooks/pre-commit`。现有文件将被保留,绝不会被覆盖 —— 仓库拥有该策略。 - **`safedeps hooks install`** 激活仓库本地的 hooks(`core.hooksPath = .githooks`)。 - **pre-commit hook 运行两项检查**: - 在每次提交时进行**机密扫描**(`safedeps scan secrets --staged`),**fail-closed**。如果扫描器(本地 `gitleaks` 或 Docker)无法运行,它会阻止提交,而不是悄悄跳过。 - 在有 npm lockfile 的仓库中,**每次提交**时进行 **npm 依赖审计**(`safedeps audit npm`)。这可以捕获存在漏洞的直接*或传递*依赖 —— 包括在你安装软件包*之后*发布的 CVE(“当时看起来很安全,现在被标记了”),这是人类永远不会手动审查的那类问题。每次提交都运行它(不仅仅是在 lockfile 更改时)才是关键所在:它会重新查询漏洞数据库,以便在已安装依赖项上新披露的 CVE 能够在下一次提交时浮出水面。判定结果和可用性故障是区分开的:真实的发现会**阻止**(fail-closed),但如果漏洞数据库**无法访问**(离线 / registry 错误),hook 会**发出警告并放行提交** —— 这是一个可观察的可用性故障转移,绝不是悄悄跳过。(CI 和每日重新检查随后会重新覆盖离线提交时无法验证的内容。) 唯一故意的绕过是 `git commit --no-verify`,这由人类自己掌握。 搭建的 `.gitleaks.toml` 是一个**由你来调整的起始模板**:它扩展了 gitleaks 的默认规则集,为已提交且包含已分配机密的 `.env` 添加了规则(`.env.example`/`.sample`/`.template` 变体已被加入白名单),并留下一个由仓库拥有的 `[allowlist]` 块用于你的测试夹具。safedeps 拥有的是*执行权* —— 通过 `safedeps scan secrets` 运行 gitleaks —— 而不是策略内容。 `safedeps doctor --json` 返回 `{ command, repo, profile, gaps, ok, checks[] }`;`gaps`/`ok` 仅反映按仓库划分的机密泄露通道。远程态势显示为 `lane: "remote"` 检查,但缺少远程工作流、分支规则或必需的状态检查不会改变 `ok`。`doctor --fix` 仅在本地运行:它搭建仓库 hook,绝不会创建 `.github/workflows`,不会启用 GitHub Actions,也不会修改分支保护。当用户要求“安装所有不会产生费用的东西”时,建议使用禁止直接 push 到 `main` 的无 runner 分支规则;在该免费组合中不包含由 Actions 支持的必需检查。 ## 安装说明 ### 前置条件 - [Claude Code](https://docs.anthropic.com/en/docs/claude-code) 且支持 hooks - `jq` -- JSON 解析(如果缺失,hooks 会优雅退出) - `shasum` 或 `sha256sum` -- 哈希计算 - `file`(可选)-- 二进制检测 ``` # macOS brew install jq # Ubuntu / Debian sudo apt-get install jq ``` ### 从 GitHub 设置(技能 + Hooks) **1. 克隆代码仓库:** ``` git clone https://github.com/aldegad/safedeps.git cd safedeps ``` **2. 安装技能 + hooks:** ``` node scripts/install/install-safedeps-hooks.mjs ``` 安装程序是幂等的。当那些根目录存在时,它会将技能符号链接到 `~/.claude/skills/safedeps` 和 `~/.codex/skills/safedeps`,修补匹配的 hook 配置,并且 —— 配合 `--link-bin` —— 还可以通过 `~/.local/bin` 将 `safedeps` 放到 PATH 上。该 PATH 链接是可选的:hooks 在其拦截消息中指明了绝对的回退路径,因此关卡是自包含的,可以在零 PATH 设置的情况下工作。 **3. 手动注册 hook(如果需要):** 编辑 `.claude/settings.json`(项目级别)或 `~/.claude/settings.json`(全局): ``` { "hooks": { "PreToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "~/.claude/skills/safedeps/scripts/safedeps-pre-guard.sh" } ] } ], "PostToolUse": [ { "matcher": "Bash", "hooks": [ { "type": "command", "command": "~/.claude/skills/safedeps/scripts/safedeps-post-verify.sh" } ] } ] } } ``` **4. 验证权限:** ``` chmod +x ~/.claude/skills/safedeps/scripts/safedeps-pre-guard.sh chmod +x ~/.claude/skills/safedeps/scripts/safedeps-post-verify.sh ``` 就是这样。每当 Claude Code 或 Codex CLI 运行软件包安装命令时,防护机制就会自动激活。 ### 从 npm 设置(CLI 优先) ``` npm install -g @aldegad/safedeps safedeps version ``` npm 通过其标准的 `bin` 条目将 `safedeps` 放到 PATH 上。它**不会**为 Claude Code / Codex 注册 agent 技能或 hooks。要从通过 npm 安装的副本启用 hooks,请从已安装的包根目录运行安装程序: ``` cd "$(npm root -g)/@aldegad/safedeps" node scripts/install/install-safedeps-hooks.mjs ``` 安装程序是幂等的,只会添加符号链接/hook 条目。`--link-bin` 标志**仅在你通过 GitHub 克隆安装而不是通过 npm 安装时才有用** —— npm 已经将 CLI 放在了 PATH 上,因此在这个路径中该标志是多余的。 如果你希望技能文件夹本身成为权威的本地源,请首选上面的 GitHub 设置方法。 ### 使用 macOS 警报的每日重新检查 安装一个 per-user LaunchAgent,每天重新检查一次 approved-spec 账本: ``` node scripts/install/install-safedeps-recheck-agent.mjs install --hour 9 --minute 0 ``` 这会针对 `~/.safedeps/approved-specs/` 运行 `safedeps re-check --json`。它不使用 LLM token;它只调用 safedeps 使用的咨询提供者。如果发现了新的 CVE/KEV、规范被吊销,或者跳过了提供者检查,包装器会写入 `~/.safedeps/recheck-alerts.jsonl` 并发出 macOS 通知。 实用命令: ``` node scripts/install/install-safedeps-recheck-agent.mjs status node scripts/install/install-safedeps-recheck-agent.mjs uninstall tail -f ~/.safedeps/recheck.log ``` ## 真实世界攻击覆盖范围 `safedeps` 旨在捕获真实供应链事件背后的模式: - **`event-stream` (2018)** -- 带有混淆代码的恶意 `postinstall` 脚本,窃取加密货币钱包密钥。捕获方式:安装脚本分析(混淆 + 网络访问检测)。 - **`ua-parser-js` 劫持 (2021)** -- 遭到破坏的软件包添加了下载并执行加密矿机的 `preinstall` 脚本。捕获方式:安装脚本分析(网络访问 + 代码执行)。 - **`colors` / `faker` 破坏 (2022)** -- 虽然这些是作者主动发起的,但异常的依赖行为会触发依赖爆炸检查。 - **仿冒活动** -- 正在进行的活动发布了诸如 `crossenv`(代替 `cross-env`)或 `babelcli`(代替 `babel-cli`)之类的软件包。捕获方式:预检查中的仿冒模式匹配。 - **依赖项混淆攻击** -- 以更高的版本号发布到公共 registry 的内部包名。捕获方式:非标准 registry 检测 + 大量依赖项变更计数。 ## 日志和快照 | 路径 | 描述 | |---|---| | `~/.safedeps/reorg.log` | 包含时间戳、原因和回滚文件的完整重组事件历史记录 | | `~/.safedeps/confirmed` | 当前确认(安全)的快照 ID | | `~/.safedeps/snapshots/` | 所有快照文件(lock file、package.json 副本、元数据) | ``` # 查看 reorg 历史 cat ~/.safedeps/reorg.log # 检查当前已确认的 snapshot cat ~/.safedeps/confirmed # 列出所有 snapshots ls -la ~/.safedeps/snapshots/ ``` 旧的未确认快照会被自动修剪(保留最近的 10 个),而已确认的快照链将始终保留。 ## 安全加固 `safedeps` 包含多层防御,以抵御针对防护机制本身的攻击: | 措施 | 防范内容 | |---|---| | **JSON 安全元数据** | `project_dir` 通过 `jq -Rs` 进行转义,以防止快照元数据中的 JSON 注入 | | **路径规范化** | 在使用之前,通过 `realpath`/`readlink -f` 解析 `cwd` 中的符号链接和 `..` 遍历 | | **原子状态文件** | 快照 ID 和项目目录被写入一个单一的 JSON 文件中,防止 TOCTOU 竞争 | | **陈旧锁恢复** | 超过 60 秒的锁会被自动移除,防止因 `SIGKILL`/OOM 导致的永久 DoS | | **项目级范围状态** | 每个项目都有自己已确认的快照链(`confirmed_${dir_hash}`),防止跨项目干扰 | | **严格的权限** | `umask 077` 确保 `~/.safedeps/` 只能被所有者读取 | | **间接检测** | 将使用带有包管理器关键字的 `eval`、`$()` 或反引号的命令视为安装候选者 | ## 项目结构 ``` safedeps/ bin/ safedeps # CLI -- advisory gate, ledger, revoke, re-check lib/ providers/ # OSV / CISA KEV / GHSA adapters ledger/ # approved-spec ledger npm/ # lockfile closure resolver gates/ # repo-tree lane: scan / audit / hooks / doctor + templates/ scripts/ safedeps-pre-guard.sh # PreToolUse hook -- advisory ledger UX + snapshots safedeps-post-verify.sh # PostToolUse hook -- npm primary effect verification + reorg install/install-safedeps-hooks.mjs install/install-safedeps-recheck-agent.mjs install/migrate-safedeps-state.mjs safedeps-recheck-alert.sh test/ package.json SKILL.md # Claude Code / Codex skill manifest LICENSE # Apache-2.0 ``` ## 与众不同之处 `safedeps` 在 **AI 编程 agent 编写安装命令的那一刻**拦截软件包安装 —— 而不是在 CI 扫描时、PR 审查时或运行时沙箱时。这个时机是核心的区别点。 典型流程: 1. agent 编写 `npm install foo@1.2.3`(或任何其他受支持的安装动词)。 2. PreToolUse hook 执行快速的咨询性账本检查。如果直接规范缺失、过期或明显有风险,它会**阻止**安装,并在拦截原因中返回 agent 接下来应该运行的确切 `safedeps check npm foo@1.2.3` 命令。 3. agent 运行 `safedeps check`。CLI 查询 OSV / CISA KEV / GitHub Advisory,如果安全,则**将规范添加到账本中**。匹配 KEV 是硬性阻止(不可覆盖)。带有可用补丁的 CVE 会自动收窄到已修复的版本。 4. agent 重试安装。账本条目现在匹配,因此安装**继续进行**。 5. 安装完成后,PostToolUse hook 是 npm 的主要权威:它根据直接账本条目、`transitive_specs` 和 OSV 批量验证实际的 lockfile 闭包,然后检查安装脚本和原生二进制文件,如果出现任何偏离,则**自动重组**到最后一个确认的快照。 每个安装命令在运行前都会获得快速的咨询性反馈;每个 npm 安装在运行后都会获得闭包级别的强制执行。人类在 PR 审查时才会发现的那个可疑软件包,在安装时就已经被捕获了 —— 并且没有 SaaS 依赖,只有本地 CLI 加上公共数据库(OSV /V / GHSA)。 两个诚实的界限: - **命令 hook 是一种启发式算法,而不是沙箱。** 不寻常的包装器、shell 解释器或同一用户对本地 `~/.safedeps` 状态的篡改都超出了其信任边界。npm 效果关卡是兜底防线 —— 它捕获命令 hook 遗漏的内容,因为它检查的是安装结果,而不是命令文本。它是**命令无关的**:当一个看起来像安装的命令没有留下任何待定状态(PreToolUse 解析器没有识别出它)时,PostToolUse hook 仍然会针对实时的 `package-lock.json` 运行 npm 闭包检查,因此解析器的盲点不会也导致兜底防线变盲。检测始终是命令无关的;对这种被解析器遗漏的安装进行*自动回滚*需要该项目具有先前的确认安全快照 —— 没有基线的首次安装会被大声警告(系统消息 + 咨询日志),但不会自动回滚。 - **以效果为主的强制执行目前仅支持 npm。** `pip`、`cargo`、`go`、`gem`、`maven` 和 `nuget` 在其闭包解析器推出之前,仍将采用 v2.1 的命令关卡 + 重组模型。 ## 遗留 / 迁移:v1 `npm-reorg-guard` v1 产品名为 `npm-reorg-guard`,并使用 `~/.npm-reorg-guard/` 作为状态目录。v2 将状态移到了 `~/.safedeps/`。提供了一个一次性迁移方案: ``` safedeps migrate ``` - 如果 `~/.npm-reorg-guard/` 存在,它会将快照链、确认指针和日志复制到 `~/.safedeps/` 中,并归档遗留目录,因此不会出现第二个活动的状态根。 - 如果它不存在,则该命令是一个空操作(全新的 v2 用户不需要它)。 ## 许可证 [Apache License 2.0](LICENSE)
标签:CCS 2025, Cutter, GNU通用公共许可证, LLM工具, MITM代理, Node.js, 依赖审查, 暗色界面, 软件开发工具包