feat(catalog): mirror artifact WASM binaries for CORS-enabled fetch (closes #304) - #308
Merged
Merged
Conversation
…loses #304) catalog.json is served with access-control-allow-origin: * from GitHub Pages, but the WASM artifacts it points at (GitHub Release assets that redirect to signed Azure Blob URLs) have no CORS header at all, blocking any browser-side consumer from fetching bytes it just discovered via the catalog. Adds scripts/ci/mirror_artifacts.py, run as a build-catalog CI step: walks the whole capabilities/ tree, downloads each unique artifact, verifies it against artifact.digest (fails closed on mismatch), and writes it to catalog/artifacts/<id>-<version>/<asset-name> -- the exact path suffix artifact.url already carries after '.../releases/download/', so the CORS-enabled mirror URL is always a fixed prefix swap, never new state to keep in sync. generate_catalog_pages.py renders the derived mirror link alongside the existing artifact link on each capability's detail page. contract.json's artifact.digest/url remain the sole authoritative record; this mirror is a convenience read-path regenerated fresh on every build, same as catalog.json itself.
enricopiovesan
enabled auto-merge (squash)
August 23, 2026 01:57
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
#304confirmed (via directcurl) thatcatalog.jsononregistry.traverse-framework.comis served withaccess-control-allow-origin: *, but the published capability WASM artifacts it points at (GitHub Release assets, spec 007-artifact-hosting) redirect to signed Azure Blob URLs with no CORS header at all — a browser-side consumer can discover a capability through the CORS-enabled catalog but itsfetch()of the artifact bytes fails outright.Verified the feasibility of mirroring before scoping the fix: 79 unique artifacts across all
artifacts/*releases, 1.6MB total, ~17KB average — well inside GitHub Pages' size/bandwidth limits.Changes
scripts/ci/mirror_artifacts.py(new): walks the wholecapabilities/**/contract.jsontree (deprecated versions included, so yanked artifacts stay fetchable too), downloads each uniqueartifact.url, re-verifies the bytes againstartifact.digest(fails the CI run closed on a mismatch — this repo's first runtime digest verification of artifact bytes; existing checks are format-only), and writes each tocatalog/artifacts/<id>-<version>/<asset-name>— the exact path suffixartifact.urlalready carries after.../releases/download/, so the CORS-enabled mirror URL is always a fixed prefix swap, never new state to keep in sync..github/workflows/ci.yml: wires the new script into the existingbuild-catalogjob (push-to-main only), after static-page generation and before the Pages upload.scripts/ci/generate_catalog_pages.py: renders the derived mirror URL as a second "Artifact (CORS mirror)" link on every capability's detail page, computed with the identical regex the mirror script uses (kept in explicit lockstep via a code comment on both sides).scripts/ci/tests/test_mirror_artifacts.py(new): URL-recognition, digest-match write path, digest-mismatch fail-closed path (mocked at the network boundary).scripts/ci/tests/test_generate_catalog_pages.py(new, first test file for this script): the newartifact_mirror_urlhelper only.docs/decision-log.md: entry 66 records the finding, feasibility check, chosen approach, and whycontract.json/spec 007 stay untouched (the mirror is a convenience read-path, regenerated fresh every build likecatalog.jsonitself — carries none of spec 007's immutability obligations).Governing Spec
Project Item
Registry Project — issue #304
Definition of Done
contract.jsonrecord before being served.Validation
python3 -m unittest discover -s scripts/ci/tests -p "test_*.py"— 91 passedpython3 scripts/ci/capability_validation.py— passes cleanpython3 -c "import yaml; yaml.safe_load(open('.github/workflows/ci.yml'))"— valid YAMLmirror_artifacts.pyagainst this repo's real, live release assets (not fixtures): 79/79 mirrored, digests matched, 0 skippedgenerate_catalog_pages.pyagainst a representative fixture and confirmed the rendered page's mirror link resolves to the exact path the mirror script writes to