diff --git a/packages/cli/src/context/core/git-env.ts b/packages/cli/src/context/core/git-env.ts index 645a29cc..0bb7bf74 100644 --- a/packages/cli/src/context/core/git-env.ts +++ b/packages/cli/src/context/core/git-env.ts @@ -31,6 +31,10 @@ function sanitizedGitEnv(env: NodeJS.ProcessEnv = process.env): NodeJS.ProcessEn * directory is an existing repo ktx did not create and the machine has no configured git * identity (e.g. a fresh Mac with no ~/.gitconfig), without mutating the user's repo config. * Explicit `--author` flags on individual commits still take precedence over GIT_AUTHOR_NAME. + * + * `commit.gpgsign=false` is injected as a per-invocation `-c` override so ktx's commits never + * attempt GPG signing: ktx commits under a synthetic identity that can never own a secret key, so + * a user's `commit.gpgsign=true` would otherwise fail every commit with "No secret key". */ export function createSimpleGit(baseDir: string, identity?: { name: string; email: string }): SimpleGit { const env = sanitizedGitEnv(); @@ -40,5 +44,5 @@ export function createSimpleGit(baseDir: string, identity?: { name: string; emai env.GIT_COMMITTER_NAME = identity.name; env.GIT_COMMITTER_EMAIL = identity.email; } - return simpleGit({ baseDir, unsafe: { allowUnsafeAskPass: true } }).env(env); + return simpleGit({ baseDir, config: ['commit.gpgsign=false'], unsafe: { allowUnsafeAskPass: true } }).env(env); } diff --git a/packages/cli/test/context/core/git.service.init-identity.test.ts b/packages/cli/test/context/core/git.service.init-identity.test.ts index b84b9aba..a1fb2aac 100644 --- a/packages/cli/test/context/core/git.service.init-identity.test.ts +++ b/packages/cli/test/context/core/git.service.init-identity.test.ts @@ -94,4 +94,23 @@ describe('GitService.initialize without a configured git identity', () => { }).trim(); expect(localName).toBe(''); }); + + // Regression for KLO-735: a machine with commit.gpgsign=true makes git try to GPG-sign every + // commit, but ktx commits under a synthetic identity that can never own a secret key, so signing + // fails with "No secret key". ktx commits must succeed regardless of the user's signing config. + it('commits even when the global git config forces gpg signing', async () => { + // Force signing and point gpg at a program that always fails, mirroring a machine whose + // configured signing key does not match ktx's synthetic identity. + await writeFile( + join(homeDir, '.gitconfig'), + '[user]\n\tuseConfigOnly = true\n[commit]\n\tgpgsign = true\n[gpg]\n\tprogram = false\n', + 'utf-8', + ); + + const service = new GitService(coreConfig(repoDir)); + await expect(service.onModuleInit()).resolves.toBeUndefined(); + + const head = await service.revParseHead(); + expect(head).toMatch(/^[0-9a-f]{40}$/); + }); }); diff --git a/packages/cli/test/context/core/git.service.repo-isolation.test.ts b/packages/cli/test/context/core/git.service.repo-isolation.test.ts index 569750c8..07478019 100644 --- a/packages/cli/test/context/core/git.service.repo-isolation.test.ts +++ b/packages/cli/test/context/core/git.service.repo-isolation.test.ts @@ -21,7 +21,11 @@ function coreConfig(configDir: string): KtxCoreConfig { } function git(cwd: string, args: string[]): string { - return execFileSync('git', args, { + // `-c commit.gpgsign=false` keeps fixture commits deterministic regardless of the host's git + // config: a contributor with commit.gpgsign=true would otherwise fail these raw commits under a + // synthetic identity that owns no secret key. + const fixtureArgs = args[0] === 'commit' ? ['-c', 'commit.gpgsign=false', ...args] : args; + return execFileSync('git', fixtureArgs, { cwd, encoding: 'utf-8', env: {