Skip to content

change(ard): drop the trust-manifest signature; publish the catalogue unsigned#123

Open
jdevalk wants to merge 1 commit into
mainfrom
change/drop-ard-signing
Open

change(ard): drop the trust-manifest signature; publish the catalogue unsigned#123
jdevalk wants to merge 1 commit into
mainfrom
change/drop-ard-signing

Conversation

@jdevalk

@jdevalk jdevalk commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Why

The signature could not do the job it existed for, and no amount of tooling around it would have changed that.

What it protected: three static fields — identity, identityType, privacyPolicyUrl.

What verified it: a JWK Set at /.well-known/jwks.jsonon the same origin as the catalogue it vouched for. Anyone able to rewrite ai-catalog.json could rewrite jwks.json in the same breath, substitute their own key, and produce a manifest that verifies perfectly. For a static site the origin is the threat model, so the signature folded to exactly the compromise it was meant to detect.

It also covered host.trustManifest only, not entries — documented as a feature ("entries change without re-signing"). But entries is where the MCP and A2A endpoint URLs live. Redirecting an agent to a hostile endpoint left the signature intact and valid. We were paying to sign the boring part.

Against that, the running cost: an offline key on one machine, a re-sign step on every catalogue edit, a CI check, and a contributor footgun — an outside contributor editing ai-catalog.json cannot re-sign it, and would hit a CI failure they structurally cannot fix.

The AI Catalog spec makes the trust manifest an optional extension, so removing it leaves a valid catalogue. TLS already proves the bytes came from the domain.

Removed

host.trustManifest · public/.well-known/jwks.json · scripts/sign-ard-catalog.mjs · the sign:ard / check:ard npm scripts · the CI step · the jwks entry in the api-catalog Linkset and its _headers block · the bold "re-run npm run sign:ard or the signature breaks" warning in CLAUDE.md.

The .ard-signing-key.json gitignore line stays, now with a comment explaining why: a leftover local key must never become committable.

What replaces it

The reasoning, on the page — which is the point. Under the rule change in #121 we no longer need to ship a signed manifest in order to have a page that discusses signing, so the page now says the useful thing:

A signature is only worth its weight when the verifying key is resolvable independently of the signed document — a DNSSEC-signed record, a key pinned by the verifier out of band, or a JWK Set on infrastructure an origin compromise would not reach. Absent one of those, an unsigned catalogue served over HTTPS makes the same guarantee with none of the machinery.

Plus the unsigned-entries trap, in both Common mistakes and Verification. Nobody else is writing this down, and it's the kind of thing an implementer gets wrong by default because signing feels like security.

Notes

Historical docs (ops/notes/ard-adoption.md, docs/okf-recon.md) get a dated superseded banner rather than a rewrite — they're point-in-time records and falsifying them would be worse than marking them.

Changelog: changed entry on agentic-resource-discovery, updated bumped. This one clearly warrants an entry — the page's guidance genuinely reverses.

Checks

npm run build ✓ · npm run check ✓ (0 errors) · npm run lint ✓ · npm run format:check ✓ · npm run check:skill ✓ · catalogue still parses as valid JSON with 4 entries.

If you ever want signing back

Only one variant is worth the machinery: publish the JWK thumbprint in a DNSSEC-signed TXT record — we already publish DNS-AID records and have a DNSSEC page, so the zone and the precedent both exist — and extend the signature to cover entries. Signing in CI with a repo secret is not a middle ground: it fixes the ergonomics and none of the security.

🤖 Generated with Claude Code

… unsigned

The signature could not do the job it existed for, and no amount of tooling
around it would have changed that.

What it protected: three static fields — `identity`, `identityType`,
`privacyPolicyUrl`. What verified it: a JWK Set at /.well-known/jwks.json, on
the same origin as the catalogue it vouched for. Anyone able to rewrite
ai-catalog.json could rewrite jwks.json in the same breath, substitute their own
key, and produce a manifest that verifies perfectly. For a static site the
origin IS the threat model, so the signature folded to exactly the compromise it
was meant to detect.

It also covered host.trustManifest only, not `entries` — documented as a feature
("entries change without re-signing"), but `entries` is where the MCP and A2A
endpoint URLs live. Redirecting an agent to a hostile endpoint left the
signature intact and valid.

Against that: an offline key on one machine, a re-sign step on every catalogue
edit, a CI check, and a contributor footgun — an outside contributor editing
ai-catalog.json cannot re-sign it and would hit a CI failure they structurally
cannot fix. The AI Catalog spec makes the trust manifest an optional extension,
so removing it leaves a valid catalogue. TLS already proves the bytes came from
the domain.

Removed: host.trustManifest, public/.well-known/jwks.json,
scripts/sign-ard-catalog.mjs, the sign:ard / check:ard npm scripts, the CI step,
the jwks entry in the api-catalog Linkset and its _headers block, and the bold
"re-run sign:ard or the signature breaks" warning in CLAUDE.md. The
.ard-signing-key.json gitignore line stays, with a comment: a leftover local key
must never become committable.

The reasoning is now on the spec page, which is the point. Under the rule change
in #121 we no longer need to ship a signed manifest to have a page that
discusses signing, so the page says the useful thing instead: sign only when the
verifying key is resolvable independently of the signed document — DNSSEC, an
out-of-band pin, or infrastructure an origin compromise would not reach — and
note that a same-origin JWK Set is not one of those. Also flags the unsigned-
`entries` trap, in Common mistakes and in Verification.

Historical notes (ops/notes/ard-adoption.md, docs/okf-recon.md) get a dated
superseded banner rather than a rewrite; they are point-in-time records and
falsifying them would be worse than marking them.

Changelog: `changed` on agentic-resource-discovery. `updated` bumped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 23, 2026

Copy link
Copy Markdown

Deploying specification-website with  Cloudflare Pages  Cloudflare Pages

Latest commit: 6c5f7d7
Status: ✅  Deploy successful!
Preview URL: https://35090129.specification-website.pages.dev
Branch Preview URL: https://change-drop-ard-signing.specification-website.pages.dev

View logs

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.

1 participant