feat(#62): Action Manifest v0 — Ed25519-signed per-action provenance#52
Merged
Conversation
Adds asymmetric authenticity on top of the audit ledger's existing tamper-evidence. The SHA-256 hash chain takes no secret, so anyone with the JSONL can recompute a self-consistent chain; an Ed25519 signature over a canonical, machine-readable manifest lets a third party verify a log offline with only the public key. New `ts_cli::provenance_manifest`: - ManifestSigner (ed25519-dalek; key 0600, generated on first use; signer_key_id = sha256(pubkey)[..16]); pubkey published beside the log. - Default checkpoint signing (one sig over a Merkle root every N entries); opt-in per-action signing (--manifest-per-action). - Canonical sorted-key serializer with reference vectors; claim taxonomy derived deterministically from each AuditEntry (kernel_enforced omitted in v0 to avoid overclaiming). - verify_manifests(): chain integrity + signature authenticity + coverage; one-shot `ts_cli --verify-manifests <log>` exits non-zero on any gap. Wiring: AuditLogger gains an optional signer, recorded after an entry is committed (off the decision path; best-effort, never affects a verdict). Signatures cover the redacted chain bytes only, so crypto-shredding (#61) leaves them valid. Deps: ed25519-dalek 2 (pure-Rust, BSD-3; no ring/aws-lc). cargo-deny licenses/bans/advisories/sources all green. Tests: 7 unit (canonical form, Merkle, checkpoint + per-action verify, tamper, forgery-with-different-key, post-erasure) + end-to-end daemon validation. Docs: README Guarantees row, THREAT_MODEL 12.1, CHANGELOG, ACTION_MANIFEST.md marked as-built. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Closes the cargo-deny advisories gate failure: RUSTSEC-2026-0190 flags an unsoundness in anyhow's Error::downcast_mut() for all versions < 1.0.103 (undefined behavior when downcast_mut is called on an error that had context added via Error::context). Advisory published 2026-06-29; the patched range is >= 1.0.103. Lockfile-only bump. Co-Authored-By: Claude Opus 4.8 <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.
Closes the last net-new capability gap from the independent calibration audit (#62 / M9): linking the runtime decision ledger to a portable, externally-verifiable provenance format.
The gap
The audit ledger is a SHA-256 hash chain — tamper-evident but not authentic. The chain hash takes no secret, so anyone with the JSONL can recompute a fully self-consistent chain; a third party cannot prove a log came from a genuine instance. Every other signature in the tree is HMAC (symmetric), which can't give external verifiability either.
What this adds
An Ed25519 (asymmetric) signature over a canonical, machine-readable manifest — verifiers need only the public key.
ts_cli::provenance_manifest:ManifestSigner(key0600, generated on first use;signer_key_id = sha256(pubkey)[..16]; pubkey published beside the log), canonical sorted-key serializer with reference vectors, Merkle checkpoints, claim taxonomy, verifier.--manifest-per-action.ts_cli --verify-manifests <log>: chain integrity + signature authenticity + coverage; exits non-zero on any gap.AuditLogger, recorded after an entry is committed — off the decision path, best-effort, never affects a verdict.Honesty / scope
kernel_enforcedclaim omitted in v0 (theAuditEntrycarries no per-action kernel-enforcement flag yet — would overclaim). v1 item.Validation
0600.ts_clisuite green;cargo fmt --check+clippy -D warningsclean; cargo-deny licenses/bans/advisories/sources all green withed25519-dalek(pure-Rust, BSD-3; no ring/aws-lc).Deps:
ed25519-dalek = 2. Docs: README Guarantees row 🚧→✅ (opt-in), THREAT_MODEL §12.1, CHANGELOG, ACTION_MANIFEST.md marked as-built.🤖 Generated with Claude Code