Skip to content

Bind a directive to an authorised signer, not to a signature - #642

Merged
MongLong0214 merged 3 commits into
mainfrom
fix-597-signer-authority
Aug 14, 2026
Merged

Bind a directive to an authorised signer, not to a signature#642
MongLong0214 merged 3 commits into
mainfrom
fix-597-signer-authority

Conversation

@MongLong0214

Copy link
Copy Markdown
Owner

Summary

Closes #597.

A signature proves that a key the verifier trusts signed the commit. It does not prove that the
signer has authority over this repository. Signature mode treated the two as the same thing: a
valid signature plus an author header matching a configured string was enough to emit directive.

Repository policy now names the signer fingerprints it authorises, and Git's own reported signer is
compared against that list.

What changed

  • a repository-local allowlist of approved signer fingerprints
  • the grade is decided from the fingerprint Git reports (%GF), not from the author header
  • absent, empty, and unreadable policy all authorise nobody — a missing list is not permission
  • the default author-string mode is unchanged and still documented as non-authenticated

Test plan

Real signatures throughout. The fixture generates throwaway GPG keys and signs commits with them;
nothing here asserts against a mocked verification result.

  • a valid signature by an unapproved key grades claim
  • a forged author header on a commit signed by an unapproved key grades claim
  • an approved signer grades directive on both the commit and the notes route
  • the approved commit returns the same grade on every core record route
  • 5 cases in signer-authority, 380 across grade, trusted-authors, query and guard
  • npx tsc --noEmit
  • canonical build and npm run artifact:verify

Negative controls. Removing the authorisation check makes both refusal cases grade directive
where they must grade claim; restoring it returns them to claim. Both pairs pasted below in the
commit record.

What this does not claim

No PKI, no hosted identity service, no automatic key enrolment — those are ruled out by the issue's
own non-goals.

Signatures are not required by default. Making them mandatory would demote every existing
repository's records on upgrade, which an existing decision record on this repository rules out.

An approved signature still establishes only that an authorised key signed this commit. It does not
establish that the record's content is true, and the product does not say otherwise.

A verified Git signature proves that a key trusted by this verifier signed a commit. It does not prove that the key is authorized to direct this repository.

Signature mode identifies a signer by Git's exact %GF fingerprint and authorizes it through repeatable repository-local commitlore.trustedSigner values. Local config keeps authority outside commit-controlled content and follows the existing trusted-author policy. Signature mode remains opt-in; an absent, empty, or unreadable signer allowlist authorizes nobody, while default author-string mode remains unchanged.

Ruled-out: signer email or author header matching | either is commit-controlled metadata and does not bind the verified key to repository authority
Blast: system
Undo: easy
Certainty: firm
Verified: npx tsc --noEmit
Verified: npx vitest run test/grade.test.ts test/trusted-authors.test.ts test/query.test.ts test/guard.test.ts
Verified: npx vitest run test/inject.test.ts test/before-change.test.ts test/mcp.test.ts
Verified: npx vitest run test/signer-authority.test.ts
Verified: docker run --rm --platform linux/amd64 -v /tmp/wt-597:/w -w /w node:24-bookworm sh -c "npm ci && npm run build"
Verified: npm ci
Verified: find dist -type f | wc -l = 274
Record-Id: r-signer597
Provenance: authored
Merging main brought in the canonical-artifact check, which the macOS-built
dist on this branch does not satisfy. Rebuilt with the documented builder and
regenerated the manifest.

Provenance: authored
Record-Id: r-canon597
Verified: docker linux/amd64 npm ci, npm run build, npm run artifact:manifest; artifact:verify reports ae22e89e; 274 files in dist
@github-actions

Copy link
Copy Markdown

CommitLore — record lint

Trailers: clean — 3 commits in origin/main..bc81ced3d668b7537fe1c98d8dea6e910aa8c24d
Active constraints: not read — commitlore: git log --follow accepts exactly one pathspec, so renames are not followed for 64 paths; query one path at a time to follow its rename chain (64 changed paths)

Trailer violations fail this check. Active constraints are informational — they are what the repository already decided, not a verdict on this PR.

@MongLong0214
MongLong0214 merged commit 3dc75e7 into main Aug 14, 2026
12 checks passed
@MongLong0214
MongLong0214 deleted the fix-597-signer-authority branch August 14, 2026 04:11
MongLong0214 added a commit that referenced this pull request Aug 14, 2026
#642(#597)가 requireSignedDirective 모드에 trustedSigner allowlist를 추가했다.
README 4개·docs/cli.md·docs/capture.md·ADR-0005는 새 계약을 담고 있는데
SPEC §7만 옛 계약(Git G 상태만 요구)에 머물러 있었다.

정본이 구현보다 약한 게이트를 서술하면, 스펙만 보고 만든 구현은 CommitLore가
claim으로 등급하는 레코드를 directive로 등급한다. #631이 다루는 경로별 등급
불일치와 같은 종류이며, 여기서는 스펙과 구현 사이에서 벌어진다.

문구는 ADR-0005의 이미 승인된 서술을 옮긴 것이고 새 결정을 담지 않는다.

Limit: SPEC §7은 구현이 실제로 강제하는 것보다 약한 조건을 서술할 수 없다
Ruled-out: README·docs만 고치고 SPEC은 두기 | 정본이 규범이라 독립 구현자는 SPEC을 읽지 README를 읽지 않는다
Record-Id: r-signspec645
Blast: module
Undo: easy
Certainty: firm
X-Claude-Session: https://claude.ai/code/session_01Go54NtZpaoNMRtmYtPLX6R
MongLong0214 added a commit that referenced this pull request Aug 14, 2026
#642(#597)가 requireSignedDirective 모드에 trustedSigner allowlist를 추가했다.
README 4개·docs/cli.md·docs/capture.md·ADR-0005는 새 계약을 담고 있는데
SPEC §7만 옛 계약(Git G 상태만 요구)에 머물러 있었다.

정본이 구현보다 약한 게이트를 서술하면, 스펙만 보고 만든 구현은 CommitLore가
claim으로 등급하는 레코드를 directive로 등급한다. #631이 다루는 경로별 등급
불일치와 같은 종류이며, 여기서는 스펙과 구현 사이에서 벌어진다.

문구는 ADR-0005의 이미 승인된 서술을 옮긴 것이고 새 결정을 담지 않는다.

Limit: SPEC §7은 구현이 실제로 강제하는 것보다 약한 조건을 서술할 수 없다
Ruled-out: README·docs만 고치고 SPEC은 두기 | 정본이 규범이라 독립 구현자는 SPEC을 읽지 README를 읽지 않는다
Record-Id: r-signspec645
Blast: module
Undo: easy
Certainty: firm
X-Claude-Session: https://claude.ai/code/session_01Go54NtZpaoNMRtmYtPLX6R
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

guard and before-change drop the signature-required policy, so a repository that demands signing is served unsigned directives

1 participant