Skip to content

Bureau — Overview

Bureau Verify Guide

pluck bureau verify is the journalist's 60-second path. Hand it any Bureau bundle and the CLI auto-detects the kind from JSON top-level keys, calls the matching offline verifier, and exits non-zero if any check fails. No accounts, no API keys, no Rekor round-trip required for the offline check.

Shell
pluck bureau verify ./bundle.json
# Auto-detected: Dossier
# OK – 14 dots verified
# 0

What the auto-detector reads

Every Bureau bundle declares its shape through top-level keys. The verifier dispatches on a fail-closed match:

Top-level keys presentBundle kindPredicate URI
dossierHash + dotsDossier(composite – dots can carry any program's predicate)
packHash + probesProbePackhttps://pluck.run/Nuclei.PackEntry/v1 (when wrapped)
voteHash + signersQuorumVote(composite – verifies threshold, dedup, revocation)
predicateType = https://pluck.run/Oath.Commitment/v1OathOath.Commitment/v1
predicateType = .../Rotate.KeyRevocation/v1Rotate revokeRotate.KeyRevocation/v1
predicateType = .../Rotate.KeyFreeze/v1Rotate freezeRotate.KeyFreeze/v1
predicateType = .../Rotate.ReWitnessReport/v1Rotate re-witnessRotate.ReWitnessReport/v1
predicateType = .../SbomAi.Entry/v1SBOM-AISbomAi.Entry/v1
predicateType = .../Fingerprint.Model/v1Fingerprint baselineFingerprint.Model/v1
predicateType = .../Fingerprint.Delta/v1Fingerprint deltaFingerprint.Delta/v1
predicateType = .../Mole.Canary/v1Mole canaryMole.Canary/v1
predicateType = .../Mole.MemorizationVerdict/v1Mole verdictMole.MemorizationVerdict/v1
predicateType = .../Whistle.Submission/v1WhistleWhistle.Submission/v1
predicateType = .../EvidencePacket/v1Bounty packetEvidencePacket/v1
predicateType = .../Bounty.Submission/v1Bounty submissionBounty.Submission/v1
predicateType = .../Custody.Bundle/v1CustodyCustody.Bundle/v1

A bundle that matches none of these falls through to a typed unknown-bundle-shape error and exits with code 2.


Per-kind invocations

Dossier

Shell
pluck bureau verify ./openai-gpt-4o.dossier.json
# Walks every TimelineDot signature, recomputes dossierHash,
# rejects on first mismatch. No flags required.

ProbePack

A signed ProbePack requires the author's public key. Pass it out-of-band – verifying against a key the registry served alongside the pack is TOFU and grants the registry total trust (see Operator Duties → Probe-pack supply-chain).

Shell
pluck bureau verify ./canon-honesty-v0.1.json --pubkey ./alice.pub.pem

QuorumVote

Shell
pluck bureau verify ./red-dot-vote.json \
  --identities ./quorum-roster.json \
  --revoked ./revoked-fingerprints.txt

The --identities JSON maps each fingerprint to a public key. --revoked is an optional newline-separated list of compromised fingerprints; signers in the revoked set are excluded from the threshold count.

Oath

Shell
pluck bureau oath verify ./oath.intoto.jsonl
# Validates Ed25519 signature against vendor-published SPKI fingerprint,
# checks expiresAt, refuses signed-but-stale claims.

Rotate – revocation, freeze, re-witness

Shell
# Verify a key revocation envelope
pluck bureau rotate verify-rotation <rekor-uuid>

# Re-witness reports surface daysSinceRevocation alongside ok
pluck bureau verify ./re-witness.intoto.jsonl

SBOM-AI entries

Shell
# By Rekor uuid (online – fetches the entry)
pluck bureau sbom-ai verify <rekor-uuid> --fingerprint <64-hex>

# By saved envelope (offline)
pluck bureau verify ./sbom-entry.intoto.jsonl

Fingerprint – baseline + delta

Shell
pluck bureau verify ./gpt-4o-baseline.intoto.jsonl
pluck bureau verify ./gpt-4o-delta.intoto.jsonl
# Delta classification: stable | minor | major | swap

Mole – canary + verdict

Shell
pluck bureau verify ./canary.intoto.jsonl
# Validates: sealedAt is BEFORE every probe's evaluatedAt,
# operator signed raw 32-byte digest of canonical(canary body).

pluck bureau verify ./memorization-verdict.intoto.jsonl
# Validates: deterministic n-gram + edit-distance score reproduces.

Whistle

Whistle submissions are signed as raw 32-byte digests by an ephemeral anon key – they are NOT wrapped in a DSSE/in-toto attestation envelope, so cosign's verify-attestation cannot consume them. Use the Pluck-specific verifier:

Shell
pluck bureau whistle verify-submission <rekor-uuid>
# Reads submission body from Rekor, recomputes canonical hash,
# checks anon-key signature.

DSSE wrapping (and cosign compatibility) is on the roadmap.

Bounty – observation packet + submission

Shell
pluck bureau verify ./evidence-packet.intoto.jsonl
pluck bureau verify ./bounty-submission.intoto.jsonl

EvidencePacket/v1 carries a markdown body suitable for direct platform submission. Verifiers walk the embedded Rekor uuid + cosign verify command independently – the bureau plays no role beyond hashing.

Custody

Shell
pluck bureau custody verify ./capture-bundle.json
# Exit 0 when FRE 902(13) compliant.
# Exit non-zero with result.reasons[] mapping each broken check to a
# legal-admissibility argument.

Custody bundles produced without WebAuthn binding emit fre902Compliant: false with a clear reason citing the Daubert reliability standard. WebAuthn binding is on the roadmap.


Exit codes

CodeMeaning
0Every signature verifies, every cross-reference resolves, every bound is honored.
1At least one check failed. The verifier prints every broken check before exiting.
2Usage error – missing flags, unreadable file, unknown bundle shape, unparseable JSON.

The --json flag emits a machine-readable verification report suitable for CI / SIEM ingestion:

Shell
pluck bureau verify ./bundle.json --json

The JSON shape is stable: { ok: boolean, reason: string, checks: [...], summary: string }. Use it to gate releases, tag artifacts in pipelines, or wire alerts in your SIEM.


Sample outputs

Clean dossier

Auto-detected: Dossier
program       dragnet
subject       openai/gpt-4o
dots          14 (12 green, 2 red)
hash          a1b2c3...
signed by     b4d5e6... (verified)
OK

Tampered dossier

Auto-detected: Dossier
hash         expected a1b2c3..., got x9y8z7...
reason       dossier-hash-mismatch
FAIL
exit 1

Unsigned probe-pack

Auto-detected: ProbePack
reason       pack-signature-missing
FAIL
exit 1

Quorum below threshold

Auto-detected: QuorumVote
threshold    3-of-5
signed       2 (after revocation dedup)
reason       below-threshold
FAIL
exit 1

When to verify online

pluck bureau verify against a saved envelope is offline – it never touches the network. Three cases require an online round-trip:

  • Rekor inclusion proof. A signed envelope alone proves the operator authored it; an inclusion proof proves Rekor accepted it. pluck bureau dragnet verify --check-inclusion <uuid> runs the RFC 6962 walker against the live Rekor instance.
  • SBOM-AI registry lookup. Cross-checking a probe-pack's SBOM dependency requires fetching the SBOM entry. pluck bureau sbom-ai verify <rekor-uuid>.
  • Vendor Oath fetch. Pulling the live /.well-known/pluck-oath.json to confirm a current claim. pluck bureau oath fetch <vendor>.

For everything else – including reproducing a journalist's claim from a saved bundle – the offline path is the canonical one.


Verifying without Pluck

Every Bureau signature is Ed25519 PureEdDSA over the raw 32-byte digest of canonicalStringify(body). That matches the wire shape cosign / sigstore-go / sigstore-python expect. If a third party wants to confirm a Bureau claim without installing Pluck:

Shell
# Use cosign directly against a saved envelope
cosign verify-attestation \
  --key alice.pub.pem \
  --type "https://pluck.run/SbomAi.Entry/v1" \
  ./sbom-entry.intoto.jsonl

# Or pull the entry from Rekor by uuid
curl https://rekor.sigstore.dev/api/v1/log/entries/<uuid>

The bureau-specific bounds (probe-pack body ≤ 256 KiB, dossier ≤ 100k dots, etc.) are NOT enforced by cosign – those are caller-side gates the Pluck verifier adds. For maximum rigor, pair cosign verify-attestation with a follow-up pluck bureau verify on the same bundle.


What's next

Edit this page on GitHub
Previous
Foundations

Ready to build?

Install Pluck and follow the Quick Start guide to wire MCP-first data pipelines into your agents and fleets in minutes.

Get started →