fail-closed tier fallback + bounded per-tier storage caps (#125 H1+H2) #164
Inga granskare
Etiketter
Inga etiketter
area/backups
area/ci
area/control-panel
area/identity
area/infra
area/observability
area/payments
area/security
area/storage
area/web
blocked
needs-info
needs-triage
ready-for-implementation
type
bug
type
chore
type
docs
type
epic
type
feature
type
task
wontfix
Ingen milstolpe
Inget projekt
Inga tilldelade
1 deltagare
Notiser
Förfallodatum
Inget förfallodatum satt.
Beroenden
Inga beroenden satta
Referens
bitborg/bitborg-infra!164
Läser in…
Hänvisa till i nytt ärende
Ingen beskrivning angiven.
Ta bort grenen "feat/125-reconciler-quota-hardening"
Borttagning av en gren är permanent. Även om den borttagna grenen kan fortsätta existera en kort tid innan den faktiskt tas bort, kan det INTE ångras i de flesta fall. Vill du fortsätta?
Closes the two HIGH findings in #125 (H1, H2). ⚠️ Review + dry-run before applying — the reconciler timer applies within ~5 min of the role apply.
H1 — fail-closed tier fallback
The old fallback sent any unmatched/mis-provisioned user to
lfs-basic, whose sharedbaserule granted unlimited non-LFS storage. A user whosetier_participantassignment failed at signup (but whose JIT Forgejo account was created) silently got unlimited hosting.participant(waslfs-basic).tier_basicis now read from Kanidm as the positive paid-seat signal (payments webhook adds members) rather than being the catch-all.forgejo_users+forgejo_service_accounts+reconciler_user_exempt_extra) are exempted into the unlimited group — otherwise fail-closed would zero-quota the operator admin and the bots.WARNis logged on every fail-closed fallback, which also surfaces an ACL-filtered empty tier read (M8) in the journal.⚠️
reconciler_user_exempt_extracurrently listssupernaut(group_vars) — the operator admin predates Ansible provisioning (forgejo_usersis empty). Confirm that's the correct + only out-of-band admin login before applying.H2 — bounded per-tier non-LFS storage
The shared
baserule (size:repos:all+size:assets:all= -1) let one basic user fill the shared data volume with ordinarygit push/packages — a shared-volume outage with only reactiveDiskUsageCritical(90%) to catch it.<group>-storerule (size:repos:all+size:assets:all) capped at 10 GiB (the paid-seat figure from the pricing decision — 10 GiB shared, no repo-count cap). LFS add-ons bump LFS only.baserule is detached from every group and deleted; groups that still carry it self-heal.size:git:lfsrule, so Forgejo's most-permissive merge can't defeat either cap.Not in scope (still open on #125)
H3 (token-scope no-op → fatal/alertable), M4 (per-cycle + org Actions bypass), M8 (sanity floor on group reads), and the upload/file-size half of M3. M3 note:
MAX_CREATION_LIMITis deliberately not set — the pricing decision chose "no repo-count cap, bounded by storage quota".Verification
Rendered with prod-shaped vars +
bash -nclean;ansible-playbook --syntax-check+ansible-lint(production profile) clean. Not yet dry-run on the instance.Refs #125.