fury-gl / fury-gl/polyxios-data

Harden catalog publishing: reviewed checksum changes, versioning, content-addressed blobs

Open
#4 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
No language data
Stars
1
Forks
1
Avg merge
1m
Merged PRs (30d)
1

Description

## Context

`models.json` is now the trust root for every asset polyxios downloads: since fury-gl/polyxios#20 the client reads asset checksums from this catalog instead of from checksums pinned in its own source. That makes the publishing path here security-relevant.

Not urgent, no open exploit. Filing so it isn't forgotten. Client-side counterpart: fury-gl/polyxios#30.

## Three mutable things the current setup depends on

1. **Release assets.** `releases/download/obj/alligator.obj` can be deleted and re-uploaded with different bytes at the same URL by anything holding `contents: write`. The URL is not a content identity.
2. **The format tags.** `obj`, `vtk`, `abaqus` … are rolling tags re-pointed as assets are added, so "pin to a tag" gives a consumer nothing. On GitHub only commit SHAs and content digests are genuinely immutable.
3. **The catalog.** `release-updated.yml` fires on `published`, **`edited`** and `deleted`, regenerates `models.json`, and pushes straight to the default branch as `github-actions[bot]`. Editing a release silently rewrites checksums with no human in the loop.

## Proposed work, cheapest first

**1. Open a PR instead of pushing to the default branch.** Highest value per line of anything here, ~5 lines. Swap the final step of `release-updated.yml` for `peter-evans/create-pull-request` and protect the default branch with required review. Every checksum change then lands as a reviewed diff, and a compromised Actions token can propose but not publish. Worth doing even if nothing else on this list happens.

**2. Add `version`, `generated` and `expires` to `models.json`.** ~15 lines in `.github/scripts/update_models_json.py`. A monotonic integer `version` lets clients refuse a catalog older than the newest they have seen (rollback protection — stops an attacker serving an old catalog naming a since-withdrawn asset). `expires`, refreshed by CI, lets clients warn when they have been pinned to a frozen snapshot while real updates ship (freeze protection).

**3. Content-address the blobs.** Upload assets named by digest — `releases/download/blobs/sha256-108a1f43…` — and keep the human filename only as catalog metadata. The URL then *is* the content identity: different bytes require a different URL, which requires a catalog change, which items 1 and 2 now constrain. Side benefits: dedup across formats, no cross-package name collisions, safe deletion. Costs a one-time migration and makes the release page unbrowsable — mitigated by the generated `README.md`.

**4. Sign the catalog (optional, later).** Only signatures give provenance rather than integrity.
- Ed25519 / minisign: publish `models.json.minisig` beside the catalog, public key baked into polyxios. **The private key must live outside this repo** — in Actions secrets here, a repo compromise takes key and payload together and the signature buys nothing.
- Sigstore keyless via GitHub OIDC: no key custody at all, attests that the catalog came from this workflow in this repo. Heavier client dependency (`sigstore`), but a better fit for an already CI-driven publish.

**5. Scope the workflow token.** `permissions: contents: write` is repo-wide. Narrow it if the create-PR route makes that possible, and consider whether `release: edited` should trigger a checksum rewrite at all without review — an edited release changing a recorded `sha256` is precisely the shape of the attack this is guarding against.

## Suggested minimum

Items 1 and 2. Together with the vendored-floor work in fury-gl/polyxios#30 they close silent swap, rollback, and unreviewed checksum rewrites, for roughly a day of work and no new runtime dependency anywhere.

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by reading release-updated.yml and .github/scripts/update_models_json.py, then compare the suggested minimum of reviewed pull requests and catalog metadata with the workflow's current triggers and publishing step. Done means checksum changes are proposed for review and models.json includes version, generated, and expires fields without adding a runtime dependency.

Written by the indexing model from the issue text.

Assessment

Tech stack
github-actions, python
Domain
ci-cd, release, security
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
38/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.