Skip to content

feat: add a verify command for signed trust manifests - #67

Merged
muscariello merged 5 commits into
fix/cosign-tlog-opt-infrom
feat/verify-command
Nov 6, 2026
Merged

muscariello merged 5 commits into
fix/cosign-tlog-opt-infrom
feat/verify-command

Conversation

@muscariello

@muscariello muscariello commented Nov 5, 2026 •

Copy link
Copy Markdown
Member

Stack: #61 ← #65 ← #67 ← #66. Review and merge in that order; each PR shows only its own commits.

Closes #63. Needs Agent-Card/ai-catalog-rust#61.

What ai-catalog verify does

It validates the catalog and runs ai_catalog_validate::verify (from Agent-Card/ai-catalog-rust#61) on the document as served, then prints a report:

  • Per trust manifest: the did-web-v1 signature (signer, protected header, assertionMethod key in the signer's root did:web document, validity period, ES256 detached JWS) and the release binding of its subject to the entry.
  • Per entry: whether the publisher endorsed it and, once a manifest is accepted, whether the artifact matches digest.
  • The catalog's conformance level: Trusted only when an entry has a verified publisher endorsement and none fails.

The checks live in the library. The CLI supplies only what the library leaves to callers:

  • Fetch: HTTPS only, no redirects, 10 s timeout, 16 MiB limit. It refuses IP-literal hosts and private, loopback, link-local, CGNAT, unique-local and IPv4-mapped-private addresses, and pins the checked addresses for the connection.
  • --did-document DID=PATH: serves a local DID document for that DID's https://<domain>/.well-known/did.json. Only root did:web DIDs are accepted.
  • --offline: fetches nothing; checks that would need a fetch come back unverifiable.
  • Reports: text by default, --json for a structured report.

Exit codes: 1 if the catalog is invalid or any check fails; --strict also fails on unverifiable.

History

Later commits give each verify test its own temporary directory (parallel tests could share a time-based name) and update the README: validate now reports at most Discoverable, and verify reports Trusted.

The first commit implemented the checks inside the CLI. The second replaces them with the library's verify(), once Agent-Card/ai-catalog-rust#61 turned out to provide the same checks, so they live in one place.

Dependencies

ai_catalog_validate::verify shipped in ai-catalog-rust 0.4.0, and #61 here is bumped to it, so this builds against released crates and CI passes.

Testing

Tested against the released 0.4.0 crates.

  • Command-level tests (generated keys, inline data, DID document supplied locally):
    • a valid publisher signature gives conformance: trusted and exits 0;
    • a tampered claim fails the signature check and exits 1;
    • offline without a DID document is unverifiable: exit 0, or exit 1 with --strict;
    • the JSON report carries the outcomes;
    • a non-root --did-document DID is rejected.
  • Fetch tests: DID-to-URL mapping, overrides and offline mode, non-https and IP-literal URLs refused, private and local addresses disallowed.
  • Checks: cargo test passes (67 + 37); cargo clippy --all-targets --all-features -- -D warnings and cargo fmt --check are clean.

`ai-catalog verify` checks each trust manifest of a catalog: the release
binding to its entry, the signature object and its validity period, and
the detached ES256 JWS under the did-web-v1 profile, resolving the
signer's root did:web document with safe fetching. It reports publisher
authority for urn:air entries and checks inline data against the entry
digest.

`--did-document DID=PATH` and `--offline` allow verification without
network access; `--strict` treats inconclusive results as failures.

Closes #63

Signed-off-by: Luca Muscariello <muscariello@ieee.org>
The did-web-v1 checks now live in ai-catalog-validate (see
Agent-Card/ai-catalog-rust#61). Drop the CLI's own implementation and
keep only what the library leaves to callers: a Fetch that follows the
safe-fetching rules, with --did-document overrides and --offline, and
the text and JSON reports.

Refs #63

Signed-off-by: Luca Muscariello <muscariello@ieee.org>
Tests run in parallel, and time-based directory names could collide, so
one test removed another's DID document.

Signed-off-by: Luca Muscariello <muscariello@ieee.org>
Since ai-catalog-validate 0.4.0, structural validation reports at most
Discoverable; only verification reports Trusted.

Signed-off-by: Luca Muscariello <muscariello@ieee.org>
@muscariello
muscariello marked this pull request as ready for review November 5, 2026 18:44
@muscariello
muscariello requested a review from a team as a code owner November 5, 2026 18:44
@muscariello
muscariello added this pull request to stack #68 November 5, 2026 18:48
Comment thread src/verify.rs Fixed
msardara
msardara previously approved these changes Nov 5, 2026
Move the scheme and host checks into `checked_target`, which returns the
parsed https URL that `fetch` then requests, and test it directly. The
refusal test no longer passes an http URL into `fetch`, which CodeQL
reported as a request over HTTP (rust/non-https-url).

Refs #63

Signed-off-by: Luca Muscariello <muscariello@ieee.org>
@muscariello
muscariello merged commit ba71df5 into main Nov 6, 2026
6 checks passed
@muscariello
muscariello deleted the feat/verify-command branch November 6, 2026 08:24
@github-actions github-actions Bot mentioned this pull request Oct 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: add an ai-catalog verify command

4 participants