actions-pinning

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

actions-pinning

actions-pinning

Pins every
uses:
reference in GitHub Actions workflows, composite actions, and reusable workflows to a commit SHA, verifies each SHA belongs to the claimed action repository, and keeps the pins current with Dependabot.
This skill covers supply-chain pinning only.
/oss-hygiene
covers
Token-Permissions
and
Dangerous-Workflow
hardening for the same workflow files;
/ci-optimize
covers wall-clock speed. Run those separately.
将 GitHub Actions 工作流、复合 Action 和可复用工作流中的每个
uses:
引用锁定到提交 SHA,验证每个 SHA 确实属于所声明的 Action 仓库,并使用 Dependabot 让这些锁定版本保持最新。
此 skill 仅涵盖供应链锁定。
/oss-hygiene
负责对同一工作流文件进行
Token-Permissions
和
Dangerous-Workflow
加固;
/ci-optimize
负责实际运行时间优化。这两项应单独运行。

Protocol

协议

1. Inventory

1. 盘点

Run the bundled scanner against every workflow and composite/reusable workflow file:
bash
python3 scripts/pin_check.py .
It walks
.github/workflows/**
,
.github/actions/**
, and every
action.yml
or
action.yaml
manifest in the tree. It skips VCS and dependency directories:
.git
,
.hg
,
.svn
,
node_modules
,
.venv
,
venv
,
__pycache__
,
dist
,
build
,
.tox
, and
target
. It scans
vendor/
, because a
./vendor/...
reference can run a vendored action. It prints a table of
(file, line, action, ref, status)
for every
uses:
line and exits 1 when any reference is unpinned. Use
--json
for machine-readable output when scripting the remaining steps.
The scanner uses regular expressions, not a YAML parser. It removes one matching pair of surrounding quotes from each
uses:
value. It has two known limits; check the workflow by hand when either applies:
  • A
    uses:
    line inside a
    run: |
    block scalar gives a false row.
  • A flow-style mapping such as
    - {uses: owner/repo@v1}
    gives no row.
对每个工作流文件以及复合/可复用工作流文件运行内置扫描器:
bash
python3 scripts/pin_check.py .
它会遍历目录树中的
.github/workflows/**
、
.github/actions/**
,以及每个
action.yml
或
action.yaml
manifest。它会跳过 VCS 和依赖目录:
.git
、
.hg
、
.svn
、
node_modules
、
.venv
、
venv
、
__pycache__
、
dist
、
build
、
.tox
和
target
。它会扫描
vendor/
,因为
./vendor/...
引用可以运行 vendored Action。
它会为每个
uses:
行打印
(file, line, action, ref, status)
表格,并在任何引用未锁定时以状态码 1 退出。编写后续步骤的脚本时,使用
--json
获取机器可读输出。
扫描器使用正则表达式,而不是 YAML parser。它会从每个
uses:
值中移除一对匹配的外围引号。它有两个已知限制;出现以下任一情况时,应手动检查工作流:
  • run: |
    块标量内的
    uses:
    行会产生误报行。
  • - {uses: owner/repo@v1}
    等流式映射不会产生对应行。

2. Classify

2. 分类

The scanner assigns one status per reference:
StatusMeaningAction needed
pinned-sha
already a full 40-character commit SHAnone
unpinned-tag
a tag-shaped ref such as
v4
or
v4.1.0
resolve to a SHA
unpinned-branch
a common branch name such as
main
resolve to a SHA
unpinned-ref
any other ref, such as
release/v1
; type unknown
resolve to a SHA
unpinned-commit
a commit-like hex ref, such as a short SHA
de0fac2
or an uppercase 40-character SHA
resolve to the full lowercase SHA
missing-ref
no
@ref
at all
resolve to a SHA
invalid-self-ref
a
$/path
self-repository reference with an
@ref
suffix
remove the
@ref
suffix
local
a local
./path
action or a
$/path
self-repository reference
skip — not a supply-chain risk
docker
a
docker://image
reference
flag separately — SHA pinning applies to the image digest, not this scanner
扫描器会为每个引用分配一种状态:
状态含义需要采取的操作
pinned-sha
已经是完整的 40 字符提交 SHA无
unpinned-tag
形如标签的引用,例如
v4
或
v4.1.0
解析为 SHA
unpinned-branch
常见分支名称,例如
main
解析为 SHA
unpinned-ref
任何其他引用,例如
release/v1
;类型未知
解析为 SHA
unpinned-commit
类似提交的十六进制引用,例如短 SHA
de0fac2
或大写的 40 字符 SHA
解析为完整的小写 SHA
missing-ref
完全没有
@ref
解析为 SHA
invalid-self-ref
带有
@ref
后缀的
$/path
自仓库引用
移除
@ref
后缀
local
本地
./path
Action 或
$/path
自仓库引用
跳过——不属于供应链风险
docker
docker://image
引用
单独标记——SHA 锁定应作用于镜像 digest,而不由该扫描器处理

3. Resolve each ref to a commit SHA

3. 将每个引用解析为提交 SHA

For each
unpinned-tag
,
unpinned-branch
,
unpinned-ref
,
unpinned-commit
, or
missing-ref
finding:
bash
undefined
对于每条
unpinned-tag
、
unpinned-branch
、
unpinned-ref
、
unpinned-commit
或
missing-ref
检查结果:
bash
undefined

Tag: the ref object is the commit (lightweight) or a tag object (annotated).

Tag: the ref object is the commit (lightweight) or a tag object (annotated).

gh api repos/{owner}/{repo}/git/ref/tags/{tag} --jq '.object'
gh api repos/{owner}/{repo}/git/ref/tags/{tag} --jq '.object'

Branch: the ref object is the commit directly.

Branch: the ref object is the commit directly.

gh api repos/{owner}/{repo}/git/ref/heads/{branch} --jq '.object.sha'
gh api repos/{owner}/{repo}/git/ref/heads/{branch} --jq '.object.sha'

Annotated tag: dereference the tag object to get the commit SHA.

Annotated tag: dereference the tag object to get the commit SHA.

gh api repos/{owner}/{repo}/git/tags/{tag_sha} --jq '.object.sha'

For an `unpinned-ref`, try the `tags/` path first, then the `heads/`
path.

For an `unpinned-commit`, the tag and branch paths cannot resolve the
ref. Resolve it through the commits endpoint, which returns the full
lowercase SHA:

```bash
gh api repos/{owner}/{repo}/commits/{ref} --jq '.sha'
Impostor-commit check — always run before rewriting a pin. Confirm the resolved SHA actually belongs to the action's own repository, not a fork, a rewritten ref, or a spoofed value:
bash
gh api repos/{owner}/{repo}/commits/{sha}
A 404 here means the SHA does not belong to that repository. Stop and re-resolve; do not write an unverified SHA.
Once verified, rewrite the line:
yaml
uses: owner/repo@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
Keep the original tag as a trailing comment — it is the human-readable version marker; the SHA is the enforced pin.
gh api repos/{owner}/{repo}/git/tags/{tag_sha} --jq '.object.sha'

对于 `unpinned-ref`,先尝试 `tags/` 路径,然后尝试 `heads/` 路径。

对于 `unpinned-commit`,tag 和 branch 路径均无法解析该引用。通过 commits 端点进行解析,该端点会返回完整的小写 SHA:

```bash
gh api repos/{owner}/{repo}/commits/{ref} --jq '.sha'
冒名提交检查——始终在重写锁定版本前执行。 确认解析出的 SHA 确实属于该 Action 自身的仓库,而不是来自 fork、被重写的 ref 或伪造值:
bash
gh api repos/{owner}/{repo}/commits/{sha}
这里返回 404 意味着该 SHA 不属于对应仓库。停止并重新解析;不要写入未经验证的 SHA。
验证完成后,重写该行:
yaml
uses: owner/repo@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
保留原始标签作为尾随注释——它是便于人类阅读的版本标记;SHA 才是实际强制执行的锁定版本。

4. Keep pins fresh with Dependabot

4. 使用 Dependabot 保持锁定版本为最新

Add (or merge into an existing
dependabot.yml
) the
github-actions
ecosystem entry in
assets/dependabot-actions-snippet.yml
. Dependabot resolves tag bumps to new commit SHAs automatically and opens a PR with the version comment updated — review and merge those PRs rather than hand-editing pins later.
Version updates (not security updates) default to a 3-day registry-availability cooldown as of 2026-07-14; a newly published tag won't appear in a Dependabot PR until it clears that window. See
references/policy.md
for the source.
For the full
dependabot.yml
scaffold across every ecosystem in the repo, use
/oss-hygiene
— this skill only owns the
github-actions
entry.
将
assets/dependabot-actions-snippet.yml
中的
github-actions
ecosystem 条目添加到现有
dependabot.yml
中,或与之合并。Dependabot 会自动将标签升级解析为新的提交 SHA,并创建一个已更新版本注释的 PR——应审查并合并这些 PR,而不是之后手动编辑锁定版本。
截至 2026-07-14,版本更新(而非安全更新)默认采用 3 天的 registry 可用性冷却期;新发布的标签在通过该窗口前不会出现在 Dependabot PR 中。来源见
references/policy.md
。
如需覆盖仓库中所有 ecosystem 的完整
dependabot.yml
脚手架,请使用
/oss-hygiene
——本 skill 仅负责
github-actions
条目。

5. Repository and organization pinning policy

5. 仓库和组织级锁定策略

GitHub can enforce SHA pinning at the allowed-actions policy level (repo, org, or enterprise), including blocking specific actions outright. Read the current policy at the scope of the request before proposing any change:
bash
undefined
GitHub 可以在 allowed-actions 策略层级(仓库、组织或企业)强制执行 SHA 锁定,包括直接阻止特定 Action。提出更改前,先读取请求范围内的当前策略:
bash
undefined

Repository scope.

Repository scope.

gh api repos/{owner}/{repo}/actions/permissions
gh api repos/{owner}/{repo}/actions/permissions

Organization scope. Use this for an organization-wide request.

Organization scope. Use this for an organization-wide request.

gh api orgs/{org}/actions/permissions

These are reads. Never call the corresponding write endpoints
(`PUT repos/{owner}/{repo}/actions/permissions`,
`PUT orgs/{org}/actions/permissions`, and the `selected-actions` /
`allowed_actions` variants) without the user's explicit authorization
for that specific change — policy changes can block other workflows
from running.

The SHA-pinning policy applies to actions only. Reusable workflows
can still use a tag under that policy, so this skill pins reusable
workflow references itself.
gh api orgs/{org}/actions/permissions

以上调用仅用于读取。未经用户明确授权进行该项具体更改,绝不能调用对应的写入端点(`PUT repos/{owner}/{repo}/actions/permissions`、`PUT orgs/{org}/actions/permissions`,以及 `selected-actions`/`allowed_actions` 变体),因为策略更改可能会阻止其他工作流运行。

SHA 锁定策略仅适用于 Action。在该策略下,可复用工作流仍可使用标签,因此本 skill 会自行锁定可复用工作流引用。

6. Flag mutable downloads inside workflow scripts

6. 标记工作流脚本中的可变下载

Regex pinning covers
uses:
only. While reading each workflow, also flag (findings only, no rewrite) any
run:
step that fetches code outside the pinned-action mechanism:
  • curl ... | sh
    or
    curl ... | bash
    piping a remote script straight into a shell.
  • wget
    from a URL with no version or checksum.
  • pip install package
    (or
    npm install
    ,
    gem install
    , ...) with no version pin.
These are supply-chain risk in the same family as an unpinned action, but fixing them is per-ecosystem and often changes build behavior — report them, do not rewrite them.
正则表达式锁定仅涵盖
uses:
。阅读每个工作流时,还要标记(仅报告发现,不重写)任何通过锁定 Action 机制之外获取代码的
run:
步骤:
  • curl ... | sh
    或
    curl ... | bash
    ,将远程脚本直接通过管道交给 shell 执行。
  • 使用
    wget
    从没有版本或校验和的 URL 下载。
  • pip install package
    (或
    npm install
    、
    gem install
    等)且未锁定版本。
这些问题与未锁定的 Action 属于同一类供应链风险,但修复方式取决于具体 ecosystem,且通常会改变构建行为——请报告,不要重写。

7. Optional: zizmor

7. 可选:zizmor

If
zizmor
is installed, run it for a second opinion (it also checks
bot-conditions
and composite-action internals this scanner does not):
bash
zizmor .github/workflows/
Skip silently if it is not installed — it is optional tooling, not a required gate.
如果已安装
zizmor
,可运行它以获得第二意见(它还会检查
bot-conditions
以及此扫描器不会检查的复合 Action 内部机制):
bash
zizmor .github/workflows/
如果未安装则静默跳过——这是可选工具,不是必需的门禁。

8. Verify

8. 验证

Re-run the scanner after every rewrite batch:
bash
python3 scripts/pin_check.py . && echo "all uses: references pinned"
Exit 0 with no
unpinned-tag
,
unpinned-branch
,
unpinned-ref
,
unpinned-commit
,
missing-ref
, or
invalid-self-ref
rows means every actionable reference is pinned. Report
local
and
docker
rows separately — they are informational, not failures.
每批重写完成后,重新运行扫描器:
bash
python3 scripts/pin_check.py . && echo "all uses: references pinned"
以状态码 0 退出,且没有
unpinned-tag
、
unpinned-branch
、
unpinned-ref
、
unpinned-commit
、
missing-ref
或
invalid-self-ref
行,意味着每个可处理的引用均已锁定。
local
和
docker
行应单独报告——它们只是信息,不是失败。

What this skill is NOT for

本 skill 不适用于

  • Token-Permissions
    and
    Dangerous-Workflow
    hardening (least-privilege
    permissions:
    blocks,
    pull_request_target
    risk,
    ${{ github.event.* }}
    interpolation into shell) — use
    /oss-hygiene
    .
  • CI run-time speed — use
    /ci-optimize
    .
  • Choosing or writing the full
    dependabot.yml
    for non-Actions ecosystems — use
    /oss-hygiene
    .
  • Applying an org-wide allowed-actions policy without the repo owner's explicit authorization for that specific write.
  • Token-Permissions
    和
    Dangerous-Workflow
    加固(最小权限
    permissions:
    块、
    pull_request_target
    风险、将
    ${{ github.event.* }}
    插值到 shell 中)——使用
    /oss-hygiene
    。
  • CI 运行速度优化——使用
    /ci-optimize
    。
  • 为非 Actions ecosystem 选择或编写完整的
    dependabot.yml
    ——使用
    /oss-hygiene
    。
  • 在没有仓库所有者针对该项具体写入操作明确授权的情况下,应用组织范围的 allowed-actions 策略。

References

参考资料

  • references/policy.md
    — cited primary sources for
    uses:
    syntax, SHA pinning, the allowed-actions policy, SHA resolution endpoints, the Dependabot cooldown, and zizmor.
  • scripts/pin_check.py
    — the inventory/classification scanner used in steps 1, 2, and 8 (
    --self-test
    runs its embedded fixtures;
    --json
    for machine-readable output).
  • assets/dependabot-actions-snippet.yml
    — the
    github-actions
    ecosystem entry for
    dependabot.yml
    .
  • references/policy.md
    ——
    uses:
    语法、SHA 锁定、allowed-actions 策略、SHA 解析端点、Dependabot 冷却期和 zizmor 的引用来源。
  • scripts/pin_check.py
    ——步骤 1、2 和 8 中使用的盘点/分类扫描器(
    --self-test
    运行其内置测试夹具;
    --json
    用于机器可读输出)。
  • assets/dependabot-actions-snippet.yml
    ——用于
    dependabot.yml
    的
    github-actions
    ecosystem 条目。