package main import ( "context" "encoding/base64" "encoding/json" "os" "strings" "testing" "git.novox.be/novox/mesh-sdk/go/catalogue" "git.novox.be/novox/mesh-sdk/go/compose" sdkdelivery "git.novox.be/novox/mesh-sdk/go/delivery" ) // natsComposedWith is the bus module's composition on novox with the given user list: the catalogue's nats manifest as // captured (testdata/beside/mesh-catalog/modules/nats/module.json.captured), its archives, which only a registration // turns into references, left out, and its container's built image given as a reference. func natsComposedWith(t *testing.T, users string) sdkdelivery.Composed { t.Helper() raw, err := os.ReadFile("../../testdata/beside/mesh-catalog/modules/nats/module.json.captured") if err != nil { t.Fatal(err) } var m catalogue.Manifest if err := json.Unmarshal(raw, &m); err != nil { t.Fatal(err) } var kept []map[string]any for _, r := range m.Resources { if _, templated := r["template"]; templated { continue // a template is rendered from the build's templates archive, which only a registration fetches } switch r["type"] { case "archive": continue case "container": // Its image is named by a build's artifact, which only a registration records: given here as a reference. delete(r, "artifact") r["image"] = "nats@sha256:" + strings.Repeat("1", 64) } kept = append(kept, r) } m.Resources = kept key := base64.StdEncoding.EncodeToString(make([]byte, 32)) in := compose.Input{Catalogue: map[string]catalogue.Manifest{m.Module: m}, BusUsers: users, OwnSecrets: []compose.OwnSecretRow{{Node: "novox", Module: m.Module, Name: "broker", Origin: "made", SealedTo: key, Sealed: "SEALED-BY-THE-TEST"}}, Nodes: []compose.Node{{Name: "novox", Assigned: []string{m.Module}, Stated: true, SealingKey: key, Capabilities: map[string]bool{"container-runtime": true, "systemd": true}}}} fp := sdkdelivery.SourcePrefix2 + strings.Repeat("e", 64) all, _, err := compose.Compositions(in, "novox", map[string]string{m.Module: fp}, compose.Foreseeing) if err != nil { t.Fatal(err) } k, _ := sdkdelivery.ComposedKey("novox", m.Module, fp) c, ok := all[k] if !ok { t.Fatalf("no composition of %s: %v", m.Module, all) } return c } // 1945/AC12 and the review's A2 (ADR 0539 clause 7): a revision of the bus module's composition that changes only its // user list, a file in a directory its container mounts, is judged neither and said to change only the user list, so // a new credential never waits for a person's yes; a revision that changes anything else beside it is judged as any. func TestARevisionOfOnlyTheUserListMovesNothing(t *testing.T) { at, _, _, haves := aPlace(t, "novox") ctx := context.Background() before := natsComposedWith(t, "authorization { users = [ {user: a} ] }\n") after := natsComposedWith(t, "authorization { users = [ {user: a}, {user: b} ] }\n") if d1, _ := sdkdelivery.ComposedDigestOf(before); d1 == func() string { d, _ := sdkdelivery.ComposedDigestOf(after); return d }() { t.Fatal("the two user lists composed the same") } key, _ := sdkdelivery.ComposedKey("novox", before.Module, before.FP) if _, err := writeComposed(ctx, at, key, before); err != nil { t.Fatal(err) } runs, _ := sdkdelivery.ComposedDigestOf(before) haves[before.Module] = sdkdelivery.Have{FP: before.FP, Composed: runs, Phase: sdkdelivery.PhaseRunning, Health: sdkdelivery.HealthOK} digest, _ := sdkdelivery.ComposedDigestOf(after) v, err := judgeMove(ctx, at, key, after, digest) if err != nil { t.Fatal(err) } if v.Judgement != sdkdelivery.JudgedNeither || !v.UserListOnly || v.Against != runs { t.Errorf("a user-list-only revision is judged %+v", v) } // The user list and a container's image beside it: judged as any move, and not user-list-only. other := after other.Resources = append([]json.RawMessage{}, after.Resources...) for i, r := range other.Resources { var head map[string]any _ = json.Unmarshal(r, &head) if head["type"] == "container" { head["image"] = "nats@sha256:" + strings.Repeat("9", 64) other.Resources[i], _ = json.Marshal(head) } } d2, _ := sdkdelivery.ComposedDigestOf(other) v, err = judgeMove(ctx, at, key, other, d2) if err != nil { t.Fatal(err) } if v.UserListOnly || v.Judgement != sdkdelivery.JudgedRecreates { t.Errorf("a new image beside the user list is judged %+v", v) } }