package main import ( "encoding/json" "errors" "strings" "testing" "github.com/novox/mesh-controller/internal/catalogue" "github.com/novox/mesh-controller/internal/inventory" "github.com/novox/mesh-controller/internal/link" "github.com/novox/mesh-controller/internal/secrets" ) // The `issued` verb runs `secret issued ` and nothing else, and that line is the one `secret` line // beside rotate and the desk's that a verb may run (novox/hq ADR 0305 §3, §10, issue 526). func TestTheIssuedVerbRunsTheOneLineThatCarriesNoValue(t *testing.T) { argv, err := argvFor("issued", map[string]any{"provision": "plex-api"}) if err != nil { t.Fatal(err) } if strings.Join(argv, " ") != "secret issued plex-api" { t.Fatalf("the verb composed %q", argv) } if _, err := argvFor("issued", map[string]any{}); err == nil { t.Fatal("the verb ran with no provision") } if _, err := argvFor("issued", map[string]any{"provision": "plex-api", "secret": "a value"}); err == nil { t.Fatal("the verb took a value beside the provision") } for _, line := range [][]string{ {"secret", "issued", "plex-api", "--from", "/tmp/x"}, {"secret", "issued", "--from"}, {"secret", "issued"}, {"secret", "accept", "ace", "kometa", "plex-api", "--provider", "ace"}, {"secret", "recover", "ace", "kometa", "plex-api"}, } { if err := terminalOnly(line); err == nil { t.Errorf("%q ran through a verb", line) } } if err := terminalOnly([]string{"secret", "issued", "plex-api"}); err != nil { t.Fatalf("the issued line was refused through its verb: %v", err) } found := false for _, v := range catalogue.ControllerVerbs { if v.Name == "issued" { found = true } } if !found { t.Fatal("the controller's seat does not declare the issued verb") } } // A provider's tool answering the value sealed to the call's key: what a provider does (ADR 0305 §2). func issuedSealed(t *testing.T, value string) func(issuedProvider, map[string]any) (link.Answer, error) { return func(_ issuedProvider, args map[string]any) (link.Answer, error) { key, _ := args["seal_to"].(string) if key == "" { t.Fatal("the provider was asked without a key to seal to") } if _, carried := args["value"]; carried { t.Fatal("the ask carried a value") } sealed, err := secrets.Seal(key, []byte(value)) if err != nil { t.Fatal(err) } raw, _ := json.Marshal(map[string]string{"sealed": sealed}) return link.Answer{Result: raw}, nil } } type issuedRecorder struct { kept []string acts []link.HandAct sent [][]string again bool // the value is held by every holder already } func (r *issuedRecorder) taker(t *testing.T, ask func(issuedProvider, map[string]any) (link.Answer, error)) issuedTaker { return issuedTaker{ providers: func(provision string) ([]issuedProvider, bool, error) { return []issuedProvider{{Node: "ace", Module: "plex", Tool: "plex_issued_credential"}}, true, nil }, ask: ask, keep: func(provision, provider, value string) (inventory.IssuedKept, error) { r.kept = append(r.kept, value) holders := []inventory.Holder{{Provision: provision, Consumer: "ace", ConsumerModule: "kometa", Provider: provider}, {Provision: provision, Consumer: "ace", ConsumerModule: "tautulli", Provider: provider}} if r.again { return inventory.IssuedKept{Holders: holders}, nil } return inventory.IssuedKept{Changed: true, Holders: holders, Sealed: holders, Machines: []string{"ace"}}, nil }, record: func(act link.HandAct) error { r.acts = append(r.acts, act); return nil }, send: func(machines []string) error { r.sent = append(r.sent, machines); return nil }, } } // The value the provider's tool sealed to the call is kept, recorded and sent, and the answer never says it. func TestAnIssuedValueIsTakenSealedFromTheProviderAndSent(t *testing.T) { var r issuedRecorder words, err := r.taker(t, issuedSealed(t, "the-servers-own-token")).take("plex-api") if err != nil { t.Fatal(err) } if len(r.kept) != 1 || r.kept[0] != "the-servers-own-token" { t.Fatalf("the provider's value was not kept: %d kept", len(r.kept)) } if len(r.sent) != 1 || strings.Join(r.sent[0], ",") != "ace" { t.Fatalf("the holders' machines were not sent: %v", r.sent) } if len(r.acts) != 1 || r.acts[0].Verb != handActIssued { t.Fatalf("the change was not recorded in the hand-act log: %+v", r.acts) } for _, said := range []string{words, r.acts[0].Why, strings.Join(r.acts[0].Args, " ")} { if strings.Contains(said, "the-servers-own-token") || strings.Contains(said, inventory.IssuedStamp("the-servers-own-token")) { t.Fatalf("the value or its fingerprint was said: %q", said) } } if !strings.Contains(words, "kometa on ace") || !strings.Contains(words, "tautulli on ace") { t.Fatalf("the answer does not name the holders: %q", words) } } // The same value again writes nothing, records nothing and sends nobody (ADR 0305 §5). func TestAnIssuedValueEveryHolderHoldsSendsNobody(t *testing.T) { r := issuedRecorder{again: true} words, err := r.taker(t, issuedSealed(t, "the-servers-own-token")).take("plex-api") if err != nil { t.Fatal(err) } if len(r.sent) != 0 || len(r.acts) != 0 { t.Fatalf("an unchanged value was sent or recorded: %v %v", r.sent, r.acts) } if !strings.Contains(words, "nothing was sent") { t.Fatalf("the answer does not say nothing was sent: %q", words) } } // A value not sealed to the call's key is not taken, nor is a refusal, nor an empty answer (ADR 0305 §2). func TestOnlyAValueSealedToTheCallIsTaken(t *testing.T) { other, _, _ := secrets.Keypair() elsewhere, _ := secrets.Seal(other, []byte("somebody's value")) raw, _ := json.Marshal(map[string]string{"sealed": elsewhere}) plain, _ := json.Marshal(map[string]string{"value": "the-servers-own-token"}) for name, ask := range map[string]func(issuedProvider, map[string]any) (link.Answer, error){ "sealed to another key": func(issuedProvider, map[string]any) (link.Answer, error) { return link.Answer{Result: raw}, nil }, "answered in the clear": func(issuedProvider, map[string]any) (link.Answer, error) { return link.Answer{Result: plain}, nil }, "refused": func(issuedProvider, map[string]any) (link.Answer, error) { return link.Answer{Error: "the controller alone"}, nil }, "not reached": func(issuedProvider, map[string]any) (link.Answer, error) { return link.Answer{}, errors.New("503 no responders") }, "sealed empty": issuedSealed(t, " "), } { var r issuedRecorder if _, err := r.taker(t, ask).take("plex-api"); err == nil { t.Errorf("%s: taken", name) } if len(r.kept) != 0 || len(r.sent) != 0 { t.Errorf("%s: something was kept or sent", name) } } } // A provision no offer says its software issues is refused before anything is asked. func TestAProvisionNoOfferSaysIsIssuedIsRefused(t *testing.T) { asked := false taker := issuedTaker{ providers: func(string) ([]issuedProvider, bool, error) { return nil, false, nil }, ask: func(issuedProvider, map[string]any) (link.Answer, error) { asked = true return link.Answer{}, nil }, } if _, err := taker.take("postgres-database"); err == nil || !strings.Contains(err.Error(), "ADR 0305") { t.Fatalf("expected a refusal naming the record, got %v", err) } if asked { t.Fatal("a provider was asked for a provision no offer says its software issues") } } // Which assignments are asked: the modules on the providing machine whose offer says so, with their tool. func TestTheProvidersAskedAreTheOffersThatSaySo(t *testing.T) { shelf := map[string]catalogue.Manifest{ "plex": {Module: "plex", Provides: []catalogue.Offer{{Name: "plex-api", Credential: &catalogue.OfferCredential{ IssuedBy: catalogue.IssuedBySoftware, Tool: "plex_issued_credential"}}}}, "jellyfin": {Module: "jellyfin", Provides: []catalogue.Offer{{Name: "plex-api"}}}, } got := issuedOn(shelf, "ace", []string{"jellyfin", "plex", "kometa"}, "plex-api") if len(got) != 1 || got[0].Node != "ace" || got[0].Module != "plex" || got[0].Tool != "plex_issued_credential" { t.Fatalf("the providers asked: %+v", got) } if err := issuedRefusesRotation(shelf, "plex-api"); err == nil || !strings.Contains(err.Error(), "secret issued plex-api") { t.Fatalf("rotate of an issued provision was not refused with the way to take it: %v", err) } if err := issuedRefusesRotation(shelf, "postgres-database"); err != nil { t.Fatalf("rotate of an ordinary provision was refused: %v", err) } } // A change of an issued value is the mesh working as decided, never a repair (ADR 0305 §8). func TestAnIssuedValueIsADecisionInTheHandActLog(t *testing.T) { for _, v := range handActVerbs { if v.Verb == handActIssued { if v.Decision == "" { t.Fatal("secret issued counts as a repair") } return } } t.Fatal("secret issued is not in the hand-act table") } // **A need's credential is the vault's for its holder alone** (issue 757) exactly when its providing module is marked // moved, so `secret issued` goes to the vault naming each holder, and its software issues the provision's credential. func TestANeedIsIssuedToItsHolderOnlyWhereTheProviderIsMovedAndItsSoftwareIssuesIt(t *testing.T) { forge := func(moved bool, issued bool) catalogue.Manifest { offer := catalogue.Offer{Name: "gitea-read"} if issued { offer.Credential = &catalogue.OfferCredential{IssuedBy: catalogue.IssuedBySoftware, Tool: "gitea_agent_token"} } return catalogue.Manifest{Module: "gitea", Moved: moved, Provides: []catalogue.Offer{offer}} } shared := func(moved bool) catalogue.Manifest { return catalogue.Manifest{Module: "gitea", Moved: moved, OwnSecrets: catalogue.OwnSecrets{"key": {Path: "/k"}}, Provides: []catalogue.Offer{{Name: "gitea-read", Credential: &catalogue.OfferCredential{Own: "key"}}}} } given := func() catalogue.Manifest { return catalogue.Manifest{Module: "gitea", Moved: true, Provides: []catalogue.Offer{{Name: "gitea-read", Credential: &catalogue.OfferCredential{IssuedBy: catalogue.IssuedOutside}}}} } need := catalogue.Needed{Name: "gitea-read", From: "novox", Module: "gitea", For: "claude-code"} for why, c := range map[string]struct { shelf map[string]catalogue.Manifest need catalogue.Needed want bool }{ "moved and issued by its software": {map[string]catalogue.Manifest{"gitea": forge(true, true)}, need, true}, "not moved": {map[string]catalogue.Manifest{"gitea": forge(false, true)}, need, false}, "a login for each consumer": {map[string]catalogue.Manifest{"gitea": forge(true, false)}, need, true}, "a login for each, not moved": {map[string]catalogue.Manifest{"gitea": forge(false, false)}, need, false}, "a credential every holder shares": {map[string]catalogue.Manifest{"gitea": shared(true)}, need, false}, "a credential a person gives": {map[string]catalogue.Manifest{"gitea": given()}, need, false}, "a provider not on the shelf": {map[string]catalogue.Manifest{}, need, false}, "answered by a record": {map[string]catalogue.Manifest{"gitea": forge(true, true)}, catalogue.Needed{Name: "gitea-read", ByRecord: true, Module: "gitea", For: "claude-code"}, false}, } { if got := issuedToHolder(c.shelf, c.need); got != c.want { t.Errorf("%s: issued to its holder is %v, want %v", why, got, c.want) } } } // **The vault is a moved provider for its consumers' credentials** (issue 793): its pair rows are the vault's since // V3, so a need of `secret` is issued to its holder and answered by a moved provider, whether or not the module is // marked moved; another module is not. func TestTheModuleHoldingTheVaultSeatCountsAsMovedForItsConsumers(t *testing.T) { vault := catalogue.Manifest{Module: "mesh-vault", Claims: []catalogue.Claim{{Name: "mesh-vault"}}, Provides: []catalogue.Offer{{Name: "secret"}}} other := catalogue.Manifest{Module: "mesh-vault", Provides: []catalogue.Offer{{Name: "secret"}}} need := catalogue.Needed{Name: "secret", Local: "admin", From: "novox", Module: "mesh-vault", For: "gitea"} if !issuedToHolder(map[string]catalogue.Manifest{"mesh-vault": vault}, need) || !providerMoved(map[string]catalogue.Manifest{"mesh-vault": vault}, need) { t.Error("the vault's consumer is not answered by a moved provider") } if issuedToHolder(map[string]catalogue.Manifest{"mesh-vault": other}, need) || providerMoved(map[string]catalogue.Manifest{"mesh-vault": other}, need) { t.Error("a module not holding the vault seat counts as moved") } } // **A provision answered by the helper makes its provider a moved one for that provision alone** (issue 792): the // provides entry says `"answered-by": "helper"`, the module need not be marked moved, and no credential is the vault's // for it. Another provision of the module, or a module without the entry, does not count. func TestAnOfferAnsweredByTheHelperCountsAsMovedForThatProvisionOnly(t *testing.T) { proxy := catalogue.Manifest{Module: "route-proxy", Provides: []catalogue.Offer{ {Name: "route", AnsweredBy: catalogue.AnsweredByHelper}, {Name: "other"}}} plain := catalogue.Manifest{Module: "route-proxy", Provides: []catalogue.Offer{{Name: "route"}}} shelf := func(m catalogue.Manifest) map[string]catalogue.Manifest { return map[string]catalogue.Manifest{m.Module: m} } route := catalogue.Needed{Name: "route", From: "novox", Module: "route-proxy", For: "gitea"} other := catalogue.Needed{Name: "other", From: "novox", Module: "route-proxy", For: "gitea"} if !providerMoved(shelf(proxy), route) { t.Error("a provision answered by the helper is not answered by a moved provider") } if providerMoved(shelf(proxy), other) || providerMoved(shelf(plain), route) { t.Error("a provision not answered by the helper counts as moved") } if issuedToHolder(shelf(proxy), route) { t.Error("the flag made a credential the vault's") } }