package main import ( "bytes" "os" "path/filepath" "strings" "testing" "time" "github.com/novox/mesh-controller/internal/catalogue" ) // Every catalogue module that runs something long-lived declares how it is ready (novox/hq ADR 0240 rule // 8): `module check` warns and counts the undeclared before the date, and refuses them from it. func TestModuleCheckCountsTheUndeclaredAndRefusesThemFromTheDate(t *testing.T) { dir := t.TempDir() digest := "@sha256:" + strings.Repeat("a", 64) path := filepath.Join(dir, "module.json") os.WriteFile(path, []byte(`{"module":"web","listens":[{"name":"web","port":80,"from":"mesh"}],"resources":[ {"id":"server","type":"container","name":"web","image":"registry.example/web`+digest+`","ports":["80"], "health":{"kind":"http","endpoint":"web"}}, {"id":"worker","type":"container","name":"web-worker","image":"registry.example/web`+digest+`"}, {"id":"seed","type":"container","name":"web-seed","image":"registry.example/web`+digest+`","run-once":true}]}`), 0o600) defer func() { checkNow = time.Now }() checkNow = func() time.Time { return catalogue.HealthRequiredFrom.Add(-time.Hour) } var out bytes.Buffer if err := moduleCheck([]string{path}, &out); err != nil { t.Fatalf("refused before the date: %v\n%s", err, out.String()) } for _, want := range []string{"ready: server by http / on web every 30s", "WARNING: worker stay(s) up", catalogue.HealthRequiredFrom.Format("2006-01-02"), UndeclaredHealthLine + " 1"} { if !strings.Contains(out.String(), want) { t.Errorf("the check does not say %q:\n%s", want, out.String()) } } checkNow = func() time.Time { return catalogue.HealthRequiredFrom } out.Reset() if err := moduleCheck([]string{path}, &out); err == nil { t.Fatalf("a long-running resource without health passed after the date:\n%s", out.String()) } if !strings.Contains(out.String(), "web: worker stays up and does not say how it is ready") { t.Errorf("the refusal does not name the resource:\n%s", out.String()) } } // A file that asks for a setting without saying whether it is trusted counts as trusted (novox/hq issue 339): // `module check` lists and counts it, and never refuses it — there is nothing unsafe to refuse. func TestModuleCheckListsUnmarkedFilesAndNeverRefusesThem(t *testing.T) { dir := t.TempDir() path := filepath.Join(dir, "module.json") os.WriteFile(path, []byte(`{"module":"power","resources":[ {"id":"logind","type":"file","path":"/etc/systemd/logind.conf.d/power.conf","mode":"0644","trusted":true, "content":"HandleLidSwitch=${setting:lid}\n"}, {"id":"note","type":"file","path":"/var/lib/power/note","mode":"0644","content":"${setting:greeting}\n"}]}`), 0o600) defer func() { checkNow = time.Now }() for _, at := range []time.Time{time.Date(2026, 10, 1, 0, 0, 0, 0, time.UTC), time.Date(2036, 1, 1, 0, 0, 0, 0, time.UTC)} { checkNow = func() time.Time { return at } var out bytes.Buffer if err := moduleCheck([]string{path}, &out); err != nil { t.Fatalf("refused at %v: %v\n%s", at, err, out.String()) } for _, want := range []string{"note ask(s) for a setting and do(es) not say whether it is trusted, so it counts as trusted", UnsaidTrustLine + " 1"} { if !strings.Contains(out.String(), want) { t.Errorf("the check does not say %q:\n%s", want, out.String()) } } } }