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:
@@ -25,6 +25,7 @@ type StackSummary = appbackup.StackSummary
|
||||
type AppBackupInfo = appbackup.AppBackupInfo
|
||||
type AppDataPath = appbackup.AppDataPath
|
||||
type AppDockerVolume = appbackup.AppDockerVolume
|
||||
type RecoveryInfo = appbackup.RecoveryInfo
|
||||
|
||||
// --- type aliases (dbdump) ---
|
||||
|
||||
@@ -80,6 +81,10 @@ func ResolveDockerVolumeNames(composePath string) []string {
|
||||
return appbackup.ResolveDockerVolumeNames(composePath)
|
||||
}
|
||||
|
||||
func ParseComposeImages(composePath string) []string {
|
||||
return appbackup.ParseComposeImages(composePath)
|
||||
}
|
||||
|
||||
// humanizeBytes forwards to appbackup.HumanizeBytes; kept unexported so the
|
||||
// many in-package call sites (backup.go, crossdrive.go, restore code) need no edit.
|
||||
func humanizeBytes(b int64) string {
|
||||
@@ -107,6 +112,18 @@ func AppVolumeDumpPath(nsRoot, stackName string) string {
|
||||
return appbackup.AppVolumeDumpPath(nsRoot, stackName)
|
||||
}
|
||||
|
||||
func RecoveryUnitPath(nsRoot, stackName string) string {
|
||||
return appbackup.RecoveryUnitPath(nsRoot, stackName)
|
||||
}
|
||||
|
||||
func RecoveryUnitComposePath(nsRoot, stackName string) string {
|
||||
return appbackup.RecoveryUnitComposePath(nsRoot, stackName)
|
||||
}
|
||||
|
||||
func RecoveryUnitManifestPath(nsRoot, stackName string) string {
|
||||
return appbackup.RecoveryUnitManifestPath(nsRoot, stackName)
|
||||
}
|
||||
|
||||
func AppDataDir(nsRoot, stackName string) string {
|
||||
return appbackup.AppDataDir(nsRoot, stackName)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user