mirror of
https://github.com/anthropics/claude-code-action.git
synced 2026-01-22 22:44:13 +08:00
fix: ensure SSH signing key has trailing newline (#834)
ssh-keygen requires a trailing newline to parse private keys correctly. Without it, git signing fails with the confusing error: 'Couldn't load public key: No such file or directory?' This normalizes the key to always end with a newline before writing.
This commit is contained in:
@@ -82,8 +82,13 @@ export async function setupSshSigning(sshSigningKey: string): Promise<void> {
|
|||||||
const sshDir = join(homedir(), ".ssh");
|
const sshDir = join(homedir(), ".ssh");
|
||||||
await mkdir(sshDir, { recursive: true, mode: 0o700 });
|
await mkdir(sshDir, { recursive: true, mode: 0o700 });
|
||||||
|
|
||||||
|
// Ensure key ends with newline (required for ssh-keygen to parse it)
|
||||||
|
const normalizedKey = sshSigningKey.endsWith("\n")
|
||||||
|
? sshSigningKey
|
||||||
|
: sshSigningKey + "\n";
|
||||||
|
|
||||||
// Write the signing key atomically with secure permissions (600)
|
// Write the signing key atomically with secure permissions (600)
|
||||||
await writeFile(SSH_SIGNING_KEY_PATH, sshSigningKey, { mode: 0o600 });
|
await writeFile(SSH_SIGNING_KEY_PATH, normalizedKey, { mode: 0o600 });
|
||||||
console.log(`✓ SSH signing key written to ${SSH_SIGNING_KEY_PATH}`);
|
console.log(`✓ SSH signing key written to ${SSH_SIGNING_KEY_PATH}`);
|
||||||
|
|
||||||
// Configure git to use SSH signing
|
// Configure git to use SSH signing
|
||||||
|
|||||||
@@ -55,6 +55,47 @@ describe("SSH Signing", () => {
|
|||||||
expect(permissions).toBe(0o600);
|
expect(permissions).toBe(0o600);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("should normalize key to have trailing newline", async () => {
|
||||||
|
// ssh-keygen requires a trailing newline to parse the key
|
||||||
|
const keyWithoutNewline =
|
||||||
|
"-----BEGIN OPENSSH PRIVATE KEY-----\ntest-key-content\n-----END OPENSSH PRIVATE KEY-----";
|
||||||
|
const keyWithNewline = keyWithoutNewline + "\n";
|
||||||
|
|
||||||
|
// Create directory
|
||||||
|
await mkdir(testSshDir, { recursive: true, mode: 0o700 });
|
||||||
|
|
||||||
|
// Normalize the key (same logic as setupSshSigning)
|
||||||
|
const normalizedKey = keyWithoutNewline.endsWith("\n")
|
||||||
|
? keyWithoutNewline
|
||||||
|
: keyWithoutNewline + "\n";
|
||||||
|
|
||||||
|
await writeFile(testKeyPath, normalizedKey, { mode: 0o600 });
|
||||||
|
|
||||||
|
// Verify the written key ends with newline
|
||||||
|
const keyContent = await readFile(testKeyPath, "utf-8");
|
||||||
|
expect(keyContent).toBe(keyWithNewline);
|
||||||
|
expect(keyContent.endsWith("\n")).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should not add extra newline if key already has one", async () => {
|
||||||
|
const keyWithNewline =
|
||||||
|
"-----BEGIN OPENSSH PRIVATE KEY-----\ntest-key-content\n-----END OPENSSH PRIVATE KEY-----\n";
|
||||||
|
|
||||||
|
await mkdir(testSshDir, { recursive: true, mode: 0o700 });
|
||||||
|
|
||||||
|
// Normalize the key (same logic as setupSshSigning)
|
||||||
|
const normalizedKey = keyWithNewline.endsWith("\n")
|
||||||
|
? keyWithNewline
|
||||||
|
: keyWithNewline + "\n";
|
||||||
|
|
||||||
|
await writeFile(testKeyPath, normalizedKey, { mode: 0o600 });
|
||||||
|
|
||||||
|
// Verify no double newline
|
||||||
|
const keyContent = await readFile(testKeyPath, "utf-8");
|
||||||
|
expect(keyContent).toBe(keyWithNewline);
|
||||||
|
expect(keyContent.endsWith("\n\n")).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
test("should create .ssh directory with secure permissions", async () => {
|
test("should create .ssh directory with secure permissions", async () => {
|
||||||
// Clean up first
|
// Clean up first
|
||||||
await rm(testSshDir, { recursive: true, force: true });
|
await rm(testSshDir, { recursive: true, force: true });
|
||||||
|
|||||||
Reference in New Issue
Block a user