feat(health-check): object-level gate that Forgejo [storage] serves (#197) #205

Sammanfogat
supernaut sammanfogade 1 incheckning från feat/197-storage-object-health-gate in i main 2026-07-22 06:29:05 +00:00
Ägare

Part of #197 (the prevention half; the duplicate-copy reclaim is the other half).

Why

The #188 cutover pointed Forgejo's [storage] at an empty volume and 404'd every avatar/package for hours — while the mount assertion, --check, and /api/healthz all stayed green. None reads a stored object. Same shallow-verification class as the #174 runner rebake.

What

A gate in the ADR 0030 post-apply health play (runs last, after Forgejo's restart handler):

  1. Pull a custom-avatar hash from the DB (SELECT avatar FROM "user" WHERE use_custom_avatar … LIMIT 1) — the source of truth for an object that must serve.
  2. Fetch /avatars/<hash>?size=64 via the local Caddy; fail the apply if not 200.
  3. Skip cleanly if the instance has no stored avatars (fresh instance).

Gated on forgejo_external_storage_enabled; read-only (changed_when: false).

Verification (prod)

storage-gate: DB-known avatar 89111e7b… -> HTTP 200   (ok — executed, not skipped)

Would have failed the #188 cutover loudly (DB had the hash; empty store → 404 → rc=1).

Part of #197 (the *prevention* half; the duplicate-copy reclaim is the other half). ## Why The #188 cutover pointed Forgejo's `[storage]` at an empty volume and **404'd every avatar/package for hours** — while the mount assertion, `--check`, and `/api/healthz` all stayed green. None reads a *stored object*. Same shallow-verification class as the #174 runner rebake. ## What A gate in the ADR 0030 post-apply health play (runs **last**, after Forgejo's restart handler): 1. Pull a custom-avatar hash from the DB (`SELECT avatar FROM "user" WHERE use_custom_avatar … LIMIT 1`) — the source of truth for an object that *must* serve. 2. Fetch `/avatars/<hash>?size=64` via the local Caddy; **fail the apply if not 200**. 3. Skip cleanly if the instance has no stored avatars (fresh instance). Gated on `forgejo_external_storage_enabled`; read-only (`changed_when: false`). ## Verification (prod) ``` storage-gate: DB-known avatar 89111e7b… -> HTTP 200 (ok — executed, not skipped) ``` Would have failed the #188 cutover loudly (DB had the hash; empty store → 404 → rc=1).
supernaut lade till 1 incheckning 2026-07-22 06:25:27 +00:00
feat(health-check): gate that Forgejo external [storage] serves a real object (#197)
Alla kontroller lyckades
ci / ci (pull_request) Successful in 1m24s
191f84bf5a
The #188 cutover pointed [storage] at an empty volume and 404'd every avatar for
hours while the mount check, --check, and /api/healthz all stayed green — none of
them reads a stored object. Add an object-level gate to the ADR 0030 post-apply
health play (runs last, after Forgejo's restart handler): pull a custom-avatar hash
from the DB (the source of truth for what MUST serve) and fetch /avatars/<hash>,
failing the apply if it isn't 200. Skips cleanly on a fresh instance with no stored
avatars. Gated on forgejo_external_storage_enabled; read-only (changed_when: false).

Verified on prod: executes (not skipped) and reports 'DB-known avatar <hash> -> HTTP
200'. Would have caught #188 at cutover (DB had the hash, empty store -> 404 -> fail).
supernaut sammanfogade incheckning 10c4953a20 till main 2026-07-22 06:29:05 +00:00
supernaut tog bort grenen feat/197-storage-object-health-gate 2026-07-22 06:29:05 +00:00
Logga in för att delta i denna konversation.
Inga granskare
Ingen milstolpe
Inget projekt
Inga tilldelade
1 deltagare
Notiser
Förfallodatum
Förfallodatumet är ogiltigt eller utanför gränserna. Använd formatet "åååå-mm-dd".

Inget förfallodatum satt.

Beroenden

Inga beroenden satta

Referens
bitborg/bitborg-infra!205
Ingen beskrivning angiven.