Serialize restore recovery and rebase manifest paths

This commit is contained in:
2026-08-10 21:01:28 +00:00
parent 4158394dcf
commit 8375ad83f3
14 changed files with 581 additions and 78 deletions

View File

@@ -114,19 +114,28 @@ func executeRestoreDownloadAction(
return err
}
if action.LocalRelativePath == config.PathManifestFile {
if isRestoreManifest(action.LocalRelativePath) {
file, err := temporary.Open()
if err != nil {
return fmt.Errorf("open restored manifest: %w", err)
}
err = validateRestoredManifest(ctx, cfg, current, file)
destinationRoot := sessionRoot
requireCurrentIdentity := action.LocalRelativePath == config.PathManifestFile
if !requireCurrentIdentity {
destinationRoot = filepath.Dir(safeLocalPath)
}
restored, prepareErr := prepareRestoredManifest(ctx, cfg, current, file, destinationRoot, requireCurrentIdentity)
closeErr := file.Close()
if err != nil {
return err
if prepareErr != nil {
return prepareErr
}
if closeErr != nil {
return fmt.Errorf("close restored manifest: %w", closeErr)
}
if err := (&manifest.LocalStore{}).Save(ctx, safeLocalPath, restored); err != nil {
return fmt.Errorf("install rebased manifest atomically: %w", err)
}
return nil
}
if err := temporary.Install(filepath.Base(safeLocalPath), fileops.WorkspaceFileMode); err != nil {
@@ -136,6 +145,11 @@ func executeRestoreDownloadAction(
return nil
}
func isRestoreManifest(relativePath string) bool {
clean := filepath.ToSlash(filepath.Clean(strings.TrimSpace(relativePath)))
return clean == config.PathManifestFile || clean == config.PathPreviousDirSegment+"/"+config.PathManifestFile
}
func verifyRestoredObject(ctx context.Context, store storage.ObjectStore, action RestoreAction, temporary *fileops.DownloadedTempFile) error {
if strings.TrimSpace(action.SHA256) == "" && strings.TrimSpace(action.Generation) == "" {
return nil
@@ -217,38 +231,3 @@ func executeRestoreAudioAction(
}
return nil
}
func validateRestoredManifest(ctx context.Context, cfg *config.Config, current *RemoteCurrentState, source io.Reader) error {
manifestStore := &manifest.LocalStore{}
m, err := manifestStore.LoadReader(ctx, source)
if err != nil {
return fmt.Errorf("validate manifest decode: %w", err)
}
requestedSession := strings.TrimSpace(cfg.Session.SessionID)
requestedCampaign := strings.TrimSpace(cfg.Session.Campaign)
manifestSession := strings.TrimSpace(m.SessionID)
manifestCampaign := strings.TrimSpace(m.Campaign)
if manifestSession != requestedSession {
return fmt.Errorf("manifest session_id %q does not match requested session_id %q", manifestSession, requestedSession)
}
if manifestCampaign == "" {
return fmt.Errorf("manifest campaign is required")
}
if manifestCampaign != requestedCampaign {
return fmt.Errorf("manifest campaign %q does not match requested campaign %q", manifestCampaign, requestedCampaign)
}
if current != nil {
if expected := strings.TrimSpace(current.SessionID); expected != "" && manifestSession != expected {
return fmt.Errorf("manifest session_id %q does not match discovered session_id %q", manifestSession, expected)
}
if expected := strings.TrimSpace(current.Campaign); expected != "" && manifestCampaign != expected {
return fmt.Errorf("manifest campaign %q does not match discovered campaign %q", manifestCampaign, expected)
}
if expected := strings.TrimSpace(current.RunID); expected != "" && strings.TrimSpace(m.RunID) != expected {
return fmt.Errorf("manifest run_id %q does not match discovered run_id %q", strings.TrimSpace(m.RunID), expected)
}
}
return nil
}