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:
@@ -302,55 +302,6 @@
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
<!-- Infra Backup -->
|
||||
<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 class="info-item">
|
||||
<span class="label">Versions</span>
|
||||
<span class="value">{{.InfraBackup.VersionCount}}</span>
|
||||
</div>
|
||||
</div>
|
||||
{{if .InfraBackupVersions}}
|
||||
<details style="margin-top: 0.75rem;">
|
||||
<summary style="cursor: pointer; color: var(--text-secondary, #94a3b8); font-size: 0.85em;">Backup History ({{len .InfraBackupVersions}} versions)</summary>
|
||||
<table style="width: 100%; margin-top: 0.5rem; font-size: 0.85em;">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="text-align: left; padding: 0.25rem 0.5rem;">Date</th>
|
||||
<th style="text-align: left; padding: 0.25rem 0.5rem;">Apps</th>
|
||||
<th style="text-align: right; padding: 0.25rem 0.5rem;">Disks</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{range .InfraBackupVersions}}
|
||||
<tr>
|
||||
<td style="padding: 0.25rem 0.5rem;">{{.CreatedAt.Format "2006-01-02 15:04"}}</td>
|
||||
<td style="padding: 0.25rem 0.5rem;">{{.StackCount}}{{if .StackNames}}: {{range $i, $n := .StackNames}}{{if $i}}, {{end}}{{$n}}{{end}}{{end}}</td>
|
||||
<td style="text-align: right; padding: 0.25rem 0.5rem;">{{.DiskCount}}</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</details>
|
||||
{{end}}
|
||||
{{else}}
|
||||
<p style="color: #facc15">No infra backup received yet</p>
|
||||
{{end}}
|
||||
</section>
|
||||
|
||||
<!-- Health -->
|
||||
<section class="card">
|
||||
@@ -489,7 +440,7 @@
|
||||
{{if eq .ConfigSyncStatus "in_sync"}}<span style="color: #22c55e;">✓ In sync</span>
|
||||
{{else if eq .ConfigSyncStatus "mismatch"}}<span style="color: #f59e0b;">⚠ Config mismatch — {{.ConfigDiffCount}} difference{{if gt .ConfigDiffCount 1}}s{{end}}</span>
|
||||
<button class="btn btn-outline btn-sm" style="margin-left: 0.5em; font-size: 0.8em;" onclick="showConfigDiff('{{.CustomerID}}')">Show Diff</button>
|
||||
{{else}}<span style="color: #94a3b8;">Unknown — no infra backup available yet</span>
|
||||
{{else}}<span style="color: #94a3b8;">Unknown — use "Show Diff" to compare live</span>
|
||||
{{end}}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user