Skip to content

Commit 1e3cbd5

Browse files
committed
fix(github): handle actions/checkout@v6 credential files
actions/checkout@v6 stores git credentials in a separate file in RUNNER_TEMP and references it via includeIf directives in .git/config. This caused duplicate Authorization headers when we set our own credentials, resulting in HTTP 400 errors during git fetch. The fix temporarily hides the checkout credential files by renaming them with a .opencode-bak suffix before configuring our auth, then restores them after for subsequent workflow steps. Inspired by: peter-evans/create-pull-request#4230
1 parent a803cf8 commit 1e3cbd5

1 file changed

Lines changed: 31 additions & 2 deletions

File tree

packages/opencode/src/cli/cmd/github.ts

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,7 @@ export const GithubRunCommand = cmd({
471471
let octoRest: Octokit
472472
let octoGraph: typeof graphql
473473
let gitConfig: string
474+
let hiddenCredentialFiles: string[] = []
474475
let session: { id: string; title: string; version: string }
475476
let shareId: string | undefined
476477
let exitCode = 0
@@ -1002,8 +1003,26 @@ export const GithubRunCommand = cmd({
10021003

10031004
console.log("Configuring git...")
10041005
const config = "http.https://github.com/.extraheader"
1005-
// actions/checkout@v6 no longer stores credentials in .git/config,
1006-
// so this may not exist - use nothrow() to handle gracefully
1006+
1007+
// actions/checkout@v6 stores credentials in a separate file in RUNNER_TEMP and references it via includeIf
1008+
// directives. Temporarily hide these files to prevent duplicate Authorization headers when we set our own
1009+
// credentials. The files will be restored by restoreGitConfig() for subsequent workflow steps.
1010+
const runnerTemp = process.env["RUNNER_TEMP"]
1011+
if (runnerTemp) {
1012+
const { readdir, rename } = await import("node:fs/promises")
1013+
const { join } = await import("node:path")
1014+
const files = await readdir(runnerTemp).catch(() => [] as string[])
1015+
for (const file of files) {
1016+
if (file.startsWith("git-credentials-") && file.endsWith(".config")) {
1017+
const sourcePath = join(runnerTemp, file)
1018+
const backupPath = `${sourcePath}.opencode-bak`
1019+
await rename(sourcePath, backupPath).catch(() => {})
1020+
hiddenCredentialFiles.push(backupPath)
1021+
}
1022+
}
1023+
}
1024+
1025+
// Unset any extraheader that might be in .git/config directly (older checkout versions)
10071026
const ret = await $`git config --local --get ${config}`.nothrow()
10081027
if (ret.exitCode === 0) {
10091028
gitConfig = ret.stdout.toString().trim()
@@ -1018,6 +1037,16 @@ export const GithubRunCommand = cmd({
10181037
}
10191038

10201039
async function restoreGitConfig() {
1040+
// Restore checkout@v6 credential files that were hidden
1041+
if (hiddenCredentialFiles.length > 0) {
1042+
const { rename } = await import("node:fs/promises")
1043+
for (const backupPath of hiddenCredentialFiles) {
1044+
const originalPath = backupPath.replace(/\.opencode-bak$/, "")
1045+
await rename(backupPath, originalPath).catch(() => {})
1046+
}
1047+
hiddenCredentialFiles = []
1048+
}
1049+
10211050
if (gitConfig === undefined) return
10221051
const config = "http.https://github.com/.extraheader"
10231052
await $`git config --local ${config} "${gitConfig}"`

0 commit comments

Comments
 (0)