AI Agent 会乱装依赖怎么办?package-doctor 把 Python 供应链风险变成可执行清单
AI 编程 Agent 可以替你安装库、修改依赖文件,也能在几分钟内把一个陌生包带进生产项目。问题是,传统依赖扫描通常只回答“有没有已知 CVE”,却不一定告诉你:这个漏洞是否正在被利用、项目是不是已经无人维护、你的代码是否真的触碰到了风险包,更不会阻止 Agent 下一次重新安装一个危险依赖。
package-doctor 是一个 MIT 许可的 Python 工具,目标不是替代 pip-audit,而是把依赖维护从“列出一堆告警”变成“现在该先处理什么”。它特别适合放进 AI 编码工作流中:先做日常扫描,再在 Agent 提议安装新包时执行检查。
它不是单一的 CVE 扫描器
package-doctor 使用两个维度筛选风险。第一维是包是否处在信任边界:它是否会解析、解码或认证攻击者能够影响的数据。第二维是项目是否已经没有人维护,例如仓库归档、状态标记为 Inactive,或存在没有修复版本的漏洞。只有这两类证据叠加,工具才会把“无人维护”提升为需要行动的发现;一个安静但与外部输入无关的测试库,不会自动被判成高危。
它还会把影响当前版本的公告按 CISA Known Exploited Vulnerabilities 和 FIRST EPSS 排序,并尽可能给出自己的代码是否导入该包。扫描结果按行动分组:exploited 表示当前版本受 CISA 已知被利用漏洞影响;replace 表示应该替换;upgrade 表示升级;mitigate 表示暂时缓解;quiet 和 unchecked 则分别表示安静但没有实际问题、或证据不足。
这里的关键不是“所有东西都红了”,而是先处理真正位于攻击路径上的依赖。
两分钟跑一次扫描
项目使用 Python 依赖文件或锁文件即可开始:
pip install package-doctor package-doctor scan package-doctor explain pillow package-doctor check requests pillow==10.0.0
scan 会读取 uv.lock、poetry.lock、Pipfile.lock、pyproject.toml、setup.cfg、setup.py 以及 requirements*.txt。explain 用来查看某一行结论背后的证据;check 则适合在新增依赖之前快速询问。没有锁文件时,工具会按全新安装将得到的最新版本进行判断,并把版本标为未知,因此正式 CI 仍应坚持提交锁文件。
它也提供 GitHub Action:
- uses: binuka200/package-doctor@v1.0.0
默认情况下,位于信任边界、需要处理的发现会让构建失败;同时可以生成 SARIF,交给代码扫描界面展示。工具还支持 pre-commit 和接受风险记录,后者要求写下理由与过期日期,而不是简单地把告警静音。
给 Claude Code 加一道依赖护栏
更有意思的是它把同一套检查接到了 Claude Code 的钩子上。可以在 .claude/settings.json 中配置:
{
"hooks": {
"PreToolUse": [
{ "matcher": "Bash",
"hooks": [{ "type": "command", "command": "package-doctor hook claude-code", "timeout": 60 }] }
],
"PostToolUse": [
{ "matcher": "Bash|Edit|Write|MultiEdit",
"hooks": [{ "type": "command", "command": "package-doctor hook claude-code", "timeout": 60 }] }
]
}
}
PreToolUse 阶段检查 Agent 准备安装的名称,可以拦截虚构的包、最近 30 天发布的包,以及位于信任边界的脆弱或废弃库。PostToolUse 再检查实际拉入的依赖和直接写进依赖文件的名称。这样做的价值在于:依赖安全不再只是提交代码后的审查,而是进入 Agent 的执行回路。
它和 pip-audit 如何分工
不要把两者当作竞争者。pip-audit 更适合每次提交都做稳定的 CVE 检查,告诉你锁定版本受哪些已知漏洞影响;package-doctor 关心的是优先级、可达性和维护者是否还可能发布修复。官方 README 明确建议将它们并用:前者是持续门禁,后者更像季度维护审查和 Agent 安全护栏。
项目 README 还给出了一个 60 个开源仓库、13,043 个包的测量结果:6,898 个锁定版本中有 6,897 个与 OSV 对漏洞影响版本的判断一致;这些是项目作者公布的测试数据,不应理解为对所有项目的普遍保证。实际部署时,仍要复核误报、信任边界映射和业务代码的导入路径。
适合怎样落地
第一步,把 scan 放进 CI,但不要一开始就对所有历史依赖“一刀切”。第二步,为真正处理外部输入的包补充或审查暴露映射;这个项目把约 1,500 个包的判断放在可讨论的 exposure.toml 中,团队可以对照自己的业务修正。第三步,再启用 Claude Code 钩子,让 Agent 在安装依赖前先问一次安全问题。
它的边界也很清楚:依赖数据、CISA 和 EPSS 会变化,风险判断不能替代人工审查;“没有人维护”本身也不是对维护者的指责。更准确的使用方式是把它当作排序器和证据收集器——帮助团队先修最可能造成真实影响的依赖,同时让自动化编码工具少引入一个未经检查的新包。