Actionpin

io.github.CloudCorpRecords由 GitHub 帳號 CloudCorpRecords 發布v0.1.8更新於 Nov 2, 2026

GitHub Actions supply-chain hardener: audit workflows for unpinned actions and build a SHA pin plan.

已驗證STDIO僅桌面開發者工具安全與監控

概覽

AI 產生的概覽

稽核 GitHub Actions 工作流程中未固定版本的 action,回報組織內的固定版本漂移,並在不寫入檔案的情況下產生 SHA 固定方案。

可以做什麼
  • 稽核儲存庫路徑下的工作流程與儲存庫內的複合 action,將每個 uses: 參照歸類為已固定、可變標籤、分支或本機,並給出擁有者類型與 PINNED、EXPOSED 或 PARTIAL 結論
  • 稽核組織根目錄下的每個儲存庫檢出,回報固定版本漂移,列出每個參照及使用它的儲存庫
  • 在不寫入任何檔案的情況下為儲存庫路徑產生 SHA 固定方案,透過 GitHub API 將可變或分支參照解析為提交 SHA,回傳改寫後的确切行或失敗原因
適用情境
當你想讓助理檢查某個儲存庫的 CI 工作流程是否信任可移動的 action 標籤、比較多個儲存庫的固定版本做法,或在任何人改動檔案之前準備一份可審閱的 SHA 固定變更時使用。
執行需求
以本機程序方式透過 npx 或 Docker 映像執行,僅限桌面端。稽核不需要憑證,也不需要網路。產生固定方案時會透過 GitHub API 解析參照,設定 GITHUB_TOKEN 可提高速率上限。
安裝前請注意
產生固定方案會透過 GitHub API 解析參照,因此儲存庫名稱與參照會離開本機;未設定 GITHUB_TOKEN 時只能使用較低的未驗證速率上限。此處描述的工具不寫入檔案,但同一軟體套件的 CLI 修復模式會就地改寫工作流程檔案,請與助理使用區分開來。Docker 映像參照只會回報,不會被改寫。

安裝

在 SourceWeft 中

  1. 開啟 儀表板中的 Actionpin,將其新增到工作區。
  2. 為需要使用其工具的對話啟用該服務。

Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。

其他 MCP 客戶端

參照 儲存庫 中的啟動說明。

README

actionpin

[npm version] [npm downloads] [MCP Registry]

A version tag is a promise anyone can break. A commit SHA is not.

Quickstart

bash
npx @reneturcios/actionpin audit

GitHub Actions are executable supply chain. When a workflow says uses: actions/checkout@v4, that tag can move. When a third-party action tag moves to a compromised commit, every workflow that trusts the tag runs the new code with that workflow's tokens. Pinning to a full 40-character commit SHA is the standard defense, and almost nobody does it consistently, because doing it by hand across every workflow is tedious and easy to get wrong.

actionpin audits every workflow in a repo, reports exactly which actions are pinned and which are not, and can rewrite the unpinned ones to SHAs for you, keeping the original tag as a comment so the pin stays readable.

Why this exists

GitHub Actions are the second largest confirmed open source supply-chain attack surface of the last year, behind only npm. Maintainer accounts and action tags have been hijacked before, and a mutable tag means the code your CI runs today is not guaranteed to be the code you reviewed. The fix is known and boring: pin to a SHA. actionpin makes the boring fix one command, and makes the audit callable by agents through MCP so it can run inside contribution and release workflows, not just by hand.

What it checks

For every uses: line in .github/workflows/*.yml and *.yaml:

classificationmeaning
PINNEDRef is a full 40-character commit SHA (or a full sha256 or sha512 content digest for a container image)
MUTABLERef is a version tag such as v4 or v4.2.1. The tag can move.
BRANCHRef is a branch such as main, master, or HEAD. It moves by design.
LOCALA local path such as ./local/action. Never rewritten.

Owner types: official for actions owned by actions or github, third-party for everyone else, docker for docker:// container actions, and local for local paths.

Verdict rules:

  • PINNED: every non-local action is pinned to a full SHA. Exit code 0.
  • EXPOSED: at least one third-party or container action uses a mutable tag or a branch. Exit code 1.
  • PARTIAL: only official actions are unpinned. Exit code 1.
  • Usage errors exit with code 2.

Fix mode resolves a tag or branch to its commit SHA through the GitHub API and rewrites the line to owner/repo@<sha> # <original ref>, preserving indentation and all other content. Files are edited line-wise; YAML is never parsed and re-emitted, so formatting survives. If a ref cannot be resolved, its line is left unchanged and the failure is reported. Docker image refs are reported but not rewritten; pin those by digest.

Usage

CLI

bash
# Audit the current reponpx @reneturcios/actionpin audit
# Audit another path, machine readablenpx @reneturcios/actionpin audit ~/src/my-repo --json
# Audit every repo checkout under an org root and report pin drift# (the same action used at different refs in different repos)npx @reneturcios/actionpin org ~/src/my-org --json
# Preview the pinning plan without writingnpx @reneturcios/actionpin fix --dry-run
# Pin everything resolvable, in placenpx @reneturcios/actionpin fix

Example output:

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.

Set GITHUB_TOKEN for the higher authenticated GitHub API rate limit during fix mode. Auditing needs no credentials and no network.

MCP server

Add to your MCP client config:

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

Tools:

  • audit_workflows: audit a repo path and return every action with its classification, owner type, file, and line, plus the verdict.
  • pin_plan: return the full SHA pinning plan for a path without writing any files.

Docker

bash
docker run -i ghcr.io/cloudcorprecords/actionpin mcpdocker run --rm -v "$PWD:/work" -w /work ghcr.io/cloudcorprecords/actionpin audit .

Limits (pinned by the hardening battery)

These behaviors are deliberate, tested, and stated plainly so a green report is never misread:

  • Scope is workflow files plus in-repo composite actions. A directory audit scans .github/workflows/*.yml and *.yaml, and also the action definitions that live inside the scanned repo: the root-level action.yml or action.yaml (the scanned repo's own published action definition, scanned whether or not a workflow references it, which is the normal shape for a repo that ships an action), every action.yml and action.yaml under .github/actions/, plus any local action directory a workflow references with a ./ uses path. Their internal steps are inventoried and classified like workflow steps, flagged as composite action refs, and drive the verdict the same way. A root action whose steps reference the repo's own action (via ./ or via its published name) is scanned exactly once; self-reference never recurses or double counts. The report lists how many composite files were scanned, and names any action files found elsewhere in the repo that were not scanned (not the root action file, outside .github/actions, and not referenced by a workflow), so coverage is never implied beyond what was audited. Passing an action.yml file path directly also parses it like any other file. Job-level uses: lines (reusable workflow calls) are in scope and are audited and pinned like step-level ones.
  • A local path with a malformed prefix is local, and the typo stays visible. A uses value such as $/.github/actions/issues-helper (a stray character where the dot of the ./ prefix belongs, shipped by real repos) names no remote repository, so it is classified LOCAL and is never resolved against the GitHub API in fix mode. The finding carries a note that the prefix is not a valid remote reference and looks like a local path typo, because the spelling is a real defect in the target repo even though it is not a pinning exposure.
  • Dynamic values are skipped, not guessed. A uses: value that contains a GitHub expression (${{ matrix.action }}, actions/checkout@${{ inputs.ref }}) is decided at run time and cannot be classified statically. actionpin skips it entirely instead of inventing an action or a verdict for it. Audit the matrix or input values themselves if a workflow builds its actions dynamically.
  • Short SHAs never count as pinned. Only a full 40-character SHA (or a full sha256 or sha512 digest for docker:// images) is PINNED. A short SHA such as abc1234 is reported in the BRANCH bucket and fails the verdict, because a short prefix is not a stable pin.
  • Container tags never count as pinned. For docker:// images only a full content digest counts. A tag spelled as 40 hex characters is still a tag and can be re-pushed, and a truncated or non-hex digest is not a digest; both are MUTABLE.
  • YAML anchors and aliases are resolved within the file. GitHub Actions has supported them since September 2025. An anchored uses: value is classified by the value itself, an alias line (uses: *name, or a step alias - *name) inherits the anchored classification and is flagged viaAlias, and anchors must be defined before use in the same file, matching GitHub. Fix mode pins the anchor definition line and never rewrites an alias line.
  • Refs containing slashes (release/v1, feature/new-thing) are reported as BRANCH bucket moving refs. Fix mode resolves them through the git-ref API with the slash preserved.
  • Block and flow style are both inventoried. Parsing is line-wise so fix mode can preserve formatting, and a quote-aware flow scanner inventories uses: entries written in YAML flow style (for example steps: [{uses: 'actions/checkout@v4'}]), including several entries sharing one line, flow collections split across lines, and quoted (JSON-shaped) keys. Commented-out uses: lines are ignored, and a uses: word inside a quoted string or a run command invents no action. Fix mode pins a flow entry without adding a version comment on the shared line, because a comment would eat the rest of that line.
  • A file that cannot be fully parsed is reported, never silent. When a workflow or composite file carries a uses: key whose value cannot be extracted, the report names the file in unparsedWorkflows, carries a note saying it could not be fully parsed, and floors the verdict at PARTIAL, so the file never silently contributes zero actions to a PINNED verdict.
  • Docker refs are reported, never rewritten. Pin container images by digest yourself; fix mode leaves docker:// lines unchanged and says so in the plan.
  • Empty estates say so. When no workflows and no action definitions are found under the audited path, the report carries a plain note that nothing was audited. The verdict is computed over zero actions and is not an all-clear for that path. A repo whose only auditable surface is its root action definition is audited on that definition and carries no empty-estate note.
  • Missing or wrong-type targets are usage errors, never a verdict. A path that does not exist exits 2 with an error on stderr and no report, matching hookcheck and injectcheck, so CI wired to a mistyped path fails instead of going green on nothing. Passing a single file audits it only when it is a .yml or .yaml file; any other regular file (a package.json, a README) is a usage error exit 2, not a workflow. A target that is neither a file nor a directory is a usage error too.
  • Non-regular files are never opened. Discovery stats every candidate before opening it and skips anything that is not a regular file, so a FIFO (named pipe), socket, or device planted at a workflow or action file path cannot hang or block the audit; the regular files around it are audited normally.
  • Piped output is delivered whole, or the run fails. Reports are written through a flush-aware emit path, so a report of any size arrives complete through a pipe, the way agents, scripts, and CI consume it. If the reader closes the pipe before the report is delivered, actionpin exits 141 (the shell-visible equivalent of SIGPIPE) instead of reporting success for output nobody received. Fixed in 0.1.2 after Round 1 real-repo validation caught silent truncation at exactly 65,536 bytes with a success exit code.

The toolkit

actionpin is part of a family of small, single-purpose developer tools by the same author, all built the same way: one bin that serves a CLI and an MCP server, deterministic checks with evidence, no invented answers.

  • greenlight: pre-flight checks for open-source contributions: is this issue actually landable?
  • shipcheck: verify a release actually shipped across git, npm, the MCP Registry, and GHCR.
  • hookcheck: audit auto-exec hooks in a repo for persistence-style risks.

Development

bash
npm installnpm run buildnpm test

Tests run on fixtures with an injected fetch function; no test touches the network.

License

MIT


Built by Rene Turcios - vibe coder / agent-native dev building in public in SF. Follow @CloudCorpRecords for the next tool. The family: greenlight · hookcheck · injectcheck · shipcheck - all on npm under @reneturcios/ and in the official MCP Registry.

If actionpin saved you time, star this repo: it helps other developers find it.

來源:README.md,提交 6260825

工具

3

audit_workflows

Audit GitHub workflow files under a repo path for action pinning. Finds every uses: reference, classifies it as PINNED (full 40-char SHA), MUTABLE (version tag), BRANCH, or LOCAL, labels the owner as official, third-party, docker, or local, and returns a PINNED, EXPOSED, or PARTIAL verdict with the file and line for every action.

輸入參數path必填

audit_org

Audit every repo under an org root (each immediate subdirectory that carries workflows is one repo) and report pin drift across the org: every action that is used at different refs in different repos, naming each ref and the repos that use it. The org verdict is the worst per-repo verdict; drift itself does not change the verdict.

輸入參數path必填

pin_plan

Build the SHA pinning plan for workflows under a repo path without writing any files. Resolves each mutable or branch ref to a commit SHA through the GitHub API and returns the exact rewritten line per action, or a failed entry with the reason when resolution is not possible. Local refs are never rewritten.

輸入參數path必填

版本歷史

4
  1. v0.1.8最新Oct 26, 2026
  2. v0.1.7Oct 23, 2026
  3. v0.1.6Oct 22, 2026
  4. v0.1.2Oct 22, 2026

評分

已滿足適用檢查項的 90%

該評分衡量此收錄條目的完整程度,依據註冊中心條目、端點與公開來源計算得出。它不是對伺服器本身的評價,也不表示伺服器安全或目前可用:可連通性是帶日期的檢查結果,評分也不包含安裝量或使用者評價。

  • 近 30 天內可連通25 分
  • 已宣告認證方式10 分

    請在註冊中心條目中宣告憑證請求標頭,或保持端點能夠回應探測,以便判定其認證方式。

  • 已列出工具必需15 分
  • 描述必需15 分
  • 圖示10 分
  • 文件15 分
  • 授權條款10 分