feat(claude-code): persistent signing key makes the manifest verifiable#41
Merged
Merged
Conversation
E2E testing showed the signed Agent Manifest could not be verified by anyone:
sign_all minted a fresh keypair per run with generate_ed25519() and discarded
it, and the manifest carried only key_id (a hash of the public key), never the
key itself. The signature was real but unverifiable after the process exited,
contradicting the README's "shareable proof a third party can verify". (TRACE
was unaffected: trace.json embeds cnf.jwk and verifies standalone.)
- Persist one Ed25519 key at ~/.claude/agentrust/signing_key.json, generated
once and reused every run (reconstructed via cryptography from the stored
seed); best-effort owner-only permissions. Records now carry a stable signing
identity instead of a throwaway key.
- Publish the public half beside each record as verification_key.json
({key_id, public_key_b64url}); the private key never leaves the machine.
- README + /trace doc: correct the claim and show the exact manifest
verification recipe (load verification_key.json into trusted_keys).
- gitignore verification_key.json and signing_key.json.
Verified: key is stable across runs; a third party with only verification_key.json
gets VALID / signature_verified True; any tamper (agent_id, artifact hash) or a
wrong key -> MISMATCH. Added 2 crypto-guarded regression tests (importorskip);
15 pass with and without the crypto packages. ruff clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Found while doing a full end-to-end run of the plugin as a new user would (
/manifest+/tracelifecycle in a throwaway home).The gap
The signed Agent Manifest could not be verified by anyone.
sign_allminted a fresh keypair per run withgenerate_ed25519()and discarded it;manifest.jsonstored onlykey_id(a hash of the public key), never the key. The signature was real but unverifiable after the process exited, which contradicts the README's "shareable proof a third party can verify." (TRACE was fine:trace.jsonembedscnf.jwkand verifies standalone.)The fix
~/.claude/agentrust/signing_key.json, generated once and reused every run (reconstructed from the stored seed viacryptography), best-effort owner-only perms. Records now carry a stable signing identity instead of a throwaway key.verification_key.json({key_id, public_key_b64url}) beside the records. The private half never leaves the machine.verification_key.jsonintotrusted_keys);/tracecommand doc updated;.gitignored the new artifacts.Validation
key_id).verification_key.json->OverallResult.VALID,signature_verified True.agent_id/ an artifact hash, or use a wrong key ->MISMATCH,signature_verified False./manifest+/traceE2E still green.importorskip); 15 pass both with and without the crypto packages.ruffclean.Note
Trace records still use a per-run key from
agentrust_trace(self-verifiable viacnf.jwk). Reusing the one persistent identity for TRACE too is a reasonable follow-up but out of scope here. Also flagged separately: the plugin's pytest suite isn't run by CI (validate.ymlonly checksintegration.yamlschemas) — worth wiring up.🤖 Generated with Claude Code