mirror of
https://github.com/anthropics/claude-code-action.git
synced 2026-01-22 22:44:13 +08:00
feat: add ssh_signing_key input for SSH commit signing (#784)
* feat: add ssh_signing_key input for SSH commit signing Add a new ssh_signing_key input that allows passing an SSH signing key for commit signing, as an alternative to the existing use_commit_signing (which uses GitHub API-based commits). When ssh_signing_key is provided: - Git is configured to use SSH signing (gpg.format=ssh, commit.gpgsign=true) - The key is written to ~/.ssh/claude_signing_key with 0600 permissions - Git CLI commands are used (not MCP file ops) - The key is cleaned up in a post step for security Behavior matrix: | ssh_signing_key | use_commit_signing | Result | |-----------------|-------------------|--------| | not set | false | Regular git, no signing | | not set | true | GitHub API (MCP), verified commits | | set | false | Git CLI with SSH signing | | set | true | Git CLI with SSH signing (ssh_signing_key takes precedence) * docs: add SSH signing key documentation - Update security.md with detailed setup instructions for both signing options - Explain that ssh_signing_key enables full git CLI operations (rebasing, etc.) - Add ssh_signing_key to inputs table in usage.md - Update bot_id/bot_name descriptions to note they're needed for verified commits * fix: address security review feedback for SSH signing - Write SSH key atomically with mode 0o600 (fixes TOCTOU race condition) - Create .ssh directory with mode 0o700 (SSH best practices) - Add input validation for SSH key format - Remove unused chmod import - Add tests for validation logic
This commit is contained in:
@@ -6,9 +6,14 @@
|
||||
*/
|
||||
|
||||
import { $ } from "bun";
|
||||
import { mkdir, writeFile, rm } from "fs/promises";
|
||||
import { join } from "path";
|
||||
import { homedir } from "os";
|
||||
import type { GitHubContext } from "../context";
|
||||
import { GITHUB_SERVER_URL } from "../api/config";
|
||||
|
||||
const SSH_SIGNING_KEY_PATH = join(homedir(), ".ssh", "claude_signing_key");
|
||||
|
||||
type GitUser = {
|
||||
login: string;
|
||||
id: number;
|
||||
@@ -54,3 +59,50 @@ export async function configureGitAuth(
|
||||
|
||||
console.log("Git authentication configured successfully");
|
||||
}
|
||||
|
||||
/**
|
||||
* Configure git to use SSH signing for commits
|
||||
* This is an alternative to GitHub API-based commit signing (use_commit_signing)
|
||||
*/
|
||||
export async function setupSshSigning(sshSigningKey: string): Promise<void> {
|
||||
console.log("Configuring SSH signing for commits...");
|
||||
|
||||
// Validate SSH key format
|
||||
if (!sshSigningKey.trim()) {
|
||||
throw new Error("SSH signing key cannot be empty");
|
||||
}
|
||||
if (
|
||||
!sshSigningKey.includes("BEGIN") ||
|
||||
!sshSigningKey.includes("PRIVATE KEY")
|
||||
) {
|
||||
throw new Error("Invalid SSH private key format");
|
||||
}
|
||||
|
||||
// Create .ssh directory with secure permissions (700)
|
||||
const sshDir = join(homedir(), ".ssh");
|
||||
await mkdir(sshDir, { recursive: true, mode: 0o700 });
|
||||
|
||||
// Write the signing key atomically with secure permissions (600)
|
||||
await writeFile(SSH_SIGNING_KEY_PATH, sshSigningKey, { mode: 0o600 });
|
||||
console.log(`✓ SSH signing key written to ${SSH_SIGNING_KEY_PATH}`);
|
||||
|
||||
// Configure git to use SSH signing
|
||||
await $`git config gpg.format ssh`;
|
||||
await $`git config user.signingkey ${SSH_SIGNING_KEY_PATH}`;
|
||||
await $`git config commit.gpgsign true`;
|
||||
|
||||
console.log("✓ Git configured to use SSH signing for commits");
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up the SSH signing key file
|
||||
* Should be called in the post step for security
|
||||
*/
|
||||
export async function cleanupSshSigning(): Promise<void> {
|
||||
try {
|
||||
await rm(SSH_SIGNING_KEY_PATH, { force: true });
|
||||
console.log("✓ SSH signing key cleaned up");
|
||||
} catch (error) {
|
||||
console.log("No SSH signing key to clean up");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user