fix(git-config): neutralize checkout credential in include-based config (#1526)

configureGitAuth() removed the actions/checkout auth header with
`git config --unset-all http.<server>/.extraheader`, which only edits the
repo-local config. Since actions/checkout v6.0.0 (backported to v5.0.1 and
v4.3.1) the header is written to a separate file under RUNNER_TEMP and
pulled in via include.path, so --unset-all on the local config is a no-op:
the code logged "No existing authentication headers to remove" while the
checkout credential (usually the workflow GITHUB_TOKEN) stayed usable by
git for the rest of the job.

Also clear the header from every included file, so it is neutralized under
both the pre-v6 (local) and v6+ (include) layouts. Includes that do not
define the header are left untouched.

Fixes #1510
This commit is contained in:
Tem Revil
2026-08-19 17:23:23 -07:00
committed by GitHub
parent e2a4b761cd
commit cff8d3c8f0
+37 -4
View File
@@ -56,6 +56,16 @@ export async function configureGitAuth(
* action's own token instead (a credential helper when non-write users are
* allowed, otherwise the origin URL). This applies to every mode, including API
* commit signing where no other git configuration is needed.
*
* actions/checkout < v6 stored the header directly in the repo-local config,
* where `git config --unset-all` removes it. Since v6.0.0 (backported to
* v5.0.1 and v4.3.1) the header is written to a separate file under
* RUNNER_TEMP that the repo config pulls in via `include.path`; `--unset-all`
* on the local config cannot touch an include-provided value, so the removal
* was a silent no-op and the checkout credential (typically the workflow
* GITHUB_TOKEN) stayed usable by git for the rest of the job. Clear the
* header from the local config AND from every included file so it can no
* longer authenticate while Claude runs.
*/
export async function replaceCheckoutCredentials(
githubToken: string,
@@ -65,12 +75,35 @@ export async function replaceCheckoutCredentials(
// Remove the authorization header that actions/checkout sets
console.log("Removing existing git authentication headers...");
const extraheaderKey = `http.${GITHUB_SERVER_URL}/.extraheader`;
let removedHeader = false;
try {
await $`git config --unset-all http.${GITHUB_SERVER_URL}/.extraheader`;
console.log("✓ Removed existing authentication headers");
} catch (e) {
console.log("No existing authentication headers to remove");
await $`git config --unset-all ${extraheaderKey}`;
removedHeader = true;
} catch {
// No extraheader in the local config (expected on the v6+ include layout).
}
try {
const includePaths =
await $`git config --local --get-all include.path`.text();
for (const includePath of includePaths.split("\n")) {
const path = includePath.trim();
if (!path) continue;
try {
await $`git config --file ${path} --unset-all ${extraheaderKey}`;
removedHeader = true;
} catch {
// This include does not define the header; leave it untouched.
}
}
} catch {
// No include.path entries in the local config.
}
console.log(
removedHeader
? "✓ Removed existing authentication headers"
: "No existing authentication headers to remove",
);
if (process.env.ALLOWED_NON_WRITE_USERS) {
// When processing content from non-write users, use a credential helper