package inventory import ( "context" "errors" "strings" "testing" "github.com/novox/mesh-controller/internal/catalogue" ) // A module with one secret of each kind the rule tells apart (novox/hq ADR 0228), assigned to the // consumer machine. func aModuleWithGivenSecrets(t *testing.T) (*Inventory, context.Context) { t.Helper() inv, ctx := twoNodesWithKeys(t) m := catalogue.Manifest{Module: "letta", Version: "1", OwnSecrets: catalogue.OwnSecrets{ "server-password": {Path: "/var/lib/letta/server-password", Taken: catalogue.TakenAtStart}, "openai-api-key": {Path: "/var/lib/letta/openai-api-key", Taken: catalogue.TakenAtStart, IssuedBy: catalogue.IssuedOutside}, "logflare": {Path: "/var/lib/letta/logflare", Taken: catalogue.TakenApplied}, "broker": {Path: "/var/lib/mesh/letta/broker"}, }} if err := inv.RegisterModule(ctx, m, Source{}); err != nil { t.Fatal(err) } assign(t, inv, ctx, "consumer", "letta") return inv, ctx } func assign(t *testing.T, inv *Inventory, ctx context.Context, node, module string) { t.Helper() n, err := inv.NodeByName(ctx, node) if err != nil { t.Fatal(err) } if _, err := inv.store.Pool().Exec(ctx, `insert into assignment (node, module) values ($1, $2) on conflict do nothing`, n.ID, module); err != nil { t.Fatal(err) } } // sent records a declaration sent to a machine now, as a push does, and answers its digest. func sent(t *testing.T, inv *Inventory, ctx context.Context, node, digest string) string { t.Helper() n, err := inv.NodeByName(ctx, node) if err != nil { t.Fatal(err) } if err := inv.RecordSent(ctx, n.ID, digest, nil); err != nil { t.Fatal(err) } return digest } func originOf(t *testing.T, inv *Inventory, ctx context.Context, node, module, name string) string { t.Helper() origin, _, err := inv.OwnSecretOrigin(ctx, node, module, name) if err != nil { t.Fatal(err) } return origin } // **A given value is replaced once, after the first good start on it, and never again** (ADR 0228): // not on a report of a declaration sent before it was given, not on a report of a declaration the // mesh has moved past, and not a second time. func TestAGivenValueIsReplacedAfterTheFirstGoodStartAndNeverAgain(t *testing.T) { inv, ctx := aModuleWithGivenSecrets(t) before := sent(t, inv, ctx, "consumer", "declaration-before") marked, err := inv.AcceptGivenSecret(ctx, "consumer", "letta", "server-password", "typed-by-a-person") if err != nil || !marked { t.Fatalf("a given value for a secret the mesh may make is marked to be replaced: %v %v", marked, err) } // The machine's report of what it was sent before the value was given is not a start on it. if got, err := inv.ReplaceGivenAfterStart(ctx, "consumer", before); err != nil || len(got) != 0 { t.Fatalf("a start before the value was given replaced it: %+v %v", got, err) } carrying := sent(t, inv, ctx, "consumer", "declaration-carrying-it") // A report about a declaration other than the one last sent says nothing about this one. if got, err := inv.ReplaceGivenAfterStart(ctx, "consumer", before); err != nil || len(got) != 0 { t.Fatalf("a report of an older declaration replaced it: %+v %v", got, err) } if originOf(t, inv, ctx, "consumer", "letta", "server-password") != OriginAccepted { t.Fatal("the given value was replaced before its module started on it") } got, err := inv.ReplaceGivenAfterStart(ctx, "consumer", carrying) if err != nil { t.Fatal(err) } if len(got) != 1 || got[0].Module != "letta" || got[0].Name != "server-password" || len(got[0].Machines) != 1 || got[0].Machines[0] != "consumer" { t.Fatalf("the first good start replaced %+v", got) } if originOf(t, inv, ctx, "consumer", "letta", "server-password") != OriginMade { t.Fatal("the replacement is not the mesh's own") } // Never again: the same report heard twice, and the next declaration's report. if again, err := inv.ReplaceGivenAfterStart(ctx, "consumer", carrying); err != nil || len(again) != 0 { t.Fatalf("the same start replaced it twice: %+v %v", again, err) } next := sent(t, inv, ctx, "consumer", "declaration-after") if again, err := inv.ReplaceGivenAfterStart(ctx, "consumer", next); err != nil || len(again) != 0 { t.Fatalf("a later start replaced the mesh's own value: %+v %v", again, err) } } // **What stays as given** (ADR 0228): a value an outside party issued, a value the module applies, // and a value the mesh's own code accepted — a bus account it issued is the mesh's word to a broker, // and a fresh random value would break it. func TestWhatIsNeverReplacedAfterAStart(t *testing.T) { inv, ctx := aModuleWithGivenSecrets(t) for _, name := range []string{"openai-api-key", "logflare"} { marked, err := inv.AcceptGivenSecret(ctx, "consumer", "letta", name, "from-outside") if err != nil || marked { t.Fatalf("%s was marked to be replaced: %v %v", name, marked, err) } } if err := inv.AcceptSecretForModule(ctx, "consumer", "letta", "broker", "issued-by-the-mesh"); err != nil { t.Fatal(err) } declared := sent(t, inv, ctx, "consumer", "declaration") if got, err := inv.ReplaceGivenAfterStart(ctx, "consumer", declared); err != nil || len(got) != 0 { t.Fatalf("a value that stays as given was replaced: %+v %v", got, err) } for _, name := range []string{"openai-api-key", "logflare", "broker"} { if originOf(t, inv, ctx, "consumer", "letta", name) != OriginAccepted { t.Fatalf("%s was touched", name) } } // And asked by hand, the outside party's key is refused, saying why and how old it is. var refused ErrNotRotatable err := inv.RotateModuleSecret(ctx, "consumer", "letta", "openai-api-key") if !errors.As(err, &refused) || !strings.Contains(err.Error(), "outside the mesh") || !strings.Contains(err.Error(), "day(s) ago") || !strings.Contains(err.Error(), "secret accept") { t.Fatalf("rotating an outside party's key must be refused with its age and the way out: %v", err) } if originOf(t, inv, ctx, "consumer", "letta", "openai-api-key") != OriginAccepted { t.Fatal("a refused rotation touched the value") } } // On an adopted machine the module must be taken before a start is one under the mesh; and a module // no longer assigned to the machine has no start to wait for. func TestAGivenValueWaitsForTheTakeOnAnAdoptedMachine(t *testing.T) { inv, ctx := aModuleWithGivenSecrets(t) if err := inv.SetAdopted(ctx, "consumer", true); err != nil { t.Fatal(err) } if _, err := inv.AcceptGivenSecret(ctx, "consumer", "letta", "server-password", "the-found-one"); err != nil { t.Fatal(err) } held := sent(t, inv, ctx, "consumer", "declaration-holding-it") if got, err := inv.ReplaceGivenAfterStart(ctx, "consumer", held); err != nil || len(got) != 0 { t.Fatalf("a module held as found, not yet taken, had its given value replaced: %+v %v", got, err) } if err := inv.Take(ctx, "consumer", "letta"); err != nil { t.Fatal(err) } taken := sent(t, inv, ctx, "consumer", "declaration-taking-it") got, err := inv.ReplaceGivenAfterStart(ctx, "consumer", taken) if err != nil || len(got) != 1 { t.Fatalf("the first good start after the take did not replace the given value: %+v %v", got, err) } // Unassigned: nothing starts, nothing is replaced. if _, err := inv.AcceptGivenSecret(ctx, "consumer", "letta", "server-password", "given-again"); err != nil { t.Fatal(err) } if err := inv.Unassign(ctx, "consumer", "letta"); err != nil { t.Fatal(err) } gone := sent(t, inv, ctx, "consumer", "declaration-without-it") if got, err := inv.ReplaceGivenAfterStart(ctx, "consumer", gone); err != nil || len(got) != 0 { t.Fatalf("a module no longer assigned had its given value replaced: %+v %v", got, err) } } // A definition that changed after the value was given is asked again at the start: one that now says // the value is an outside party's keeps it as given. func TestADefinitionThatNowSaysOutsideKeepsTheGivenValue(t *testing.T) { inv, ctx := aModuleWithGivenSecrets(t) if _, err := inv.AcceptGivenSecret(ctx, "consumer", "letta", "server-password", "typed"); err != nil { t.Fatal(err) } m := catalogue.Manifest{Module: "letta", Version: "2", OwnSecrets: catalogue.OwnSecrets{ "server-password": {Path: "/var/lib/letta/server-password", Taken: catalogue.TakenAtStart, IssuedBy: catalogue.IssuedOutside}}} if err := inv.RegisterModule(ctx, m, Source{}); err != nil { t.Fatal(err) } declared := sent(t, inv, ctx, "consumer", "declaration") if got, err := inv.ReplaceGivenAfterStart(ctx, "consumer", declared); err != nil || len(got) != 0 { t.Fatalf("a value the definition now says is an outside party's was replaced: %+v %v", got, err) } if originOf(t, inv, ctx, "consumer", "letta", "server-password") != OriginAccepted { t.Fatal("the value was touched") } }