Skip to content

Releases: agentrust-io/trace-registry

trace-verify 0.4.3

Choose a tag to compare

@imran-siddique imran-siddique released this 30 Sep 19:42
7380dd8
  • Duplicate JSON members are refused. The trace-verify CLI parsed the
    claim, proof, receipt and entry files with last-wins json.loads, so a claim
    carrying a member twice verified over one value while a first-wins reader of
    the same file saw the other. It now uses loads_unique at all four parse
    sites and exits 2 with duplicate JSON member name (#104).

trace-verify 0.4.2

Choose a tag to compare

@imran-siddique imran-siddique released this 26 Sep 21:27
4ae8c49

pip install trace-verify==0.4.2

Behaviour changes

  • Key rotation is now refused. trace-verify chain fails a link whose key_id differs from the previous checkpoint's. Each checkpoint names its own key, so a chain that changed signers midway used to verify clean. The chain format has no rotation statement, so a checkpoint signed by a new key is a break, not a continuation: there is no supported way to rotate the checkpoint key and keep a chain verifying. The anchor pipeline also refuses to extend a published chain when its configured signing key is not the one that signed the last checkpoint.
  • trace-verify chain with no checkpoints exits 1 (#88). It exited 0 and, with --json, reported verified: true for input containing no checkpoint. It now prints NOT VERIFIED, and --json reports verified: false, checkpoints: 0, reason: "no_checkpoints".
  • Malformed input fails instead of raising (#94). CheckpointRecord.from_dict raises ValueError for a missing or mistyped member (it raised KeyError or TypeError) and refuses a boolean, float or numeric-string integer. verify_checkpoint_link returns a failure for a non-string root. InclusionProof.from_dict and ConsistencyProof.from_dict raise InvalidArgumentError. A non-string canonicalization_id is an UnknownCanonicalizationError. The CLI exits 2 for a file that is not UTF-8 or is nested too deeply, and chain reports a malformed checkpoint as a failure; both printed tracebacks. Found by the new ClusterFuzzLite targets in .clusterfuzzlite/.

Fixes

  • trace-verify --json prints one JSON document when the signature does not verify. It printed two (#93).
  • trace-verify --entry-url follows a redirect only to an allowlisted https host. The allowlist was checked on the first URL only, and urllib followed any redirect after it (#93).

Registry side (not in the package)

  • The pipeline, the aggregator and tools/anchor.py refuse a claim outside the registry-anchor-v1 section 1 profile: a non-integer number, an integer outside -(2^53-1)..2^53-1, or a duplicate member name. Every claim already anchored is inside the profile (#93).
  • A staged record whose producer is an array or object is rejected by name. It used to abort the scheduled run for every producer. CI now dry-runs staged records (#93).
  • tools/check_append_only.py diffs with --no-renames and fails when the base SHA does not resolve (#93).
  • The aggregator caps request bodies at 4 MiB (413), answers a missing, negative or malformed Content-Length with 400, and answers 400 to a body nested too deeply to parse (#93, #94).
  • tools/capture_witness_receipt.py --registry-entry lifts the mmr_checkpoint out of a registry entry file, with --batch-id for a multi-line file (#78).
  • CI: ruff (#96), per-job write permissions (#95), pipeline runtime dependencies (#89), maintainer approval check (#92).

Full list in CHANGELOG.md.

trace-verify 0.4.1

Choose a tag to compare

@imran-siddique imran-siddique released this 12 Sep 04:50
40729e0

Verifying a claim no longer needs a clone of the registry.

pip install trace-verify

trace-verify \
  --claim your-record.json \
  --proof your-record.proof.json \
  --entry-url https://raw.githubusercontent.com/agentrust-io/trace-registry/main/registry/2026/06/12.ndjson

In 0.4.0, --entry-url fetched the registry entry and stopped there. The producer key still had to be on disk, so a reader without a clone got no registered key for producer '...' and exit 1. The only workaround was --no-verify-signature, which checks inclusion and not authorship: the weaker half of the answer, reached by switching off the stronger half.

The key now comes from the same allowlisted host as the entry. The producers base is derived from the entry URL, and three things keep that from being a hole:

  • the derived URL is re-checked against the host allowlist, so an entry URL on another host cannot smuggle a fetch;
  • the fetched file lands under the exact name the existing loader expects, so the producer-id validation that keeps a crafted id inside the directory still runs;
  • derivation happens only when neither producers option is given and only for --entry-url, so a local --entry makes no network call at all.

--producers-url overrides the derivation. --producers-dir still takes a local directory. The two are mutually exclusive.

The output says when a key came over the wire, as a second line in text and as producer_key_source in --json. A key fetched from a host is a different trust statement from one already on disk, and an unqualified signature valid would blur them.

0.4.0 shipped a README claiming --entry-url was enough on its own. It was not. This is that claim made true rather than withdrawn.

Full notes: CHANGELOG.md

trace-verify 0.4.0

Choose a tag to compare

@imran-siddique imran-siddique released this 12 Sep 04:34
e638f8c

One install now answers all three questions a reader can ask of this registry.

pip install trace-verify

trace-verify --claim C.json --proof P.json --entry E.ndjson   # is my claim anchored?
trace-verify chain E.ndjson [MORE...]                          # does the registry's history hold?

pip install "trace-verify[witness]"
trace-verify receipt --checkpoint CP.json --response POST.json \
  --registry-key HEX --witness-key HEX --expected-log-id ID    # does an outside witness agree?

Chain verification was a Python API with no command, and witness-receipt verification was not in the package at all. Both were reachable only by cloning the repository.

verify_chain_against_entries is new in the package and is the substantive part. It rebuilds the Merkle Mountain Range from the raw entries and compares it to what each checkpoint claims, which is what catches a quiet edit to an already-anchored entry: such an edit leaves every checkpoint record's own math self-consistent, so the chain-consistency check still passes and only the recompute fails. That check previously existed in the repository and nowhere a pip user could reach it.

Compatibility. The inclusion check keeps its bare-flag form, so every invocation written against 0.3.x runs unchanged. Only the literal tokens chain and receipt route. cbor2 and scitt-cose are imported inside the witness verifier rather than at module scope, so import trace_verify still works without a CBOR stack; they arrive through the new witness extra.

--version was wrong before this. 0.3.0 and 0.3.1 both answered --version with 0.1.0. The publish workflow now refuses a release whose tag disagrees with the packaged version, or whose __version__ disagrees with pyproject.toml.

Package metadata. Homepage, Bug Tracker and Changelog point at this repository again, now that it is public. License metadata is Apache-2.0.

Full notes: CHANGELOG.md

trace-verify 0.3.1

Choose a tag to compare

@imran-siddique imran-siddique released this 21 Aug 23:53
23b0898

Metadata-only release. No behaviour change to the verifier.

What this fixes

trace-verify 0.3.0 on PyPI serves [project.urls] pointing at agentrust-io/trace-registry, which is private. Anyone who installed the package and followed its Documentation or Homepage link got a 404.

The URLs were corrected on main in #38, after v0.3.0 was tagged and without a version bump, so PyPI has been serving the stale metadata ever since. There was nothing left to fix in the URLs themselves. The version bump is the fix.

Closes the remaining half of agentrust-io/trace-spec#138, via #43.

After this release

Link Before After
Homepage agentrust-io/trace-registry (private, 404) public trace-spec
Documentation trace-registry/.../docs/anchor-format.md (404) anchor format in trace-spec
Changelog trace-registry/.../CHANGELOG.md (404) public
Bug Tracker trace-spec/issues unchanged

Worth stating plainly, since this package exists to verify that evidence resolves: a published artifact pointing at a repository nobody can reach is the same failure the anchor format rules are written to prevent. It went unnoticed for eleven days.

trace-verify 0.3.0

Choose a tag to compare

@imran-siddique imran-siddique released this 10 Aug 00:38
a5b03c0

The published 0.2.0 verifies non-ASCII records against bytes the producer never signed

canonical_body_bytes built the signature pre-image with json.dumps(sort_keys=True, ensure_ascii=True), while agentrust_trace.sign_record signs through rfc8785.dumps. The two agree on ASCII and diverge everywhere else, so signer and verifier computed different bytes for any record carrying an accented character, a non-Latin script, or an emoji.

old: b'{"note":"café","producer":"acme/1.0.0"}'
new: b'{"note":"caf\xc3\xa9","producer":"acme/1.0.0"}'

The failure mode is rejection, not acceptance

A verifier that reconstructs different bytes fails the signature check. 0.2.0 therefore rejected valid records; it did not accept invalid ones. Nothing was forgeable through this and no advisory is warranted.

It was still wrong in the one function whose entire job is reproducing what a producer signed.

Why 0.3.0 and not 0.2.1

The behaviour changed, not only the bytes. Signature verification now refuses rather than guessing when rfc8785 is unavailable:

pip install "trace-verify[signature]"

Falling back to a canonicalization that only agrees on ASCII is precisely how this defect shipped, so the fallback is gone and the error names what to install.

Scope is one function, deliberately

Four other json.dumps(sort_keys=True, ...) sites in this repository are correct. The anchor leaf is defined as sorted-key JSON by docs/anchor-format.md §1 and must not move. Two canonicalizations at two layers is the trap that document's §0 exists to name, and fixing the wrong one would have created the exact bug it warns about.

Reported externally as agentrust-io/trace-spec#138.

v0.2.0

Choose a tag to compare

@imran-siddique imran-siddique released this 30 Jun 20:08
c0c254d

Security hardening release. trace-verify now verifies claim signatures by default (fail-closed); the registry verifies producer signatures before anchoring; outbound fetches are restricted to an https host allowlist (SSRF mitigation); producer-id path traversal is blocked. BREAKING for scripts that relied on inclusion-only success of trace-verify.