Constrain restore installation to session root
This commit is contained in:
@@ -524,6 +524,36 @@ func TestExecuteRestorePlanPathMismatchFails(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestExecuteRestorePlanRejectsAncestorSymlinkCreatedAfterPlanning(t *testing.T) {
|
||||
cfg := restorePlanConfig(t)
|
||||
current := restorePlanCurrentState(t, cfg)
|
||||
store := &storage.FakeBackend{}
|
||||
seedRestoreObject(store, current.CurrentManifestKey, []byte(`{"session_id":"2026-05-03"}`))
|
||||
seedRestoreObject(store, current.SessionPrefix+"artifacts/session_recap.md", []byte("remote-content\n"))
|
||||
plan, err := buildRestorePlan(context.Background(), cfg, current, store, RestorePlanOptions{Force: true})
|
||||
if err != nil {
|
||||
t.Fatalf("buildRestorePlan() error = %v", err)
|
||||
}
|
||||
|
||||
sessionRoot := artifacts.SessionWorkDirForCampaign(cfg.Pipeline.Workspace.Root, cfg.Session.Campaign, cfg.Session.SessionID)
|
||||
outside := t.TempDir()
|
||||
if err := os.Symlink(outside, filepath.Join(sessionRoot, "artifacts")); err != nil {
|
||||
t.Skipf("Symlink() unavailable: %v", err)
|
||||
}
|
||||
|
||||
report, err := newRestoreReport(current, plan, RestorePlanOptions{Force: true})
|
||||
if err != nil {
|
||||
t.Fatalf("newRestoreReport() error = %v", err)
|
||||
}
|
||||
_, err = executeRestorePlan(context.Background(), cfg, current, plan, report, store)
|
||||
if err == nil || !strings.Contains(err.Error(), "not a directory") {
|
||||
t.Fatalf("executeRestorePlan() error = %v, want ancestor conflict", err)
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(outside, "session_recap.md")); !os.IsNotExist(err) {
|
||||
t.Fatalf("outside target was changed: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func mustReadRestoreReport(t *testing.T, path string) *RestoreReport {
|
||||
t.Helper()
|
||||
data, err := os.ReadFile(path)
|
||||
|
||||
Reference in New Issue
Block a user