v0.294.0: off-site clean-up guard follows the policy's own constants (R-867); no image clean-up while compose pulls (R-863); stderr tail (R-864); move-aside destination logged (R-869)
gates / gates (push) Successful in 28s

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
2026-10-05 07:13:02 +02:00
parent 69e914534f
commit 7861bf9dde
16 changed files with 607 additions and 36 deletions
@@ -1,6 +1,7 @@
package stacks
import (
"errors"
"fmt"
"os"
"path/filepath"
@@ -214,7 +215,7 @@ func TestImageRetention_OneTimeSweepOnlyCatalogRepos(t *testing.T) {
cat := filepath.Join(m.cfg.Paths.DataDir, "catalog-cache", "templates", "gone")
must(t, os.MkdirAll(cat, 0o755))
must(t, os.WriteFile(filepath.Join(cat, "docker-compose.yml"), []byte("services:\n gone:\n image: acme/gone:6\n"), 0o644))
deleted := m.RunImageRetentionOnce()
deleted, _ := m.RunImageRetentionOnce()
got := strings.Join(f.rmi, ",")
if !strings.Contains(got, "sha256:OLD") {
t.Fatalf("an earlier-removed app's image was not swept: %v", deleted)
@@ -242,8 +243,8 @@ func TestImageRetention_NoPassWhileAnUpdateRuns(t *testing.T) {
m.stacks["docs"].Updating = true
m.mu.Unlock()
st, _ := m.GetStack("web")
if _, err := m.deleteUnkeptImages("test", appImageRepos(filepath.Dir(st.ComposePath), st.AppConfig), ""); err != nil {
t.Fatal(err)
if _, err := m.deleteUnkeptImages("test", appImageRepos(filepath.Dir(st.ComposePath), st.AppConfig), ""); !errors.Is(err, errImageRetentionBusy) {
t.Fatalf("err = %v, want errImageRetentionBusy (the caller tries again later)", err)
}
if len(f.rmi) != 0 {
t.Fatalf("a pass ran while docs was updating: %v", f.rmi)