diff --git a/README.md b/README.md index b52aacc..dcf1944 100644 --- a/README.md +++ b/README.md @@ -77,6 +77,13 @@ gitrep-uninstall --keep-env The commit hook automatically signs **all commits** by default (GitHub, GitLab, GitRepublic, etc.). The signature is just text in the commit message and doesn't interfere with git operations. +**Note:** Commit signature events do not include the commit hash tag because: +- The commit-msg hook runs **before** the commit is created, so the hash doesn't exist yet +- Nostr events are **immutable** - once created and signed, they cannot be changed + (changing tags would change the event ID and invalidate the signature) + +Verification matches events to commits by comparing the commit message in the event's `message` tag with the actual commit message. This is secure because the signature proves the message was signed by the author. + To only sign GitRepublic repositories (skip GitHub/GitLab): ```bash diff --git a/nostr/commit-signatures.jsonl b/nostr/commit-signatures.jsonl index d2dbcd3..39e002f 100644 --- a/nostr/commit-signatures.jsonl +++ b/nostr/commit-signatures.jsonl @@ -1,3 +1,4 @@ {"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1772009088,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","Sync from gitrepublic-web monorepo - 2026-02-25 09:44:48"]],"content":"Signed commit: Sync from gitrepublic-web monorepo - 2026-02-25 09:44:48","id":"b97b2110557874521f3d7bb16293a1da5e62d78c092a5c0131caef26e8e99d6f","sig":"0158e672a19fdd63c540ba1e6f31ac1a8127d113ce066095ea3e67673a307582733ebcde3d9664bc92ec0a75a8d88c079f6a9129d4c3f174ce9d1fb238881714"} {"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1772009175,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","Sync from gitrepublic-web monorepo - 2026-02-25 09:46:15"]],"content":"Signed commit: Sync from gitrepublic-web monorepo - 2026-02-25 09:46:15","id":"abcfd862456591f5a75ac3a4eec686c8189e0e72a55827840ed81474d6775615","sig":"7654e225ca006b05f4fdfeb18800d3f6c58cd7c42470835ada0b4f259af36feae1084c1da21ce51037145735227383739ab1c23abc2a2e0cb9946525e520a72f"} {"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1772009282,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","Sync from gitrepublic-web monorepo - 2026-02-25 09:48:02"]],"content":"Signed commit: Sync from gitrepublic-web monorepo - 2026-02-25 09:48:02","id":"e01e92e0b585ee1b17be95a6fb9e754b7c76d8195e59c56c04cf887458966735","sig":"de2bc3dbef419fa97c0251202c3202ea5d11116d6974000133d1c2831dc02287620e56679e3fdbad6a2c764749be4a61901a1538f2733ca88969487251399477"} +{"kind":1640,"pubkey":"573634b648634cbad10f2451776089ea21090d9407f715e83c577b4611ae6edc","created_at":1772009424,"tags":[["author","Silberengel","silberengel7@protonmail.com"],["message","Sync from gitrepublic-web monorepo - 2026-02-25 09:50:24"]],"content":"Signed commit: Sync from gitrepublic-web monorepo - 2026-02-25 09:50:24","id":"e037cd91a9495e4a610d6d7d18d7481aab1f84b52fb28b211635157a5a36cbc3","sig":"44bd88f4daad791691cf22c96f376c6e61afc0cc21dd5a91bed1a87f517c7c4391630639a89d3e55f2416f0e46802c2b984f5c513d5d286f5bf8abea463ade53"} diff --git a/scripts/git-commit-msg-hook.js b/scripts/git-commit-msg-hook.js index 6d0b0d5..7f14330 100755 --- a/scripts/git-commit-msg-hook.js +++ b/scripts/git-commit-msg-hook.js @@ -295,8 +295,19 @@ async function signCommitMessage(commitMessageFile) { const timestamp = Math.floor(Date.now() / 1000); // Create a commit signature event template - // Note: We don't have the commit hash yet, so we'll sign without it - // The signature is still valid as it signs the commit message + // + // IMPORTANT: We cannot include the commit hash in the event because: + // 1. The commit-msg hook runs BEFORE the commit is created, so the hash doesn't exist yet + // 2. Nostr events are immutable - once created and signed, they cannot be changed + // (changing tags would change the event ID and invalidate the signature) + // + // The signature is still valid as it proves: + // - The commit message was signed by the author + // - The author's identity (pubkey) + // - The timestamp of signing + // + // Verification can match events to commits by comparing the commit message + // in the event's 'message' tag with the actual commit message. const eventTemplate = { kind: KIND_COMMIT_SIGNATURE, pubkey, @@ -304,6 +315,7 @@ async function signCommitMessage(commitMessageFile) { tags: [ ['author', authorName, authorEmail], ['message', commitMessage] + // Note: 'commit' tag is intentionally omitted - see comment above ], content: `Signed commit: ${commitMessage}` };