crabbox verify checks a signed run receipt produced by crabbox run --attest.
It recomputes the receipt's canonical bytes, verifies the embedded Ed25519
signature, and prints the signer's public key fingerprint, so a reviewer can
confirm a pasted receipt has not been edited after the run once they have
matched the fingerprint through a trusted channel.
crabbox run --attest receipt.json -- go test ./...
crabbox verify receipt.jsonOn success it prints one line and exits 0:
PASS receipt.json signer=sha256:6a5f... trust=self-signed
If any signed field was modified after signing, it prints a failure line and exits 1:
FAIL receipt.json signer=sha256:6a5f... trust=self-signed: signature mismatch
A receipt that cannot be checked at all (unreadable file, invalid JSON,
duplicate JSON keys, a missing or malformed public_key or signature) exits
2 with an error on stderr. Duplicate keys are rejected outright because JSON
parsers disagree on which duplicate wins, which would let an edited receipt
show one value to a reader while the signature still verifies against another.
Schema v1 is the existing successful-run format. It is a flat JSON object.
schema_version, generated_at,
provider, command, exit_code, command_ms, and public_key are always
present; lease_id, slug, run_id, actions_url, and log_sha256 appear
when the run produced them. log_sha256 is the SHA-256 of the combined
stdout and stderr stream as observed by the client during SSH-backed runs.
The signature covers the canonical encoding of every field except signature
itself: the object is re-marshaled as compact JSON with lexicographically
sorted keys, and the Ed25519 signature is computed over those bytes. Because
public_key is inside the signed payload, swapping in a different key also
fails verification.
Schema v2 terminal receipts are emitted for non-zero local runs and stored by the coordinator for brokered terminal runs. They additionally bind the run, lease, slug, raw command digest, final exit code, sync/command/total timing, timestamps, retained log hash, truncation state, full observed stream hash, and signer fingerprint. Their signature input is a fixed length-prefixed field sequence shared by the Go CLI and Worker verifier. Command display text is bounded; unusually long displays are replaced by a marker containing the exact raw-argument digest.
Signing uses a per-user Ed25519 key that crabbox run --attest mints on first
use at <user config dir>/crabbox/attest/id_ed25519.pem (PKCS8 PEM, file mode
0600). Pass --attest-key <path> to crabbox run to sign with an existing
PKCS8 PEM Ed25519 key instead; the override path is never auto-created.
Verification trusts the key embedded in the receipt and reports its
fingerprint. Binding that fingerprint to an identity is out of scope: compare
it out of band with the signer. The trust=self-signed marker is printed on
every verification result so PASS cannot be mistaken for an identity or
execution-provenance check.
crabbox verify proves integrity and possession of the signing key, not
identity or execution provenance. There are no trust roots, no transparency
log, and no coordinator-held keys in this version.