Pipelock's flight recorder generates Ed25519-signed action receipts -- one per proxied request. Each receipt links to the previous one via a SHA-256 hash chain, forming a tamper-evident log of every security decision. This guide covers how to verify receipts, check chain integrity, and use the cross-implementation conformance suite.
- After an incident: Verify the evidence log to confirm it has not been tampered with. A broken hash chain or invalid signature means evidence was modified after the fact.
- During audit: Provide the verified chain to auditors as signed proof of what pipelock enforced during a session.
- In CI/CD: Run
pipelock verify-receiptagainst evidence files produced by integration tests to confirm the flight recorder is functioning. - Cross-implementation: Use the conformance suite's golden files to verify that a third-party receipt verifier (e.g. Python, TypeScript) agrees with the reference Go implementation.
pipelock verify-receipt receipt.jsonOutput on success:
OK: receipt.json
Action ID: 019...
Action Type: fetch
Verdict: allowed
Target: https://docs.python.org/3/
Transport: fetch
Timestamp: 2026-04-10T14:30:00Z
Signer: 70b991eb...
Chain seq: 42
Chain prev: sha256:a1b2c3d4...
Pin a specific signer key to reject receipts from unknown signers:
pipelock verify-receipt receipt.json --key 70b991eb77816fc4ef0ae6a54d8a4119ddc5a16c9711c332c39e743079f6c63eExit code 0 means valid, exit code 1 means invalid or malformed.
Pass a flight recorder JSONL file to verify the entire hash chain:
pipelock verify-receipt evidence-proxy-0.jsonlOutput on success:
CHAIN VALID: evidence-proxy-0.jsonl
Receipts: 142
Final seq: 141
Root hash: sha256:e5f6a7b8...
Start: 2026-04-10T14:00:00Z
End: 2026-04-10T15:30:00Z
Chain verification checks:
- Every receipt's Ed25519 signature is valid against the signer key.
- All receipts share the same signer key (or match the
--keyargument). chain_seqincrements by exactly 1 from 0 to N-1.- The first receipt has
chain_prev_hash: "genesis". - Each subsequent receipt's
chain_prev_hashequals the SHA-256 hash of the previous receipt's canonical JSON.
If any check fails, the output reports which sequence number broke the chain.
The transcript root is the hash of the final receipt in the chain, serving as a tamper-evident summary of the entire session:
pipelock transcript-root evidence-proxy-0.jsonl --key 70b991eb...Transcript Root: evidence-proxy-0.jsonl
Session: proxy
Root hash: sha256:e5f6a7b8...
Receipt count: 142
Final seq: 141
Start: 2026-04-10T14:00:00Z
End: 2026-04-10T15:30:00Z
The --key flag is required for transcript roots: the root is only
meaningful if every receipt in the chain was verified against a trusted key.
When verifying a file-based evidence capture, transcript-root derives the
SessionID from the first entry in the file rather than the --session
flag (which still controls the session ID for directory-based chain scans).
An empty evidence file — zero receipts — fails with a non-zero exit code
rather than silently printing a valid-looking root, so scripts can trust
an exit-0 status to mean "receipts were present and the chain verified."
Each receipt contains:
- action_record: The security decision (action ID, verdict, target, transport, policy hash, chain sequence, chain previous hash).
- signature:
ed25519:prefix + hex-encoded Ed25519 signature overSHA-256(canonical JSON of action_record). - signer_key: Hex-encoded Ed25519 public key of the signer.
The chain links receipts via chain_prev_hash:
Receipt 0: chain_seq=0, chain_prev_hash="genesis"
Receipt 1: chain_seq=1, chain_prev_hash=sha256(receipt_0)
Receipt 2: chain_seq=2, chain_prev_hash=sha256(receipt_1)
...
Inserting, removing, or modifying any receipt breaks the chain at that point.
When pipelock restarts or rotates the evidence file, the receipt emitter resumes the chain from the last persisted receipt. v2.2.0 hardens the resume path in three ways:
- Tail signature verification: the resume code verifies the Ed25519
signature of the tail receipt before trusting its
chain_seqand chain hash. A tampered or partially-corrupted evidence file fails fast rather than letting the next emitted receipt silently continue from attacker-controlled state. - Atomic resume: the recorder computes the resumed sequence number, previous hash, and first-sequence-in-span into local temporaries and only mutates its internal state after all filesystem reads succeed. A transient read error no longer leaves a half-initialised chain that restarts from genesis.
- uint64 sequence parsing: file ordering during resume uses
strconv.ParseUintso evidence filenames with sequence numbers greater thanmath.MaxInt(or 32-bit builds) order correctly.
These hardenings are transparent to verifiers — the wire format is unchanged. They protect the emitter side from bugs and tampering that would have produced broken or forgeable chains at restart.
The sdk/conformance/ directory contains golden test vectors for any
receipt verifier implementation:
| File | Purpose |
|---|---|
testdata/test-key.json |
Test keypair seed and public key hex |
testdata/valid-single.json |
Single valid receipt, seq 0, genesis prev |
testdata/valid-chain.jsonl |
Five-receipt chain (one JSON per line) |
testdata/invalid-signature.json |
Valid structure with tampered signature |
testdata/broken-chain.jsonl |
Five receipts with a prev_hash break at seq 3 |
The signing key is deterministic (seeded from a known phrase) so the golden files can be regenerated bit-identical:
go test ./sdk/conformance/ -run TestGenerateGoldenFiles -update- Parse
test-key.jsonto get the test public key. - Verify
valid-single.json: signature must pass, action record must parse correctly. - Verify
valid-chain.jsonl: all 5 signatures must pass, chain must be unbroken (seq 0-4, genesis first, prev_hash links valid). - Reject
invalid-signature.json: signature verification must fail. - Reject
broken-chain.jsonl: chain verification must fail at seq 3.
A reference Python verifier is available at pipelock-verify-python.
- Flight recorder guide for configuring evidence logging
- Mediation envelope guide for receipt ID correlation
- Receipt transport coverage for the per-transport emission matrix and error-path receipt coverage
- Configuration reference for all recorder fields