v0.54.0: Phase 2b — restore-from-recovery-unit + fail-closed data-key gate
Restore recreates an app from its on-drive unit + the guest's own secrets, regenerating nothing. reconcileRestoreSecrets (pure, unit-tested) merges the unit's non-secret env with secrets recovered from the live app.yaml and FAILS CLOSED if a data-encrypting key is unrecoverable (refuse — a PBS whole-guest restore is needed — rather than regenerate and corrupt). Resettable secrets missing → warn + proceed. - backup: RestoreFromRecoveryUnit (manifest -> recover secrets -> gate -> restore volumes -> recreate definition + redeploy w/ re-pull); falls back to volume-only. - seams: RecoverStackSecrets/RecreateStackFromUnit (adapter +encKey), stacks.RedeployFromEnv. Wired into /backup/restore. - tests: gate (refuse/proceed/verbatim) + data_key parsing. Gate + reconcile + data_key parsing unit-tested; capture live-validated (v0.53.1). Full readable-data e2e vs AdventureLog needs the auth-gated dashboard restore — pending. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -30,6 +30,19 @@ type StackDataProvider interface {
|
||||
// from the guest's own app.yaml, live or via the PBS whole-guest snapshot). ok=false if the
|
||||
// stack is unknown.
|
||||
GetStackRecoveryInfo(name string) (RecoveryInfo, bool)
|
||||
|
||||
// --- Phase 2b: restore-from-recovery-unit ---
|
||||
|
||||
// RecoverStackSecrets returns the live decrypted values for the named secret env vars that are
|
||||
// currently present (non-empty) in the stack's app.yaml (the guest's own — live rootfs, or
|
||||
// PBS-restored). Names that are absent/empty are simply omitted from the map; the caller's
|
||||
// fail-closed gate decides what to do. The unit is never the source of secrets.
|
||||
RecoverStackSecrets(name string, names []string) map[string]string
|
||||
|
||||
// RecreateStackFromUnit restores an app's definition from the unit's compose dir into the stack
|
||||
// dir, writes app.yaml from fullEnv (encrypting secret fields), and (re-)deploys it via
|
||||
// `docker compose up -d`, which re-pulls the pinned image. Secrets are NEVER regenerated.
|
||||
RecreateStackFromUnit(name, composeSrcDir string, fullEnv map[string]string) error
|
||||
}
|
||||
|
||||
// RecoveryInfo carries everything needed to write a secret-free recovery unit for a stack.
|
||||
|
||||
Reference in New Issue
Block a user