关于 python-supply-chain
python-supply-chain 是一项用于为 GitHub 上的 Python 仓库添加多层供应链防护的技能,涵盖依赖更新、安全扫描、路径所有权控制以及 SBOM 和构建来源证明,并明确区分由配套技能负责的事项。
主要功能
- 01审计现有仓库控制措施
- 02配置依赖更新自动化
- 03扫描依赖、密钥与代码
- 04用 CODEOWNERS 保护自动化路径
- 05生成 SBOM 与来源证明
适用场景
- 01加固 Python 包仓库
- 02检查锁定依赖中的漏洞
- 03添加 GitHub 安全扫描
- 04准备软件清单与构建证明
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ paldom/ python-skills --skill python-supply-chain安装后在 Claude Code 中输入/python-supply-chain确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
evals/evals.jsonreferences/dependabot.mdscanning-and-provenance.mdscripts/check_supply_chain.py详细介绍
python-supply-chain
在 GitHub 上的 Python 软件包仓库中安装分层供应链控制措施:带新鲜度延迟的依赖项更新自动化、漏洞和机密扫描、代码扫描、自动化相关路径的所有权规则,以及 SBOM/来源证明工件。此设计基于 2025–2026 年的事件浪潮(Shai-Hulud npm 蠕虫、由依赖项机器人传播的恶意 axios 版本、可变标签 Action 遭入侵):如今的攻击面是你的自动化,以及发布后的最初几小时——因此,以下任何单一控制措施都不足以应对,机器人产出的内容也应像人工 PR 一样受到审查。
不要在以下情况下使用
- CI 质量门禁工作流、分支规则集、Action SHA 固定、zizmor——如果已安装 python-ci skill,这些由它负责。本 skill 只添加扫描和更新工作流,并说明哪些控制措施依赖规则集。
- PyPI 可信发布(OIDC)和由标签触发的发布工作流——由 python-release skill 负责。本 skill 仅处理仓库端的 SBOM/来源证明;将软件包上传到 PyPI 的发布步骤应由该 skill 负责。
- Pre-commit 钩子接入(包括本地 gitleaks 钩子)——由 python-precommit skill 负责。本地钩子仅供参考;本 skill 会安装强制执行的服务器/CI 层。
- 打包和锁文件设置(
uv init、pyproject.toml)——由 python-packaging 负责。 - Agent 钩子/AGENTS.md 规则——由 agent-guardrails 负责。本 skill 仅通过 CODEOWNERS 保护 Agent 配置路径。
- 超出基本凭据轮换范围的主动事件响应——升级给人工处理;不要尝试自动清理正在发生的入侵。
工作流
按顺序完成以下步骤;每一步都有独立价值,因此在用户要求的范围结束处停止。更改 GitHub 设置的步骤需要 gh 已通过身份验证,并在仓库上拥有管理员权限——否则请输出命令供用户运行。
1. 审查当前安全状况
在添加任何内容之前,从仓库根目录运行随附的只读检查器:
python3 "${CLAUDE_SKILL_DIR}/scripts/check_supply_chain.py" --root . # file-level checks
python3 "${CLAUDE_SKILL_DIR}/scripts/check_supply_chain.py" --root . --github # + GitHub-side settings via gh
(如果当前工作目录不同,请从此 skill 的文件夹中使用绝对路径调用。)它会为每项控制措施输出一行 PASS|WARN|FAIL|NOTE check: detail,并在出现 FAIL 时以非零状态退出。请在以下步骤中修复 FAIL;将 WARN 视为待办事项。不要重复添加已存在的控制措施——应对其进行调整。
2. 基线:提交锁文件
以下所有控制措施都假定依赖项集合已固定版本并提交:uv.lock(首选)、poetry.lock/pdm.lock,或使用哈希固定依赖项的 requirements(通过 pip-tools 使用 --generate-hashes)。如果没有锁文件,这是 python-packaging 的问题——请指出并停止;审计未固定版本的依赖项集合,审计的只是猜测。
3. 依赖更新自动化(Dependabot)
编写 .github/dependabot.yml:
version: 2
updates:
- package-ecosystem: "uv" # uv.lock projects; use "pip" for requirements/pip-tools/poetry
directory: "/"
schedule:
interval: "weekly"
open-pull-requests-limit: 10
cooldown:
default-days: 7 # skip versions published < 7 days ago
groups:
python-minor-patch:
update-types: ["minor", "patch"] # majors stay individual PRs
- package-ecosystem: "github-actions" # keeps actions updated; pinning policy = python-ci
directory: "/"
schedule:
interval: "weekly"
cooldown:
default-days: 7
关键决策详见 references/dependabot.md:
- 冷却期是供应链控制手段,而不是更新计划:它会延迟采用新发布的版本,避开恶意版本通常被发现前的时间窗口;对于安全公告更新则会自动绕过冷却期——这就是它优于仅使用包管理器级新鲜度限制的原因。自 2026-07-14 起,github.com 默认应用 3 天冷却期,无需配置;
default-days: 7可用于主动延长冷却期(并与第 5 步的exclude-newer保持一致)。 - 将次要版本和补丁版本分组,是解决 PR 过多问题的公认做法。主要版本不要分组,以便对破坏性变更进行单独审查。
- 绝不要对机器人 PR 一概自动合并。 在 2026 年 4 月的恶意
axios事件中,机器人发起的更新 PR 占 214 个中的 154 个,且约 60% 的机器人 PR 在未经人工审查的情况下合并。Dependabot PR 应与其他 PR 一样,要求 CI 检查通过并经人工审查。 - 当用户需要以代码管理配置的灵活性时,Renovate 是可选方案;它对应的冷却机制是
minimumReleaseAge。相关权衡及其pinDigest陷阱见参考文档。选择一个机器人即可——同时运行两个会使通知量翻倍。 - pip、uv、pre-commit 和 github-actions 生态系统支持冷却期(
default-days以及 pip/uv 的semver-*-days);启用后,请确认更新 PR 确实会在下次计划运行时生成。
4. 锁文件漏洞审计(pip-audit)
审计从锁文件导出的项目固定依赖集:
uv export --format requirements-txt --no-emit-project -o /tmp/audit-req.txt
uvx --from pip-audit==2.10.1 pip-audit -r /tmp/audit-req.txt --no-deps
(==2.10.1 是示例固定版本——请查看 PyPI,确认当前版本并固定该版本。未固定版本的 uvx 会执行几分钟前刚发布的内容:这正是本技能要防范的攻击。)使用普通 pip 的备用方案是在项目环境中运行:python -m pip install pip-audit==2.10.1 && pip-audit。
- 不要在没有
-r的情况下直接运行uvx pip-audit:它审计的是 pip-audit 自己的临时环境,而不是你的项目,并会为错误的目标报告无漏洞。 --no-deps会跳过重新解析;由于导出文件中的版本已全部固定,因此这样做是正确的。- 按软件包报告发现的问题及其修复版本;不要盲目升级所有内容,也不要在自动化中使用
pip-audit --fix(它会修改环境,而不是锁文件)。 - 备选方案:
osv-scanner(Go 二进制文件)可直接读取uv.lock;uv audit(自 2026 年 6 月起处于预览阶段,由 OSV 提供支持,可感知锁文件)稳定后将成为无需安装的选项——请固定你验证过的 uv 版本。 - 持续审计:Dependabot 安全更新负责告警;仅当用户希望在 CI 中输出审计结果时,才添加定期扫描工作流(工作流示例见 references/scanning-and-provenance.md)。
5. 依赖解析新鲜度窗口(uv 项目)
对于 uv 项目,添加解析器级缓冲期,以避开刚发布的软件包:
[tool.uv]
exclude-newer = "2026-06-27T00:00:00Z" # resolver ignores anything published after this
uv 也接受相对时间窗口——exclude-newer = "7 days"(或 ISO 8601 格式的 P7D);exclude-newer-package 可按软件包分别设置截止时间。设置后运行 uv lock。截止时间会比较每个构件的上传时间,而非发布日期,因此较晚上传的 wheel 会根据自身时间单独过滤。
有两点需要注意:固定时间戳会使解析结果停留在过去,直到有人更新它(请将更新操作加入发布检查清单);与 Dependabot 的冷却期不同,它也会延迟安全修复——因此两者都要使用:exclude-newer 保护笔记本电脑和 CI 上运行的 uv lock,冷却期保护机器人,而安全公告会绕过机器人的冷却期。参考文档:https://docs.astral.sh/uv/reference/settings/#exclude-newer。
6. 秘密扫描、推送保护和 CI 后备检查
GitHub 端的扫描对公共仓库免费且默认启用;私有仓库需要 GitHub Secret Protection 许可。启用/验证这两个开关:
gh api -X PATCH "repos/{owner}/{repo}" --input - <<'EOF'
{ "security_and_analysis": {
"secret_scanning": { "status": "enabled" },
"secret_scanning_push_protection": { "status": "enabled" } } }
EOF
推送保护会在检测到秘密时,在其进入历史记录之前阻止推送——这严格强于任何事后扫描——但 GitHub 文档说明,它只会阻止一部分高置信度模式。添加 CI gitleaks 扫描作为后备检查,它还能捕获通过 --no-verify 绕过本地钩子的情况(参考资料中包含工作流 YAML,以及 gitleaks-action 的组织许可注意事项)。如果发现任何秘密:首先轮换凭据;重写历史记录无法让已克隆、分叉或缓存的内容不再泄露。
7. 代码扫描(CodeQL)
对于纯 Python 仓库,默认设置就足够了(无需构建步骤):
gh api -X PATCH "repos/{owner}/{repo}/code-scanning/default-setup" -f state=configured
公共仓库免费;私有仓库需要 GitHub Code Security 许可。只有当用户需要控制查询包,或需要对工作流文件进行 language: actions 覆盖时,才使用参考资料中的高级工作流。将代码扫描结果设为合并阻止条件属于规则集的配置——交由 python-ci 处理。
8. 为定义自动化的路径设置 CODEOWNERS
# .github/CODEOWNERS — LAST matching rule wins (not first)
* @OWNER/maintainers
/.github/ @OWNER/platform-security
/.github/CODEOWNERS @OWNER/platform-security
/AGENTS.md @OWNER/platform-security
/CLAUDE.md @OWNER/platform-security
/.claude/ @OWNER/platform-security
原因:能够编辑工作流、dependabot.yml 或 Agent 指令文件的人,可以绕过所有其他控制,因此这些路径需要比代码更严格的所有者。两个容易被忽略的问题:只有在分支保护/规则集中启用“要求代码所有者审核”后,CODEOWNERS 才会生效(这属于 python-ci 的职责——在交接时说明);没有写入权限的所有者会被忽略,且不会报错——请在 GitHub 上检查该文件的渲染视图,确认没有语法/所有者错误。
9. 安全状况仪表板(OpenSSF Scorecard,可选)
添加每周运行的 ossf/scorecard-action 工作流(YAML 见参考资料),即可通过 Security 选项卡中的 SARIF 结果,获得涵盖约十几项启发式检查的 0–10 分数。将其视为分流仪表板,而不是门禁:其维护者也称这些检查具有启发性,而追逐分数(例如固定无人审核的 SHA)被记录为安全作秀。在添加任何内容之前,公共仓库可以先到
https://scorecard.dev/viewer/?uri=github.com/OWNER/REPO 查看现有分数。
10. SBOM 和发布溯源证明
两种 SBOM 方案——根据受众选择:
# Repo-level SPDX from GitHub's dependency graph (compliance requests):
gh api "repos/{owner}/{repo}/dependency-graph/sbom" --jq .sbom > sbom.spdx.json
# Build-time CycloneDX from the lockfile (ship next to the wheel):
uv export --format requirements-txt --no-emit-project -o /tmp/sbom-req.txt
uvx --from cyclonedx-bom==7.3.1 cyclonedx-py requirements /tmp/sbom-req.txt -o sbom.cdx.json
对于发布版本,请在发布工作流中使用 actions/attest-build-provenance 为构建产物生成证明(并使用 actions/attest-sbom 为 SBOM 生成证明)——代码片段和所需权限见参考资料。发布工作流本身,以及通过可信发布生成的 PyPI 端证明,属于 python-release 技能。请如实告知用户其限制:证明只能证明产物在何处以及如何构建,并不能证明它是安全的——现实中曾发生过有效签名的恶意构建被发布的事件——而且只有在使用者进行验证时才有意义(gh attestation verify dist/pkg.whl --repo OWNER/REPO)。
11. 重新审计并交接
重新运行步骤 1;脚本应报告没有 FAIL。列出剩余的 WARN/NOTE 项,并为每项用一句话说明原因(有意跳过、需要许可,或属于相邻技能的职责范围)。
输出规范——完成状态
.github/dependabot.yml中包含 pip 或 uv 生态系统条目、每周计划、冷却期、分组的次要/补丁更新,以及 github-actions 条目。- 已提交锁文件;记录了固定版本的 pip-audit 调用方式(或定期扫描)。
- 已启用秘密扫描和推送保护(如果权限/许可受限,则向用户提供准确命令),并设置 CI gitleaks 后备检查。
- 已启用 CodeQL(默认设置或已提交工作流)。
- CODEOWNERS 覆盖
/.github/和 Agent 配置路径,并在交接说明中指出分支保护依赖项。 - 根据范围可选:Scorecard 工作流、SBOM 产物、接入发布工作流的证明步骤(或委派给 python-release)。
scripts/check_supply_chain.py --root .退出码为 0。
故障模式与注意事项
- 不带
-r运行uvx pip-audit会审计错误的环境(即该工具自己的临时 venv),并轻易报告零项发现。 - Dependabot 冷却期可能卡住频繁发布的依赖项:筛选器只评估了最新版本,因此每周发布一次的依赖项可能永远不会提出更新(dependabot-core #14234/#14579;已部分修复——请验证当前行为)。 表现:依赖项在 Dependabot 状态一直为绿色的情况下,悄然过时数月。
- 在包管理器层面设置冷却期会阻止安全修复;Dependabot 的冷却期不会(安全公告更新会绕过冷却期)。不要用前者替代后者。
- 尚未证明冷却期对传递依赖有效(已确认 npm 存在此缺口,见 dependabot-core #14683;pip/uv 尚未验证)——第 4 步中的锁文件审计才是实际覆盖传递依赖的控制措施。
- 机器人创建的 PR 不应获得未经验证的信任:攻击者会冒充 Dependabot 的品牌标识,而 axios 事件中,绿色检查通过后自动合并曾导致恶意软件上线。对待所有 PR 都应一视同仁地审查。
- Dependabot 不会针对固定 SHA 的 Actions 发出警报(只针对 semver 标签)——这是本技能的警报机制与 python-ci 固定版本策略之间已知的差距;dependabot 的
github-actions条目仍会提出固定版本更新,因此请保留该条目。 - 组织仓库使用 gitleaks-action 需要许可证密钥
(
GITLEAKS_LICENSE密钥;个人账户可免费使用)——这是容易被忽略、且失败时不会发出提示的设置步骤。 - CODEOWNERS 遵循最后匹配优先——末尾的
*规则会覆盖上方的所有保护规则。请将兜底规则放在最前面,具体的安全路径规则放在后面。 - 推送保护只是子集筛选器,并非保证——请保留 CI 后备检查。
- Scorecard 可被操纵,且依赖启发式规则——绝不要将其设为合并门禁;由于 API 成本原因,其公开的每周扫描会省略多项检查(CI-Tests、Contributors、Dependency-Update-Tool),因此得分与本地运行结果不同。
- 安装 Python 包会执行代码——安装时(构建后端、
setup.py)和导入时都会执行。绝不要为了检查包而安装它;先在 https://inspector.pypi.io 上阅读其内容。注意拼写仿冒包(request与requests),以及大模型建议中编造的包名(slopsquatting)——在运行uv add前,请在 pypi.org 上核实准确的包名、仓库链接和发布历史。 - 免费套餐边界:依赖关系图、Dependabot 警报和安全更新在所有仓库中均免费;密钥扫描和 CodeQL 仅对公开仓库免费——对于私有仓库,应让用户决定许可证事宜,而不是启用无法正常工作的开关。
文件
- references/dependabot.md — 完整注释版 dependabot.yml、冷却期语义与错误详情、Renovate 对比、噪声调优、自动合并策略的依据。
- references/scanning-and-provenance.md — gitleaks/TruffleHog CI 工作流、高级 CodeQL 工作流、Scorecard 工作流、含权限设置的 SBOM/证明代码片段、验证命令。
- scripts/check_supply_chain.py — 只读安全态势审计;
--github会通过gh添加 GitHub 设置检查;FAIL 时以非零状态退出。