qf-verify
Independent, offline verifier for Query Fanout AI
agent audit evidence bundles (.json) and evidence packs (.zip).
It is small and dependency-light (only cryptography; asn1crypto is optional
and needed for RFC 3161 timestamps), so an auditor can read it and run it
without trusting the Query Fanout service that produced the evidence. It makes
no network calls.
Install
pip install "qf-verify[tsa]" # from PyPI, with RFC 3161 timestamp support
pip install ./qf-verify # or from a checkout of the Query Fanout repo
qf-verify --version
Python 3.10 or newer.
Use
# 1. Get the publisher's public keys from a source other than the evidence itself
curl -s "https://<host>/audit/keys" > keys.json # public endpoint, no API key
# 2. Verify an evidence bundle or an evidence pack
curl -H "X-API-Key: $QF_API_KEY" "https://<host>/audit/export?run_id=r1" > bundle.json
qf-verify bundle.json --trusted-keys-file keys.json
curl -H "X-API-Key: $QF_API_KEY" "https://<host>/audit/evidence-pack?run_id=r1" -o pack.zip
qf-verify pack.zip --trusted-keys-file keys.json
# 3. Also check who issued the RFC 3161 timestamps: pass the timestamp
# authority's CA certificate, downloaded from the authority itself
curl -s https://freetsa.org/files/cacert.pem > freetsa-ca.pem
qf-verify pack.zip --trusted-keys-file keys.json --tsa-ca freetsa-ca.pem
Exit codes: 0 verified, 1 verification failed, 2 unreadable input.
Add --json for machine-readable output (it includes a timestamps list).
| Option | Meaning |
|---|---|
--trusted-keys-file FILE |
Ed25519 keys from /audit/keys (or query-fanout-audit-admin keys) |
--trusted-key [ID=]BASE64 |
pin a single Ed25519 public key (repeatable) |
--tsa-ca FILE |
trusted TSA CA certificate(s), PEM bundle or DER (repeatable) |
--pin-tsa-cert SHA256 |
accept only a TSA signing certificate with this fingerprint (repeatable) |
--no-anchors |
skip timestamp checks |
--allow-unsigned |
downgrade missing signatures to warnings |
--json, -q |
machine-readable / quiet output |
What it checks
See docs/audit-schema.md in the Query Fanout repository for the format.
| Check | Catches |
|---|---|
| Record hash (SHA-256 over RFC 8785 canonical header) | edited metadata |
| Payload hash | edited query/sources/decision |
| Ed25519 record + checkpoint + bundle signatures | forged or re-hashed records |
| Merkle inclusion proof vs signed tree head | records not in the log, inserted records |
| Consistency proofs between checkpoints | history rewritten after a checkpoint |
| Manifest + hash-chain links | deleted, inserted or reordered records |
| Retention tombstones | payloads removed without a signed retention event |
| RFC 3161 timestamp tokens on the checkpoint and earlier checkpoints | backdated checkpoints; reported as "records 1–N existed no later than T" |
--tsa-ca: TSA certificate chain (at the timestamp's time), timeStamping EKU, ESS signing-certificate binding |
timestamps from an authority you don't trust |
| Pack: signed manifest with per-file SHA-256 | files edited, added, removed or swapped inside the zip |
| Pack: cross-checks | records.jsonl / checkpoint.json / anchors.json / public-keys.json disagreeing with the signed bundle |
Packs are read in memory and never extracted. Names containing paths, duplicate entries, and oversized archives are rejected.
Pin keys (--trusted-key / --trusted-keys-file) obtained out of band; without
pinning, the verifier trusts the keys embedded in the bundle and says so. In the
same way, without --tsa-ca or --pin-tsa-cert a timestamp's signature is
checked but the identity of the authority is only reported, with a warning.
Limits: certificate revocation (CRL/OCSP) is not checked, because the verifier works offline. Chains are evaluated at the timestamp's generation time.
Changelog
- 0.3.0:
--tsa-cachain validation, timestamps on earlier checkpoints,anchors.jsonin packs,--version, keys file may be a plain list, PyPI metadata. - 0.2.0: evidence packs (
.zip). - 0.1.0: evidence bundles.
License
Apache License 2.0, see LICENSE.
Metadata
Release files for qf-verify 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| qf_verify-0.3.0.tar.gz | 22.8 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| qf_verify-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 49.6 kB
Release files / qf_verify-0.3.0.tar.gz
| Download URL | qf_verify-0.3.0.tar.gz |
|---|---|
| Size | 22.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
75f0e8e69be6570c89136e885c907534af6b4cbc136c5da6a5536eba931f9c09
|
|
BLAKE2b-256 checksum How to use checksums |
27dd0df1172403fe04df648de82c75c4e76b207d918031a26eea2b38c97ba0c5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.5
|
Release files / qf_verify-0.3.0-py3-none-any.whl
| Download URL | qf_verify-0.3.0-py3-none-any.whl |
|---|---|
| Size | 26.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
e586c0e027f25ce007a63bbe57c5b53c38296abdb34c37fdb766e8da554b105c
|
|
BLAKE2b-256 checksum How to use checksums |
6266a0b8a33805a2b8fbb139fe27240dd8fa7eac5185be42368a9377d3072568
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.5
|
Security for qf-verify 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.