checkout-isolated: add a pre-checkout git-config isolation action - #4
Conversation
Hardening a checkout has to happen before that checkout runs, which rules out a local (`./`) action in the consuming repo: GitHub resolves those from the workspace, and the workspace is empty until something checks out — a consumer that tried it got "Can't find action.yml" on a fresh runner. Downloaded from here, the runner needs no workspace for it. The step itself is the block consumers already run inline ahead of a checkout on self-hosted runners, with the checkout's ref, depth and credential persistence as inputs. persist-credentials defaults off, unlike actions/checkout. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
| } >> "$GITHUB_ENV" | ||
| rm -rf .git | ||
|
|
||
| - uses: actions/checkout@v6 |
There was a problem hiding this comment.
Semgrep identified a blocking 🔴 issue in your code:
GitHub Actions step uses a mutable tag or branch reference. Tags and branch names can be silently repointed by the action owner, enabling supply-chain attacks — as seen in the trivy-action and kics-github-action compromises. Pin the reference to a full 40-character commit SHA instead, e.g. uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608.
To resolve this comment:
🔧 No guidance has been designated for this issue. Fix according to your organization's approved methods.
💬 Ignore this finding
Reply with Semgrep commands to ignore this finding.
/fp <comment>for false positive/ar <comment>for acceptable risk/other <comment>for all other reasons
Alternatively, triage in Semgrep AppSec Platform to ignore the finding created by github-actions-mutable-action-tag.
You can view more details about this finding in the Semgrep AppSec Platform.
There was a problem hiding this comment.
/ar actions/checkout is GitHub's own first-party action, and every one of the eight other checkout pins in this repo (ci.yml, codex-agent.yml, flaky-*.yml, flaky-filter, flaky-record-results, link-check.yml, spellcheck.yml) is the same @v6 version tag. SHA-pinning only this one would diverge from all of them and then drift, since the repo has no process for bumping SHA pins — the deliberate SHA pin here is openai/codex-action, a third party. The rule's threat model (the action owner silently repointing the tag) is GitHub itself, which the runner and the API already trust wholesale.
Problem
Git-config isolation only helps if it runs before a checkout. That makes it
impossible to package as a local (
./) composite action in a consuming repo:GitHub resolves local actions from the workspace, and the workspace is empty
until something checks out. A consumer that factored its triplicated
isolate-then-checkout block into
./.github/actions/checkout-isolatedgotCan't find 'action.yml'on a fresh runner, in every job that used it.Consumed from here it works, because the runner downloads a remote action
without needing a workspace at all.
What this adds
.github/actions/checkout-isolated— the isolate-then-checkout block consumersalready run inline ahead of a checkout on self-hosted runners:
step in the job, ignores system config, and keeps only
safe.directory, so noleftover key that maps an event or path to an executable (hooks, fsmonitor,
attributesFile filters, templateDir,
url.insteadOf,credential.helper,sshCommand, …) can take effect;.git, which carries the same state locally;ref/fetch-depth/persist-credentialsas inputs.persist-credentialsdefaults tofalserather than actions/checkout'strue:a job that pushes should mint a scoped token and pass it explicitly.
Nothing existing changes — this only adds a new unit plus one README row, so
moving
v1onto it is behaviour-preserving for current consumers.🤖 Generated with Claude Code
Note
Low Risk
Additive CI plumbing only; no changes to existing workflows or runtime product code, though mis-ordering the step in a consumer job would weaken the intended hardening.
Overview
Introduces
checkout-isolated, a composite action meant as a job’s first step on persistent self-hosted runners. Beforeactions/checkout@v6, it writes a minimal global git config underRUNNER_TEMP, exportsGIT_CONFIG_GLOBAL/GIT_CONFIG_NOSYSTEM(and nulls system config) for the rest of the job, setssafe.directory '*', andrm -rf .gitso reused workspace state cannot influence checkout.Exposes
ref,fetch-depth(default1), andpersist-credentials(defaultfalse, unlike stock checkout). The action is documented in the README Shared CI utilities table with a note that it must be consumed from this repo (not as a local./action) because isolation has to run before any workspace checkout.Reviewed by Cursor Bugbot for commit a6d3c9d. Bugbot is set up for automated code reviews on this repo. Configure here.