Skip to content

Commit 0cbbd69

Browse files
committed
fix: use remote URL token embedding for git push auth
The extraheader-only approach introduced in 7e92e5b doesn't work with actions/checkout@v6 which no longer persists credentials by default. Switch withGitToken to embed the token in the remote URL instead, matching the approach that was previously working in pushWithToken.
1 parent 84413fc commit 0cbbd69

1 file changed

Lines changed: 15 additions & 12 deletions

File tree

packages/bumpy/src/core/git.ts

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,9 @@ export function pushWithTags(opts?: { cwd?: string }): void {
2020
* Temporarily configure git credentials using BUMPY_GH_TOKEN (or GH_TOKEN),
2121
* execute a callback, then restore the original config.
2222
*
23-
* Uses the http.extraheader approach (same as actions/checkout) rather than
24-
* embedding tokens in the remote URL, because extraheader takes priority over
25-
* any credential manager that may be installed on the runner.
26-
*
27-
* Also clears any existing credential config set by actions/checkout (extraheader
28-
* or includeIf entries) so our token is used instead of the default GITHUB_TOKEN.
23+
* Embeds the token in the remote URL and clears any existing credential config
24+
* set by actions/checkout (extraheader or includeIf entries) so our token is
25+
* used instead of the default GITHUB_TOKEN.
2926
*/
3027
export function withGitToken(cwd: string | undefined, fn: () => void): void {
3128
const token = process.env.BUMPY_GH_TOKEN || process.env.GH_TOKEN;
@@ -37,8 +34,6 @@ export function withGitToken(cwd: string | undefined, fn: () => void): void {
3734
}
3835

3936
const extraHeaderKey = `http.${server}/.extraheader`;
40-
// Authorization: bearer works for both GitHub PATs and GITHUB_TOKEN
41-
const authHeader = `Authorization: bearer ${token}`;
4237

4338
// Save and clear any existing credential config set by actions/checkout:
4439
// 1. Direct http.<server>/.extraheader in local config
@@ -56,15 +51,21 @@ export function withGitToken(cwd: string | undefined, fn: () => void): void {
5651
}
5752
}
5853

54+
// Rewrite the remote URL to embed the token — this is the most reliable
55+
// auth method as it bypasses all credential helpers and extraheader issues
56+
const originalUrl = tryRunArgs(['git', 'remote', 'get-url', 'origin'], { cwd });
57+
const authedUrl = originalUrl ? originalUrl.replace(/^https:\/\//, `https://x-access-token:${token}@`) : null;
58+
5959
try {
6060
if (savedHeader) {
6161
runArgs(['git', 'config', '--local', '--unset-all', extraHeaderKey], { cwd });
6262
}
6363
for (const entry of savedIncludeIfs) {
6464
tryRunArgs(['git', 'config', '--local', '--unset', entry.key], { cwd });
6565
}
66-
// Set our token as the Authorization header — this takes priority over credential managers
67-
runArgs(['git', 'config', '--local', extraHeaderKey, authHeader], { cwd });
66+
if (authedUrl) {
67+
runArgs(['git', 'remote', 'set-url', 'origin', authedUrl], { cwd });
68+
}
6869
try {
6970
fn();
7071
} catch (err) {
@@ -73,8 +74,10 @@ export function withGitToken(cwd: string | undefined, fn: () => void): void {
7374
throw new Error(msg.replaceAll(token, '***'));
7475
}
7576
} finally {
76-
// Remove our injected header
77-
tryRunArgs(['git', 'config', '--local', '--unset-all', extraHeaderKey], { cwd });
77+
// Restore original remote URL
78+
if (originalUrl) {
79+
runArgs(['git', 'remote', 'set-url', 'origin', originalUrl], { cwd });
80+
}
7881
// Restore previous credential config
7982
if (savedHeader) {
8083
runArgs(['git', 'config', '--local', extraHeaderKey, savedHeader], { cwd });

0 commit comments

Comments
 (0)