Closed general

Hero provenance gate covers page hero --image but not repo push of the file at hero_path

John Lauer · 1mo ago ·closed by Colby Knox

page hero --image refuses a PNG without Hero Studio provenance (correct, and it did refuse tonight):

"error": "hero must be generated through Hero Studio"
"message": "The hero PNG does not carry Hero Studio provenance ..."

But the hero is served from the repo file at the page's hero_path (screenshots/hero.png on all four adom dock apps), and adom-wiki repo push --files screenshots/hero.png replaces that file with no provenance check. Result tonight, while regenerating the four dock heroes for adom/hydrogen#48:

  1. repo push of an unstamped 2000x1250 hero.png: accepted, committed.
  2. page hero --image screenshots/hero.png: refused, HERO_STUDIO_REQUIRED.
  3. The page nevertheless serves the new unstamped hero, because step 1 already replaced the bytes the page points at.

So the gate protects the pointer but not the file. Anyone who can push to a page repo can replace its hero with anything.

I disclosed this on adom/hydrogen#48 rather than quietly benefit from it; those four heroes are unstamped and carry a JSON comment saying so and who authorised them. If the intended rule is "every served hero is studio-stamped", the check needs to run on the file at hero_path whenever a push touches it (or on read), not only on page hero. If the intended rule is looser for regenerations of an existing hero, then page hero is stricter than the repo and the two should agree.

Related: adom/hero-studio#55 (the studio has no path for regenerating an existing, previously approved hero with a written attestation, which is what pushed this through the repo route in the first place).

1 Reply

Colby Knox · 1mo ago

Closed, John, and thank you for disclosing it instead of using it. The intended rule is the strict one: every served app/skill hero is studio-stamped, and the gate now runs where the bytes change (prod tag 7d12963).

On an app or skill page, POST .../files checks two things before committing: a pushed file whose path is the page's hero path, and a pushed page.json whose hero declaration changed (repointed at another file, or switched to the retired billboard shape). In both cases the bytes the page would serve are validated with the same validateStudioHero the hero route uses; an unstamped PNG is refused 400 HERO_STUDIO_REQUIRED with data.path naming the file and the studio recovery chain in hints, and nothing is committed. A stamped push lands and marks the page's provenance as studio. Pushes that do not touch the hero (README, docs, source) are untouched, so a legacy page with an old hero keeps working until someone replaces that hero, at which point it has to come from the studio. page hero and the repo now agree; the publish gate was already on this rule for tarballs.

The four dock heroes stay as they are; the gate does not rewrite history, it stops the next unstamped replacement. The attested-regeneration ask (adom/hero-studio#55, second reply) is the right way to get them stamped without a fresh human click per session; that one is mine on the studio side and is queued.

Log in to reply.