hub v0.12.0: retire Infra Backup, purge its plaintext secrets, fix backup-deadline email

Phase-1 of SPIKE-infra-backup-2026-06-15. The infra-backup mechanism was dead
since slice 8C yet stored plaintext customer secrets at rest (app-secret key,
restic password, Cloudflare tokens) — a zero-knowledge violation — and its
absence made the daily expected_backup_missed email fire for healthy customers.

- Repoint monitor.CheckBackupDeadlines backup half to the agent host-report's
  PBS snapshots (+vzdump): alarm only on no-backup / >26h stale / verify failed.
  Keep the db_dump half. No host-report → no backup alarm (liveness owns that).
  New store.GetLatestHostReportJSON. Tests incl. a companion that fails pre-fix.
- Remove the infra-backup endpoints, store methods/types, and operator panel;
  /recovery now returns config_yaml only.
- migrate(): DROP infra_backup_versions/infra_backups + VACUUM (+wal_checkpoint)
  to physically reclaim the plaintext pages, gated on table existence.

Flagged out-of-scope: exposed creds need operator rotation; legacy reports table
holds historical plaintext restic_password rows (separate leak, not purged here).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-16 11:08:06 +02:00
parent 2f7acb7d07
commit 0635640848
10 changed files with 466 additions and 595 deletions
-23
View File
@@ -133,29 +133,6 @@
{{end}}
</section>
<!-- Infra Backup (Disaster Recovery) -->
<section class="card">
<h2>Infra Backup</h2>
{{if .InfraBackup}}
<div class="info-grid">
<div class="info-item">
<span class="label">Last Updated</span>
<span class="value">{{.InfraBackupAge}}</span>
</div>
<div class="info-item">
<span class="label">Deployed Stacks</span>
<span class="value">{{.InfraBackup.StackCount}}</span>
</div>
<div class="info-item">
<span class="label">Disks</span>
<span class="value">{{.InfraBackup.DiskCount}}</span>
</div>
</div>
{{else}}
<p style="color: #facc15">No infra backup received yet</p>
{{end}}
</section>
<!-- Health -->
<section class="card">
<h2>Health</h2>