5f5e3c54a1
DR recipe slice (hub half), grounded in SPIKE-dr-recipe-2026-06-16. The hub
receives two additive dr_recipe halves on the existing report paths (agent
storage/guest/PBS on host-report; controller customer/apps on the controller
report), stores them PLAINTEXT in a DEDICATED dr_recipe table keyed by customer
(each half preserves the other), and AssembleDRRecipe stitches them into one
operator-readable recipe (ignore-unknown + version-skew tolerant).
View: a DR-recipe panel on the customer page + GET /customers/{id}/dr-recipe.json
download (operator-auth, no secrets to redact). Plaintext-at-rest is correct —
the recipe is the clean inverse of the retired infra-backup.
Tests: store round-trip (each half preserves the other), assemble-matches-golden,
ignore-unknown + version skew, partial halves, no-secrets sweep. Manifest tag
bumped to v0.13.0.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
65 lines
3.4 KiB
Markdown
65 lines
3.4 KiB
Markdown
# 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](hub/CHANGELOG.md).
|
|
|
|
---
|
|
|
|
## REPORT — hub v0.13.0: DR recipe (assemble + store + view)
|
|
|
|
**TASK — DR recipe slice (hub half).** Receive the two secret-free recipe halves, assemble them into one
|
|
customer recipe, store PLAINTEXT in a dedicated table, and expose an operator view/download. Grounded in
|
|
`documentation/audits/SPIKE-dr-recipe-2026-06-16.md`. Pairs with felhom-agent v0.38.0 (storage/guest/PBS
|
|
half) + felhom-controller v0.73.0 (customer/apps half, the boundary-enforcing emitter).
|
|
|
|
### Store (`hub/internal/store/dr_recipe.go`)
|
|
|
|
- New `dr_recipe` table (migrate()) — DEDICATED, separate from the opaque `host_escrow` and from the
|
|
dropped `infra_backup*` tables. Keyed by `customer_id`; columns `recipe_version, host_id,
|
|
host_half_json, app_half_json, updated_at`.
|
|
- `SaveDRRecipeHostHalf` / `SaveDRRecipeAppHalf` — each upserts its half and PRESERVES the other
|
|
(last-write-wins per half; a re-report of one half never clobbers the other).
|
|
- `AssembleDRRecipe(rec)` — stitches the two halves into `AssembledRecipe{recipe_version, customer,
|
|
guests, pbs, drives, pve_storage, apps}`. Sub-sections pass through as `json.RawMessage` (verbatim);
|
|
**ignore-unknown** at the top level + version-skew tolerant (`recipe_version` = max) for forward-compat
|
|
across the three repos. Pure → unit-tested.
|
|
|
|
### Ingest (`hub/internal/api/handler.go`)
|
|
|
|
- `handleHostReport` persists the `dr_recipe` host-half (keyed by the host's customer).
|
|
- `handleReport` persists the `dr_recipe` app-half (keyed by `customer_id`), mirroring the
|
|
`app_telemetry` pattern. Both backward-compatible (old agents/controllers omit the field) and never
|
|
fatal to the heartbeat.
|
|
|
|
### View (`hub/internal/web/dr_recipe.go` + customer page)
|
|
|
|
- A DR-recipe panel on the customer detail page (which half landed + last-updated) with a
|
|
**Download recipe (JSON)** link.
|
|
- `GET /customers/{id}/dr-recipe.json` serves the assembled recipe (operator dashboard-auth, pretty
|
|
JSON, `Content-Disposition` attachment). No decrypt, nothing to redact.
|
|
|
|
### Boundary
|
|
|
|
The recipe is PLAINTEXT-at-rest because it carries NO secrets — only identifiers/intents/sizes/
|
|
coordinates. The PBS key stays in escrow, the access token in identity-escrow, the restic password in
|
|
escrow. This is the clean inverse of the retired infra-backup (which shipped `restic_password`/
|
|
`cf_api_token` and was a zero-knowledge violation). The leak-preventing allowlist is enforced at the
|
|
controller emitter; the hub adds a defense-in-depth no-secrets sweep.
|
|
|
|
### Tests
|
|
|
|
`TestDRRecipe_StoreRoundTrip`, `TestAssembleDRRecipe_MatchesGolden` (assembled shape pinned in
|
|
`testdata/dr-recipe.golden.json`), `TestAssembleDRRecipe_IgnoreUnknownAndVersionSkew`,
|
|
`TestAssembleDRRecipe_PartialHalves`, `TestAssembleDRRecipe_NoSecrets`. `go build`/`go vet`/`go test ./...`
|
|
green.
|
|
|
|
### Cross-repo golden discipline
|
|
|
|
The recipe wire spans three repos. The agent's `host-report.golden.json` `dr_recipe` section and the
|
|
hub's host-half test literal must stay key-consistent; the controller's emitter and the hub's app-half
|
|
test literal likewise. On any wire change, manually checksum-diff the golden across the three repos
|
|
(there is no shared types module yet).
|
|
|
|
### Deploy
|
|
|
|
Built + pushed `felhom-hub:0.13.0`; manifest tag bumped + ArgoCD `felhom` app synced.
|