diff --git a/internal/catalogue/holds_test.go b/internal/catalogue/holds_test.go index 8c66ed50..2a39fb71 100644 --- a/internal/catalogue/holds_test.go +++ b/internal/catalogue/holds_test.go @@ -23,7 +23,9 @@ func TestWhatAMoveUnderRecordHoldsFor(t *testing.T) { {"id":"inbox-note","type":"file","path":"${dir:data-mail}/README","content":"x"}, {"id":"imap","type":"container","image":"registry/imap@sha256:1","volumes":["${dir:data-mail}:/mail"], "env-file":["${dir:state}/mailu.env"]}, - {"id":"watcher","type":"process","command":"watch"}]}` + {"id":"watcher","type":"process","command":"watch"}, + {"id":"installation","type":"archive","path":"/opt/mailu-tools","artifact":"archive"}, + {"id":"guard","type":"package","package":"nftables"}]}` var m Manifest if err := json.Unmarshal([]byte(raw), &m); err != nil { t.Fatal(err) @@ -62,6 +64,8 @@ func TestWhatAMoveUnderRecordHoldsFor(t *testing.T) { {"a provider", func(m *Manifest) { m.Requires = append(m.Requires, "s3") }, "what it requires"}, {"what it provides", func(m *Manifest) { m.Provides = append(m.Provides, Offer{Name: "smtp"}) }, "what it provides"}, {"a process of a module with data", func(m *Manifest) { resource(m, "watcher")["command"] = "watch2" }, "long-running process watcher"}, + {"an archive resource", func(m *Manifest) { resource(m, "installation")["artifact"] = "archive2" }, "the archive installation"}, + {"a package resource", func(m *Manifest) { resource(m, "guard")["package"] = "nftables2" }, "the package guard"}, } for _, c := range cases { t.Run(c.name, func(t *testing.T) { diff --git a/internal/catalogue/recreates.go b/internal/catalogue/recreates.go index 14350954..431a3f81 100644 --- a/internal/catalogue/recreates.go +++ b/internal/catalogue/recreates.go @@ -195,6 +195,12 @@ func Holds(from, to Manifest) string { if keepsData { return fmt.Sprintf("it changes its long-running %s %s, and it keeps data of its own", kind, id) } + default: + // Anything that is not a file or directory (judged above by whether a container mounts it + // or it holds data) always holds: an archive, a package, a user, a network, or any type + // added later (novox/hq ADR 0377 ยง3's allowlist names only tools bundles and manifest + // fields that recreate nothing). + return fmt.Sprintf("it changes the %s %s", kind, id) } } }