Summary
Since v0.91.0 (#65423, fail-closed credential cleanup), the agent job's Clean credentials step runs clean_git_credentials.sh followed by verify_git_credentials.sh. When any actions/checkout step in the job used persist-credentials: true, the verify script always fails, and the agent never starts:
Cleaning git credentials from '/home/runner/work/<repo>/<repo>/.git/config'
Found authenticated remote URLs, cleaning...
Cleaned credentials from remote.origin.url
✓ Git credentials cleaned from '/home/runner/work/<repo>/<repo>/.git/config'
ERROR: Git credentials remain in /home/runner/work/<repo>/<repo>/.git/config; refusing agent execution
##[error]Process completed with exit code 1.
Root cause
The two scripts read different things:
- actions/checkout v6+ (actions/checkout#2286) no longer writes the token into
.git/config. It writes http.https://github.com/.extraheader into ${RUNNER_TEMP}/git-credentials-<uuid>.config and links it from .git/config with includeIf.gitdir:<workspace>/.git.path, includeIf.gitdir:<workspace>/.git/worktrees/*.path and the /github/workspace container equivalents. Submodule configs get the same entries.
clean_git_credentials.sh edits .git/config with git config --file <path> .... It does not follow includes, so it removes the credential.* and extraheader entries in that file, but leaves both the includeIf.*.path entries and the included credentials file untouched.
verify_git_credentials.sh reads with git config --file <path> --includes --list. It follows the includeIf path, sees http.https://github.com/.extraheader, and exits 1.
As a result, the cleanup can never satisfy its own verification when checkout persisted credentials.
Reproduction
- Any gh-aw v0.91.0 / v0.91.1 workflow whose agent job checks out with
persist-credentials: true. A custom steps: checkout, or a compiled checkout changed to true, both reproduce it.
- Run it on a GitHub-hosted runner. The checkout pinned by the compiler is
actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1.
- Clean credentials fails as shown above. On v0.90.3, with no verify step, the same workflow runs.
Observed in a fleet that forces persist-credentials: true as a workaround for checkout's submodule cleanup failure (fatal: No url found for submodule path ..., actions/checkout#1358 / #788 / #1867, all still open). Every agentic workflow failed at this step, 6/6 smoke workflows included.
Expected
clean_git_credentials.sh removes everything verify_git_credentials.sh checks for, including credentials reached through includeIf.
Possible fix
- In
clean_git_config, for each includeIf.*.path entry whose value matches git-credentials-[0-9a-f-]+\.config$, unset the entry. Delete the referenced file if it is under RUNNER_TEMP. This mirrors checkout's own removeIncludeIfCredentials, and also applies to .git/modules/*/config.
Summary
Since v0.91.0 (#65423, fail-closed credential cleanup), the agent job's Clean credentials step runs
clean_git_credentials.shfollowed byverify_git_credentials.sh. When anyactions/checkoutstep in the job usedpersist-credentials: true, the verify script always fails, and the agent never starts:Root cause
The two scripts read different things:
.git/config. It writeshttp.https://github.com/.extraheaderinto${RUNNER_TEMP}/git-credentials-<uuid>.configand links it from.git/configwithincludeIf.gitdir:<workspace>/.git.path,includeIf.gitdir:<workspace>/.git/worktrees/*.pathand the/github/workspacecontainer equivalents. Submodule configs get the same entries.clean_git_credentials.shedits.git/configwithgit config --file <path> .... It does not follow includes, so it removes thecredential.*andextraheaderentries in that file, but leaves both theincludeIf.*.pathentries and the included credentials file untouched.verify_git_credentials.shreads withgit config --file <path> --includes --list. It follows theincludeIfpath, seeshttp.https://github.com/.extraheader, and exits 1.As a result, the cleanup can never satisfy its own verification when checkout persisted credentials.
Reproduction
persist-credentials: true. A customsteps:checkout, or a compiled checkout changed totrue, both reproduce it.actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1.Observed in a fleet that forces
persist-credentials: trueas a workaround for checkout's submodule cleanup failure (fatal: No url found for submodule path ..., actions/checkout#1358 / #788 / #1867, all still open). Every agentic workflow failed at this step, 6/6 smoke workflows included.Expected
clean_git_credentials.shremoves everythingverify_git_credentials.shchecks for, including credentials reached throughincludeIf.Possible fix
clean_git_config, for eachincludeIf.*.pathentry whose value matchesgit-credentials-[0-9a-f-]+\.config$, unset the entry. Delete the referenced file if it is underRUNNER_TEMP. This mirrors checkout's ownremoveIncludeIfCredentials, and also applies to.git/modules/*/config.