v0.53.0: Phase 2 capture side — per-app secret-free recovery unit
Each app's on-drive backup becomes a self-contained, recreatable recovery unit: compose/ (docker-compose.yml + .felhom.yml + secret-stripped app.yaml) alongside the existing db-dumps/ + volume-dumps/, plus a secret-free manifest.json (image pins, secret env-var NAMES, data_key names, checksums). The unit stores no secret value, no data-key, and not the image — secrets are recovered at restore from the guest's own app.yaml (live/PBS), never regenerated. - appbackup: RecoveryUnit* path helpers, RecoveryInfo + GetStackRecoveryInfo, ParseComposeImages; AppDBDump/Volume refactored onto RecoveryUnitPath. - backup: recovery_unit.go (manifest + CaptureRecoveryUnit), wired into RunDBDumps; capture test proves secret-free. - stacks: DeployField.DataKey + Metadata.DataKeyEnvVars(); main.go stackAdapter implements GetStackRecoveryInfo (excludes secret-named + encrypted values). - Restore-from-unit recreate + fail-closed gate + live AdventureLog validation: next. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -33,14 +33,35 @@ func PrimaryBackupPath(nsRoot string) string {
|
||||
return filepath.Join(nsRoot, "backups", "primary")
|
||||
}
|
||||
|
||||
// RecoveryUnitPath returns the per-app self-contained recovery-unit ROOT under a namespace root.
|
||||
// It is the existing per-app backup dir (`backups/primary/<stack>/`) — the legacy name is kept so the
|
||||
// db-dumps/ and volume-dumps/ already written there need no migration; the unit gains compose/ and
|
||||
// manifest.json as siblings, making the whole dir a complete, recreatable unit (Phase 2). The unit is
|
||||
// secret-free: secrets/data-keys are recovered from the guest's own app.yaml (live or via PBS), never
|
||||
// stored here. See backup.recoveryUnit / restore for the capture + restore flow.
|
||||
func RecoveryUnitPath(nsRoot, stackName string) string {
|
||||
return filepath.Join(nsRoot, "backups", "primary", stackName)
|
||||
}
|
||||
|
||||
// RecoveryUnitComposePath returns the compose/config capture dir within an app's recovery unit
|
||||
// (docker-compose.yml + .felhom.yml + secret-stripped app.yaml).
|
||||
func RecoveryUnitComposePath(nsRoot, stackName string) string {
|
||||
return filepath.Join(RecoveryUnitPath(nsRoot, stackName), "compose")
|
||||
}
|
||||
|
||||
// RecoveryUnitManifestPath returns the manifest.json path within an app's recovery unit.
|
||||
func RecoveryUnitManifestPath(nsRoot, stackName string) string {
|
||||
return filepath.Join(RecoveryUnitPath(nsRoot, stackName), "manifest.json")
|
||||
}
|
||||
|
||||
// AppDBDumpPath returns the DB dump directory for an app under a felhom-data namespace root.
|
||||
func AppDBDumpPath(nsRoot, stackName string) string {
|
||||
return filepath.Join(nsRoot, "backups", "primary", stackName, "db-dumps")
|
||||
return filepath.Join(RecoveryUnitPath(nsRoot, stackName), "db-dumps")
|
||||
}
|
||||
|
||||
// AppVolumeDumpPath returns the Docker-volume dump-tar directory for an app under a namespace root.
|
||||
func AppVolumeDumpPath(nsRoot, stackName string) string {
|
||||
return filepath.Join(nsRoot, "backups", "primary", stackName, "volume-dumps")
|
||||
return filepath.Join(RecoveryUnitPath(nsRoot, stackName), "volume-dumps")
|
||||
}
|
||||
|
||||
// AppDataDir returns the app data directory under a felhom-data namespace root.
|
||||
|
||||
Reference in New Issue
Block a user