diff --git a/packages/web/server/lib/git/service.js b/packages/web/server/lib/git/service.js index e676b9eb..1f6b80c3 100644 --- a/packages/web/server/lib/git/service.js +++ b/packages/web/server/lib/git/service.js @@ -352,7 +352,7 @@ const buildGitEnv = async () => { return env; }; -const createGit = async (directory, { allowUnsafeSshCommand = false } = {}) => { +const createGit = async (directory, { allowUnsafeSshCommand = false, allowUnsafeCredentialHelper = false } = {}) => { const env = await buildGitEnv(); const spawnOptions = { windowsHide: true }; const binary = getGitBinary(); @@ -360,8 +360,9 @@ const createGit = async (directory, { allowUnsafeSshCommand = false } = {}) => { const unsafe = hasCustomBinary || allowUnsafeSshCommand ? { ...(hasCustomBinary && { allowUnsafeCustomBinary: true }), - ...(allowUnsafeSshCommand && { allowUnsafeSshCommand: true }), - } + ...(allowUnsafeSshCommand && { allowUnsafeSshCommand: true }), + ...(allowUnsafeCredentialHelper && { allowUnsafeCredentialHelper: true }), + } : undefined; // Always pin simple-git to an explicit working directory. Omitting baseDir // makes simple-git use process.cwd(), which breaks when the OpenChamber @@ -2146,7 +2147,7 @@ export async function hasLocalIdentity(directory) { } export async function setLocalIdentity(directory, profile) { - const git = await createGit(directory, { allowUnsafeSshCommand: true }); + const git = await createGit(directory, { allowUnsafeSshCommand: true, allowUnsafeCredentialHelper: true }); try { diff --git a/packages/web/server/lib/git/service.test.js b/packages/web/server/lib/git/service.test.js index 1b742704..db2cc418 100644 --- a/packages/web/server/lib/git/service.test.js +++ b/packages/web/server/lib/git/service.test.js @@ -183,6 +183,41 @@ describe.runIf(canRunGit())('setLocalIdentity', () => { "ssh -i '/tmp/test key' -o IdentitiesOnly=yes" ); }); + + it('configures the stored credential helper for token auth with the targeted simple-git opt-in', async () => { + const { tmpDir } = await createTempRepo(); + + await setLocalIdentity(tmpDir, { + userName: 'Token User', + userEmail: 'token@example.com', + authType: 'token', + host: 'github.com', + }); + + expect(runGit(tmpDir, ['config', '--local', '--get', 'credential.helper']).trim()).toBe('store'); + }); + + it('clears the stored credential helper when switching to SSH auth', async () => { + const { tmpDir } = await createTempRepo(); + + await setLocalIdentity(tmpDir, { + userName: 'Token User', + userEmail: 'token@example.com', + authType: 'token', + host: 'github.com', + }); + await setLocalIdentity(tmpDir, { + userName: 'SSH User', + userEmail: 'ssh@example.com', + authType: 'ssh', + sshKey: '/tmp/test key', + }); + + expect(runGit(tmpDir, ['config', '--local', '--get', 'core.sshCommand']).trim()).toBe( + "ssh -i '/tmp/test key' -o IdentitiesOnly=yes" + ); + expect(() => runGit(tmpDir, ['config', '--local', '--get', 'credential.helper'])).toThrow(); + }); }); // ---------------------------------------------------------------------------