feat: fetch schemas from /protocol/{version}.tgz bundle#41
Merged
Conversation
Replaces ~250 per-file gh api calls with a single CDN fetch + SHA-256 verify. Drops the GH_TOKEN requirement from CI and cuts schema-sync wall time by 20-50x. check-freshness.sh now reads the /protocol/ manifest instead of the GitHub API. Validates VERSION against a semver/latest regex, rejects bundles with path-traversal entries or symlinks, and adds a CI drift check for adcp/types_gen.go. Closes #40 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Picks up adcontextprotocol/adcp#2273 — released tarballs now ship cosign keyless signatures. When .sig/.crt sidecars are present and cosign is installed, verify against the upstream release workflow identity. Falls back to checksum-only trust when sidecars are missing (latest.tgz, pre-signing releases). Set ADCP_STRICT_VERIFY=1 to require signatures (fails closed when sidecars are missing or cosign is unavailable). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fully wires the consumer side of adcontextprotocol/adcp#2273: download.sh now reads signature_verification metadata from the /protocol/ manifest rather than hardcoding the Sigstore identity, and cosign is installed in CI. Released versions (non-"latest") MUST be signed — the script fails closed when sidecars or cosign are missing. latest.tgz remains unsigned by design and falls back to checksum-only trust. Migrates consumers to the new IdentityMatchRequest.identities[] shape introduced upstream: user_token and uid_type moved into an IdentityToken array (maxItems 3 to match TMPX budget). Touches router provider filter, targeting engine primary-token selection, tmpclient wire construction, reference identity agent, and every test call site. targeting/valkeystore also picks up the earlier tmproto.ExposeRequest -> targeting.ExposeRequest move. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Hardcode cosign identity regex and OIDC issuer in download.sh rather than sourcing from the /protocol/ manifest. Manifest-sourced identity is equivalent-trust to origin TLS — an attacker with write access to the origin could swap the regex to match any cert they control. In-tree pinning requires attacker to also compromise the upstream GitHub workflow. - Validate signature certificate is actually PEM before handing to cosign (catches CDN returning 200 with an HTML error body). - rm partial sidecar files on non-200 response codes. - Cap IdentityToken.UserToken length at MaxIDLength (256) to bound request memory; prior validation applied this to other IDs. - Document Identities[0] primary-token behavior on EvaluateIdentity. - identity-agent now calls ValidateIdentityRequest rather than only checking len(Identities) == 0, so the full invariant set (max 3, uid_type non-empty, country format, package limits) is enforced. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #40. Replaces the per-file GitHub API schema sync in
adcp/schemas/download.shwith a single tarball fetch fromhttps://adcontextprotocol.org/protocol/{version}.tgz, SHA-256 verified against the co-located sidecar, with optional Sigstore signature verification on top.gh apicalls → 2 CDN GETs. Schema sync goes from ~30-60s to ~1-2s.GH_TOKENrequired by CI — the bundle is served publicly. Dropped the env var from the CI step.check-freshness.shported to the/protocol/manifest. ForVERSION=latest, compares the pinned bundle's SHA-256 against the upstream sidecar; for pinned releases, diffs the highest released version in the manifest (proper semver sort, not lex)..sig/.crtsidecars are present andcosignis on PATH, verify against the upstream release workflow identity (.github/workflows/release.yml) and OIDC issuer. Falls back to checksum-only trust when sidecars are missing (expected forlatest.tgzand pre-signing releases). SetADCP_STRICT_VERIFY=1to fail closed when sidecars or cosign are unavailable.adcp/types_gen.go— the existing CI only diffedtmproto/types_gen.go, so an upstream schema change that alteredadcp/types_gen.gocould merge green with stale generated code.VERSIONmoved from a commit SHA (12c09e0...) tolatest— onlylatestis currently published at the protocol manifest endpoint. Once released versions land we can pin to them.Safety hardening (from code + security review)
VERSIONvalidated against^(latest|\d+\.\d+\.\d+(-[A-Za-z0-9.]+)?)$before it's interpolated into URLs, rsync source paths, or theVERSIONfile./-prefixed or..-containing entries before extraction.rsync --deletesource path existence check so a missing/renamed bundle layout fails loudly instead of wiping the schema tree.curl --retry 3 --retry-all-errors --max-time 60on every fetch.PROTECTED=(...)array at the top ofdownload.shso the exclude-list maintenance burden is obvious.Trust model
Current
latestpin relies on sha256 + TLS (same-origin — verifies transport, not supply chain). Once the repo pins to a released version (3.1.0+), cosign verification proves the bundle came from the upstream release workflow, defending against host compromise.Test plan
./download.shsucceeds withVERSION=latest, sha256 matches, scripts survive rsync./download.sh '../evil'and./download.sh 'foo; rm -rf /'rejected by validationlatest.tgzpath reports "checksum-only trust" and succeedsADCP_STRICT_VERIFY=1 ./download.shfails closed when sidecars absent./check-freshness.shreports up-to-date after fresh downloadgo build ./...passesgo test ./adcp/...passes🤖 Generated with Claude Code