mcpField
A
actionpin

actionpin

本地服务
github.com/CloudCorpRecords安全01 天前更新

关于 actionpin

actionpin 审计 GitHub Actions 工作流和复合 Action 引用,并生成将可变引用固定到提交 SHA 的计划。它面向需要基于证据进行供应链检查的维护者和 Agent,同时提供命令行与 MCP 接口。

主要功能

  1. 01按固定状态分类 Action 引用
  2. 02报告工作流审计结论
  3. 03生成 SHA 固定计划
  4. 04在修复模式中改写可解析的引用
  5. 05扫描指定的复合 Action 定义

适用场景

  1. 01检查仓库的 Actions 供应链风险
  2. 02发布前审查工作流中的 Action
  3. 03预览 SHA 更改而不修改文件

MCP 相关

MCP 服务提供 `audit_workflows` 以审计仓库,以及 `pin_plan` 以生成 SHA 固定计划而不修改文件。可通过文档所示的 `npx` 配置由 MCP 客户端调用。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"cloudcorprecords-actionpin": {
"command": "npx",
"args": [
"-y",
"@reneturcios/actionpin"
]
}
}
}
启动命令npx -y @reneturcios/actionpin

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
npm@reneturcios/actionpin0.1.8
ocighcr.io/cloudcorprecords/actionpin:0.1.8

工具

2

收录的工具列表 · 更新于 2 天前

参数类型必填说明
pathstring是仓库根目录、.github/workflows 目录或单个工作流文件

详细介绍

actionpin

版本标签是一种任何人都能破坏的承诺。提交 SHA 则不是。

GitHub Actions 是可执行的供应链。当工作流写着 uses: actions/checkout@v4 时,该标签可能会变动。当第三方操作的标签被移到遭到入侵的提交时,所有信任该标签的工作流都会使用该工作流的令牌运行新代码。固定到完整的 40 个字符提交 SHA 是标准的防护措施,但几乎没人能始终如一地做到,因为手动处理每个工作流既繁琐又容易出错。

actionpin 会审计仓库中的每个工作流,准确报告哪些操作已固定、哪些没有,还可以替你将未固定的操作改写为 SHA,并保留原始标签作为注释,让固定后的引用仍然易读。

为什么要开发这个工具

GitHub Actions 是过去一年中已确认的第二大开源供应链攻击面,仅次于 npm。维护者账户和操作标签曾遭劫持,而可变标签意味着 CI 今天运行的代码不一定是你审查过的代码。解决方法早已明确,也很简单:固定到 SHA。actionpin 将这个简单的修复变成一条命令,并让 Agent 可以通过 MCP 调用审计,这样它就能在贡献和发布工作流中运行,而不只是供人手动执行。

检查内容

针对 .github/workflows/*.yml 和 *.yaml 中的每一行 uses::

分类含义
PINNED引用是完整的 40 个字符提交 SHA(或容器镜像的完整 sha256 或 sha512 内容摘要)
MUTABLE引用是版本标签,例如 v4 或 v4.2.1。标签可能会变动。
BRANCH引用是分支,例如 main、master 或 HEAD。分支本来就会变动。
LOCAL本地路径,例如 ./local/action。永远不会被改写。

所有者类型:official 表示由 actions 或 github 所有的操作,third-party 表示其他所有者,docker 表示 docker:// 容器操作,local 表示本地路径。

判定规则:

  • PINNED:所有非本地操作都固定到了完整 SHA。退出代码为 0。
  • EXPOSED:至少有一个第三方或容器操作使用了可变标签或分支。退出代码为 1。
  • PARTIAL:只有官方操作未固定。退出代码为 1。
  • 用法错误:退出代码为 2。

修复模式会通过 GitHub API 将标签或分支解析为提交 SHA,并将该行改写为 owner/repo@<sha> # <original ref>,同时保留缩进和其他所有内容。文件按行编辑;不会解析再重新输出 YAML,因此格式得以保留。如果无法解析某个引用,该行将保持不变,并报告失败。Docker 镜像引用会报告,但不会改写;请将其固定到摘要。

用法

CLI
# Audit the current repo
npx @reneturcios/actionpin audit

# Audit another path, machine readable
npx @reneturcios/actionpin audit ~/src/my-repo --json

# Preview the pinning plan without writing
npx @reneturcios/actionpin fix --dry-run

# Pin everything resolvable, in place
npx @reneturcios/actionpin fix

输出示例:

actionpin audit .: EXPOSED
  workflows: 2, actions: 6, pinned: 1, mutable: 4, branch: 1, local: 0
  [PINNED] .github/workflows/ci.yml:12 actions/checkout@0123456789abcdef0123456789abcdef01234567 (official)
  [MUTABLE] .github/workflows/ci.yml:13 actions/setup-node@v4 (official)
  [MUTABLE] .github/workflows/publish.yml:20 docker/build-push-action@v6 (third-party)
EXPOSED: at least one third-party or container action uses a mutable tag or branch ref.

在修复模式下设置 GITHUB_TOKEN,即可获得更高的 GitHub API 认证速率限制。审计无需凭据,也无需联网。

MCP 服务

添加到 MCP 客户端配置中:

{
  "mcpServers": {
    "actionpin": {
      "command": "npx",
      "args": ["-y", "@reneturcios/actionpin", "mcp"]
    }
  }
}

工具:

  • audit_workflows:审计仓库路径,并返回每个操作的分类、所有者类型、文件和行号,以及判定结果。
  • pin_plan:返回指定路径的完整 SHA 固定计划,不会写入任何文件。
Docker
docker run -i ghcr.io/cloudcorprecords/actionpin mcp
docker run --rm -v "$PWD:/work" -w /work ghcr.io/cloudcorprecords/actionpin audit .

限制(由加固测试套件验证)

这些行为都是有意设计、经过测试且明确说明的,确保绿色报告不会被误读:

  • 范围包括工作流文件和仓库内的复合操作。 目录审计会扫描 .github/workflows/*.yml 和 *.yaml,也会扫描位于被扫描仓库内的操作定义:根目录下的 action.yml 或 action.yaml(即使工作流未引用,也会扫描被扫描仓库自身发布的操作定义;这是发布操作的仓库通常采用的结构)、.github/actions/ 下的每个 action.yml 和 action.yaml,以及工作流通过 ./ 使用路径引用的任何本地操作目录。系统会盘点这些文件的内部步骤,并像工作流步骤一样进行分类、标记为复合操作引用,并以相同方式决定审计结论。根操作中引用仓库自身操作(通过 ./ 或已发布的名称)的步骤只扫描一次;自引用不会递归扫描或重复计数。报告会列出扫描了多少个复合操作文件,并指出仓库其他位置发现但未扫描的操作文件(不是根操作文件、不在 .github/actions 下,且未被工作流引用),因此绝不会暗示审计覆盖范围超出实际范围。直接传入 action.yml 文件路径也会像解析其他文件一样对其进行解析。作业级 uses: 行(可复用工作流调用)也在范围内,会像步骤级调用一样进行审计和固定。
  • 前缀格式错误的本地路径仍是本地路径,并会保留拼写错误。 像 $/.github/actions/issues-helper 这样的 uses 值(真实仓库中确实存在这种把 ./ 前缀中的点替换成多余字符的情况)并未指定远程仓库,因此会被归类为 LOCAL,修复模式下绝不会通过 GitHub API 解析。该发现会附带说明,指出该前缀不是有效的远程引用,看起来像本地路径拼写错误;因为即使它不是固定版本方面的风险,这种拼写在目标仓库中仍是实际缺陷。
  • 动态值会被跳过,而不是靠猜测处理。 含有 GitHub 表达式(${{ matrix.action }}、actions/checkout@${{ inputs.ref }})的 uses: 值会在运行时确定,无法静态分类。actionpin 会将其完全跳过,而不是凭空编造操作或审计结论。如果工作流会动态构造操作,请审计矩阵值或输入值本身。
  • 短 SHA 永远不会被视为已固定。 只有完整的 40 个字符 SHA(或 docker:// 镜像的完整 sha256 或 sha512 摘要)才会被标记为 PINNED。像 abc1234 这样的短 SHA 会归入 BRANCH 类别,并导致审计结论不通过,因为短前缀不是稳定的固定版本。
  • 容器标签永远不会被视为已固定。 对于 docker:// 镜像,只有完整的内容摘要才算固定版本。由 40 个十六进制字符组成的标签仍然是可重新推送的标签;截断的摘要或非十六进制摘要也不是真正的摘要;两者都会被标记为 MUTABLE。
  • YAML 锚点和别名会在文件内解析。 GitHub Actions 自 2025 年 9 月起支持它们。带锚点的 uses: 值会根据其值本身分类;别名行(uses: *name 或步骤别名 - *name)会继承锚点分类并标记为 viaAlias;锚点必须像 GitHub 一样在同一文件中先定义后使用。修复模式会固定锚点定义行,绝不会改写别名行。
  • 包含斜杠的引用(release/v1、feature/new-thing)会被归入 BRANCH 类别,标记为可变引用。修复模式会保留斜杠,通过 git-ref API 解析它们。
  • 逐行解析。 不会检测单行流式 YAML(例如 steps: [{ uses: actions/checkout@v4 }]),也会忽略注释掉的 uses: 行。
  • Docker 引用只报告,不改写。 请自行通过摘要固定容器镜像;修复模式会保持 docker:// 行不变,并在计划中说明这一点。
  • 没有可审计内容时会明确说明。 如果被审计路径下没有工作流和操作定义,报告会附带一条普通说明,指出没有任何内容经过审计。审计结论根据零个操作计算,不表示该路径已通过审计。如果仓库中唯一可审计的内容是根操作定义,系统会审计该定义,并且不会附带无可审计内容的说明。
  • 目标缺失或类型错误属于用法错误,不会给出审计结论。 路径不存在时会以错误状态码 2 退出,在标准错误输出中显示错误且不生成报告;这与 hookcheck 和 injectcheck 的行为一致,因此在 CI 中接入时,路径拼写错误会导致失败,而不会因无内容可审计而误报通过。传入单个文件时,只有 .yml 或 .yaml 文件会被审计;其他任何普通文件(如 package.json、README)都会导致用法错误,状态码为 2,而不会被当作工作流。既不是文件也不是目录的目标同样属于用法错误。
  • 绝不会打开非普通文件。 发现过程会先对每个候选文件执行 stat,再打开文件;任何非普通文件都会被跳过。因此,即使有人在工作流或操作文件路径放置 FIFO(命名管道)、套接字或设备,也不会导致审计挂起或阻塞;周围的普通文件仍会正常审计。
  • 管道输出要么完整送达,要么运行失败。 报告通过支持刷新机制的输出路径写入,因此无论报告多大,都能通过管道完整送达,符合 Agent、脚本和 CI 的使用方式。如果读取端在报告送达前关闭管道,actionpin 会以状态码 141 退出(在 Shell 中等同于 SIGPIPE),而不会在输出无人接收的情况下报告成功。此问题已在 0.1.2 中修复;Round 1 的真实仓库验证发现,报告恰好在 65,536 字节处被静默截断,但退出状态码仍为成功。

工具包

actionpin 是同一作者开发的一系列小型单用途开发工具之一,它们采用相同的构建方式:一个二进制文件同时提供 CLI 和 MCP 服务,执行带有证据的确定性检查,不编造答案。

  • greenlight:开源贡献的提交前检查:这个问题真的可以合并吗?
  • shipcheck:验证某个版本是否确实已发布到 git、npm、MCP Registry 和 GHCR。
  • hookcheck:审计代码库中的自动执行钩子,检查是否存在持久化类风险。

开发

npm install
npm run build
npm test

测试使用注入了 fetch 函数的固定样例运行;没有任何测试会访问网络。

许可证

MIT

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。