Files
felhom.eu/REPORT.md
T

3.9 KiB

felhom.eu — task reports

Overwrite this file with a summary of the most recent task only (uniform with the other repos; not cumulative). The cumulative hub history lives in hub/CHANGELOG.md; the scripts history lives in scripts/CHANGELOG.md.

Hub v0.61.0 + felhom-tenantsync v1.1.0 — Customer RESET (middle lifecycle tier) — 2026-07-17

Commits: 4009401 (code), e144c5e (manifest). Live: hub 0.61.0 on k3s (Synced/Healthy); felhom-tenantsync v1.1.0 on ep0 (felhom-hetzner).

What shipped

The middle lifecycle tier between host delete and customer Delete. One operator action returns a customer to pre-first-install: every OPERATIONAL trace dies — offsite repo (Hetzner sub-account/box), PBS namespace + all backup groups + token, DR recipe, one-time secret, claim state, retained escrow custody — while identity + basic config survive (customer_configs incl. the offsite tier CHOICE, all provenance rows, and the audit-event stream).

Viktor's rulings, all implemented: (1) destroying retained escrow custody gets its own separate acknowledgment; (2) RESET clears claim state → fresh code next onboarding; (3) RESET refuses while any host row exists (delete hosts first — reset never deletes hosts); (4) the confirm surface shows a live-counted inventory.

Discipline

External teardown FIRST, DB purge LAST (publish-last). Every leg idempotent → a partial run is re-run from the top; a failed external leg is a clean journal entry and the DB purge (which erases the descriptors that say what still needs tearing down) is withheld until every external leg is ok. Provenance + events are never wiped.

Components

  • store/customer_reset.go: customer_resets journal (per-attempt, per-leg, resumable); CustomerResetInventory (live counts incl. retained blobs via the F-14 host_deletions UNION); Start/UpdateResetLeg/Finish/LatestCustomerReset; ack-gated PurgeCustomerResetDBState; DeleteClaim.
  • claim.ResetToUnclaimed: deletes the claim row → EnsureIssued mints a fresh first code next onboarding.
  • offsite: Deprovision (idempotent label-lookup delete), OffsiteIdentifier, ClearProvisionedDescriptor.
  • tenantsync + scripts/felhom-tenantsync.sh v1.1.0: deprovision op destroys the namespace + backup groups + token; shared felhom@pbs user untouched; idempotent.
  • web/customer_reset.go: GET /configs/{id}/reset → inventory JSON; POST → orchestration (all gates before any write/external call). A distinct amber RESET card + reset_done flash.

Verification

  • Green gate: go build ./... && go vet ./... && go test ./... all pass. Hub confirm gate OK.
  • Red-proofs (run-fail-revert, both proven red then restored): (a) escrow-ack gate — defeat it → reset proceeds & destroys blobs → FAIL; (b) partial-failure resumability — don't withhold the purge → DB purged despite an external failure → FAIL. Plus store ack-gating + journal round-trip; offsite Deprovision idempotency + descriptor clear; RESET-card render.
  • Live drill on ep0 (throwaway drill-reset-01, real PBS data): provision → real backup written into the namespace → deprovision (deleted:true; namespace + backup group + token destroyed) → token/ns confirmed gone → idempotent re-run (deleted:false) → all 3 real tenants + the shared user survived.

Not live-drilled (covered otherwise)

The web RESET POST and the Hetzner sub-account delete are covered by the httptest-driven orchestration tests + offsite unit tests (the offsite Deprovision faithfully mirrors the live-proven ReissueCredentials, swapping reset→delete). The hub UI is operator-password-gated → CC verifies the UI via render tests, not a live click. A live Hetzner create/delete drill was not run (billed external service; mirror-of-live-proven + idempotency-tested).