package provider import ( "bytes" "context" "encoding/json" "errors" "fmt" "reflect" "slices" "strings" "sync" "testing" "time" ) // standIn is a stand-in bus: buckets of keys and values, and watches that hand the current values first and then // every change, as the bus's key-value watch does. type standIn struct { mu sync.Mutex buckets map[string]map[string][]byte watchers map[string][]func(string, []byte) } func newStandIn() *standIn { return &standIn{buckets: map[string]map[string][]byte{}, watchers: map[string][]func(string, []byte){}} } func (s *standIn) Watch(ctx context.Context, bucket string, handle func(key string, value []byte)) error { s.mu.Lock() current := map[string][]byte{} for k, v := range s.buckets[bucket] { current[k] = v } s.watchers[bucket] = append(s.watchers[bucket], handle) s.mu.Unlock() for _, k := range sortedKeys(current) { handle(k, current[k]) } return nil } func (s *standIn) Put(_ context.Context, bucket, key string, value []byte) error { s.mu.Lock() if s.buckets[bucket] == nil { s.buckets[bucket] = map[string][]byte{} } s.buckets[bucket][key] = append([]byte(nil), value...) ws := slices.Clone(s.watchers[bucket]) s.mu.Unlock() for _, w := range ws { w(key, value) } return nil } func (s *standIn) Delete(_ context.Context, bucket, key string) error { s.mu.Lock() delete(s.buckets[bucket], key) ws := slices.Clone(s.watchers[bucket]) s.mu.Unlock() for _, w := range ws { w(key, nil) } return nil } func (s *standIn) get(bucket, key string) []byte { s.mu.Lock() defer s.mu.Unlock() return s.buckets[bucket][key] } func (s *standIn) keys(bucket string) []string { s.mu.Lock() defer s.mu.Unlock() return sortedKeys(s.buckets[bucket]) } // everything is every value the bus holds, for a test that no secret is in a bucket. func (s *standIn) everything() []byte { s.mu.Lock() defer s.mu.Unlock() var all []byte for _, b := range s.buckets { for k, v := range b { all = append(all, k...) all = append(all, v...) } } return all } // vault is a stand-in vault: a value per name, or nothing yet. type vault struct { mu sync.Mutex values map[string]string asked []string } func (v *vault) Value(_ context.Context, name string) ([]byte, error) { v.mu.Lock() defer v.mu.Unlock() v.asked = append(v.asked, name) val, ok := v.values[name] if !ok { return nil, fmt.Errorf("the vault holds no %s yet", name) } return []byte(val), nil } // maker records what the provider's adapter was asked to make, with the credential it was handed. type maker struct { mu sync.Mutex made map[string]string // contributed is what each consumer's entry carried of its plan's contribution. contributed map[string]map[string]any // as is the identity each consumer's entry was made under. as map[string]string gone []string fail error calls int } func (m *maker) Make(_ context.Context, c Consumer) error { m.mu.Lock() defer m.mu.Unlock() m.calls++ if m.fail != nil { return m.fail } if m.made == nil { m.made = map[string]string{} } m.made[c.Entry.Key()] = string(c.Credential) if m.contributed == nil { m.contributed = map[string]map[string]any{} } m.contributed[c.Entry.Key()] = c.Entry.Contributes if m.as == nil { m.as = map[string]string{} } m.as[c.Entry.Key()] = c.Entry.As return nil } func (m *maker) Gone(_ context.Context, e Entry) error { m.mu.Lock() defer m.mu.Unlock() m.gone = append(m.gone, e.Key()) return nil } // assign puts a consumer's assignment with its plan's provisions into the stand-in mirror. func assign(t *testing.T, bus *standIn, node, module string, provisions ...map[string]string) { t.Helper() ps := []map[string]string{} ps = append(ps, provisions...) raw, err := json.Marshal(map[string]any{"node": node, "module": module, "assigned": "2026-10-15T00:00:00Z", "provisioning": map[string]any{"templates": map[string]string{"source": "x", "digest": "y"}, "provisions": ps}}) if err != nil { t.Fatal(err) } if err := bus.Put(context.Background(), AssignmentsBucket, node+"."+module, raw); err != nil { t.Fatal(err) } } func bind(provision, local, provider, providerModule string) map[string]string { b := map[string]string{"provision": provision, "provider": provider, "provider-module": providerModule} if local != "" { b["local"] = local } return b } func entryOf(t *testing.T, bus *standIn, key string) Entry { t.Helper() raw := bus.get(BucketOf("postgres"), key) if raw == nil { t.Fatalf("no entry %s in %s; it holds %v", key, BucketOf("postgres"), bus.keys(BucketOf("postgres"))) } var e Entry if err := json.Unmarshal(raw, &e); err != nil { t.Fatalf("entry %s: %v", key, err) } return e } // postgres is a provider of postgres-database on novox with a login per consumer (ADR 0048, ADR 0158 §11), its // served values derived from each consumer's identity (ADR 0202 §1). func postgres(bus *standIn, v *vault, m *maker) *Provider { return New(Options{ Node: "novox", Module: "postgres", Bus: bus, Vault: v, Make: m.Make, Gone: m.Gone, Offers: map[string]Offer{ "postgres-database": {Credential: PerConsumer, Serves: map[string]any{ "host": "postgres.novox.mesh", "port": 5432, "database": "${consumer:as}"}}, }, Logf: func(string, ...any) {}, }) } // A provider answers each consumer that binds it with an entry of its own in its own bucket: composed from its // served values and the consumer's identity, naming the credential the vault keeps for that consumer, and never // the credential itself; its adapter is handed each consumer's own value read from the vault. func TestEachConsumerGetsAnEntryOfItsOwnAndTheVaultsValue(t *testing.T) { bus, m := newStandIn(), &maker{} v := &vault{values: map[string]string{ "pair/novox/postgres-database/ace/letta": "letta-secret-1", "pair/novox/postgres-database/g14/umami": "umami-secret-2", }} assign(t, bus, "ace", "letta", bind("postgres-database", "", "novox", "postgres")) assign(t, bus, "g14", "umami", bind("postgres-database", "", "novox", "postgres")) p := postgres(bus, v, m) out, err := p.Pass(context.Background()) if err != nil { t.Fatal(err) } if got := bus.keys(BucketOf("postgres")); !slices.Equal(got, []string{"ace.letta.postgres-database", "g14.umami.postgres-database"}) { t.Fatalf("entries %v", got) } e := entryOf(t, bus, "ace.letta.postgres-database") if e.Provider != "novox" || e.ProviderModule != "postgres" || e.Consumer != "ace" || e.Module != "letta" || e.As != "mesh_ace_letta" || e.User != "mesh_ace_letta" || e.Credential != "pair/novox/postgres-database/ace/letta" || e.Refused != "" { t.Fatalf("entry %+v", e) } if e.Values["database"] != "mesh_ace_letta" || e.Values["host"] != "postgres.novox.mesh" || e.Values["port"] != float64(5432) { t.Fatalf("values %v", e.Values) } if m.made["ace.letta.postgres-database"] != "letta-secret-1" || m.made["g14.umami.postgres-database"] != "umami-secret-2" { t.Fatalf("made %v", m.made) } if bytes.Contains(bus.everything(), []byte("secret-")) { t.Fatal("a credential is in a bucket") } for _, o := range out { if o.Status != Answered { t.Fatalf("outcome %+v", o) } } } // A provider whose offer shares one credential (ADR 0158) names the vault's one value for the provision, and its // one user name, to every consumer. func TestASharedCredentialIsTheVaultsOneValueAndTheProvidersOneUser(t *testing.T) { bus, m := newStandIn(), &maker{} v := &vault{values: map[string]string{"provision/novox/sonarr-api": "one-value"}} assign(t, bus, "ace", "overseerr", bind("sonarr-api", "", "novox", "sonarr")) assign(t, bus, "g14", "homepage", bind("sonarr-api", "", "novox", "sonarr")) p := New(Options{Node: "novox", Module: "sonarr", Bus: bus, Vault: v, Make: m.Make, Logf: func(string, ...any) {}, Offers: map[string]Offer{"sonarr-api": {Credential: Shared, User: "sonarr", Serves: map[string]any{"url": "http://sonarr.novox.mesh:8989"}}}}) if _, err := p.Pass(context.Background()); err != nil { t.Fatal(err) } for _, key := range []string{"ace.overseerr.sonarr-api", "g14.homepage.sonarr-api"} { var e Entry if err := json.Unmarshal(bus.get(BucketOf("sonarr"), key), &e); err != nil { t.Fatalf("%s: %v", key, err) } if e.Credential != "provision/novox/sonarr-api" || e.User != "sonarr" || e.Values["url"] == nil { t.Fatalf("%s: %+v", key, e) } if m.made[key] != "one-value" { t.Fatalf("%s made with %q", key, m.made[key]) } } if bytes.Contains(bus.everything(), []byte("one-value")) { t.Fatal("the shared credential is in a bucket") } } // A consumer that keeps several holders of one provision is served no derived value: its entry refuses it, naming // both ends, so its client can report it (ADR 0349 clause 12, ADR 0202 §10); nothing is made for it. func TestAMultiHolderConsumerIsRefusedADerivedValueNamingBothEnds(t *testing.T) { bus, m := newStandIn(), &maker{} v := &vault{values: map[string]string{"pair/novox/postgres-database/ace/letta/archive": "x-secret"}} assign(t, bus, "ace", "letta", bind("postgres-database", "archive", "novox", "postgres")) out, err := postgres(bus, v, m).Pass(context.Background()) if err != nil { t.Fatal(err) } e := entryOf(t, bus, "ace.letta.postgres-database.archive") for _, says := range []string{"letta on ace", "postgres on novox", "postgres-database", "archive"} { if !strings.Contains(e.Refused, says) { t.Fatalf("the refusal does not name %q: %s", says, e.Refused) } } if e.Values != nil || e.Credential != "" { t.Fatalf("a refused entry carries values: %+v", e) } if m.calls != 0 { t.Fatal("the adapter made a refused consumer") } if len(out) != 1 || out[0].Status != Refused { t.Fatalf("outcomes %+v", out) } } // A consumer bound under a local name is served when the offer derives nothing from it: its credential is its own // pair row under that local name. func TestALocalNameIsServedWhenNothingIsDerived(t *testing.T) { bus, m := newStandIn(), &maker{} v := &vault{values: map[string]string{"pair/novox/redis-cache/ace/letta/queue": "q-secret"}} assign(t, bus, "ace", "letta", bind("redis-cache", "queue", "novox", "redis")) p := New(Options{Node: "novox", Module: "redis", Bus: bus, Vault: v, Make: m.Make, Logf: func(string, ...any) {}, Offers: map[string]Offer{"redis-cache": {Credential: PerConsumer, Serves: map[string]any{"port": 6379}}}}) if _, err := p.Pass(context.Background()); err != nil { t.Fatal(err) } var e Entry if err := json.Unmarshal(bus.get(BucketOf("redis"), "ace.letta.redis-cache.queue"), &e); err != nil { t.Fatal(err) } if e.Refused != "" || e.Credential != "pair/novox/redis-cache/ace/letta/queue" || e.Local != "queue" { t.Fatalf("entry %+v", e) } if m.made["ace.letta.redis-cache.queue"] != "q-secret" { t.Fatalf("made %v", m.made) } } // A consumer that unbinds loses its entry and the adapter hears it is gone; an entry another machine's instance of // the same provider wrote is not this one's to remove. func TestAnUnbindRemovesTheEntryAndLeavesAnotherProvidersAlone(t *testing.T) { bus, m := newStandIn(), &maker{} v := &vault{values: map[string]string{"pair/novox/postgres-database/ace/letta": "s1"}} assign(t, bus, "ace", "letta", bind("postgres-database", "", "novox", "postgres")) other, _ := json.Marshal(Entry{Provider: "shanks", ProviderModule: "postgres", Provision: "postgres-database", Consumer: "g14", Module: "gitea"}) _ = bus.Put(context.Background(), BucketOf("postgres"), "g14.gitea.postgres-database", other) p := postgres(bus, v, m) if _, err := p.Pass(context.Background()); err != nil { t.Fatal(err) } _ = bus.Delete(context.Background(), AssignmentsBucket, "ace.letta") out, err := p.Pass(context.Background()) if err != nil { t.Fatal(err) } if got := bus.keys(BucketOf("postgres")); !slices.Equal(got, []string{"g14.gitea.postgres-database"}) { t.Fatalf("entries left %v", got) } if !slices.Equal(m.gone, []string{"ace.letta.postgres-database"}) { t.Fatalf("gone %v", m.gone) } if len(out) != 1 || out[0].Status != Removed { t.Fatalf("outcomes %+v", out) } } // A bind whose credential the vault does not hold yet is waited for: nothing is made and no entry is written, so a // consumer is never told of a login its provider has not made; once the vault holds it, it is answered. func TestACredentialTheVaultDoesNotHoldYetIsWaitedFor(t *testing.T) { bus, m := newStandIn(), &maker{} v := &vault{values: map[string]string{}} assign(t, bus, "ace", "letta", bind("postgres-database", "", "novox", "postgres")) p := postgres(bus, v, m) out, err := p.Pass(context.Background()) if err != nil { t.Fatal(err) } if len(out) != 1 || out[0].Status != Waiting || !strings.Contains(out[0].Why, "pair/novox/postgres-database/ace/letta") { t.Fatalf("outcomes %+v", out) } if bus.keys(BucketOf("postgres")) != nil || m.calls != 0 { t.Fatal("a consumer was answered before its credential was there") } v.values["pair/novox/postgres-database/ace/letta"] = "late" if _, err := p.Pass(context.Background()); err != nil { t.Fatal(err) } if entryOf(t, bus, "ace.letta.postgres-database").Refused != "" || m.made["ace.letta.postgres-database"] != "late" { t.Fatal("not answered once the vault held the value") } } // Only the binds naming this provider, on this machine, are its own; a bind naming it for a provision it does not // offer is refused, naming both ends. func TestOnlyBindsNamingThisProviderAreAnswered(t *testing.T) { bus, m := newStandIn(), &maker{} v := &vault{values: map[string]string{"pair/novox/postgres-database/ace/letta": "s"}} assign(t, bus, "ace", "letta", bind("postgres-database", "", "shanks", "postgres"), bind("mongodb-database", "", "novox", "postgres")) assign(t, bus, "ace", "other", bind("postgres-database", "", "novox", "mssql")) out, err := postgres(bus, v, m).Pass(context.Background()) if err != nil { t.Fatal(err) } if got := bus.keys(BucketOf("postgres")); !slices.Equal(got, []string{"ace.letta.mongodb-database"}) { t.Fatalf("entries %v", got) } e := entryOf(t, bus, "ace.letta.mongodb-database") if !strings.Contains(e.Refused, "postgres on novox") || !strings.Contains(e.Refused, "letta on ace") { t.Fatalf("refusal %q", e.Refused) } if len(out) != 1 || m.calls != 0 { t.Fatalf("outcomes %+v, %d made", out, m.calls) } } // An assignment that cannot be read stops the pass: a bind missed would read as an unbind and remove an entry its // consumer still reads. func TestAnUnreadableAssignmentRemovesNothing(t *testing.T) { bus, m := newStandIn(), &maker{} v := &vault{values: map[string]string{"pair/novox/postgres-database/ace/letta": "s"}} assign(t, bus, "ace", "letta", bind("postgres-database", "", "novox", "postgres")) p := postgres(bus, v, m) if _, err := p.Pass(context.Background()); err != nil { t.Fatal(err) } _ = bus.Put(context.Background(), AssignmentsBucket, "ace.letta", []byte("{not json")) if _, err := p.Pass(context.Background()); err == nil { t.Fatal("a pass over an unreadable assignment went on") } if bus.get(BucketOf("postgres"), "ace.letta.postgres-database") == nil || len(m.gone) != 0 { t.Fatal("an entry was removed on an unreadable assignment") } } // An adapter that fails is said with the credential taken out of its words, and the entry is not written. func TestAFailedMakeIsSaidWithoutTheCredential(t *testing.T) { bus, m := newStandIn(), &maker{fail: errors.New(`password "hunter2-secret" rejected`)} v := &vault{values: map[string]string{"pair/novox/postgres-database/ace/letta": "hunter2-secret"}} assign(t, bus, "ace", "letta", bind("postgres-database", "", "novox", "postgres")) var logged []string p := postgres(bus, v, m) p.opts.Logf = func(f string, a ...any) { logged = append(logged, fmt.Sprintf(f, a...)) } out, err := p.Pass(context.Background()) if err != nil { t.Fatal(err) } if len(out) != 1 || out[0].Status != Failed || strings.Contains(out[0].Why, "hunter2") { t.Fatalf("outcomes %+v", out) } if strings.Contains(strings.Join(logged, "\n"), "hunter2") || len(logged) == 0 { t.Fatalf("logged %q", logged) } if bus.keys(BucketOf("postgres")) != nil { t.Fatal("an entry was written for a consumer the adapter could not make") } } // Run watches the binds on the stand-in bus: a consumer that binds is answered, and one that unbinds is removed, // without a pass asked by hand. func TestRunAnswersBindsAndUnbindsAsTheyAreWatched(t *testing.T) { bus, m := newStandIn(), &maker{} v := &vault{values: map[string]string{"pair/novox/postgres-database/ace/letta": "s"}} p := postgres(bus, v, m) p.opts.Every = time.Hour ctx, cancel := context.WithCancel(context.Background()) done := make(chan error, 1) go func() { done <- p.Run(ctx) }() assign(t, bus, "ace", "letta", bind("postgres-database", "", "novox", "postgres")) waitFor(t, func() bool { return bus.get(BucketOf("postgres"), "ace.letta.postgres-database") != nil }) _ = bus.Delete(context.Background(), AssignmentsBucket, "ace.letta") waitFor(t, func() bool { return bus.get(BucketOf("postgres"), "ace.letta.postgres-database") == nil }) cancel() if err := <-done; err != nil && !errors.Is(err, context.Canceled) { t.Fatal(err) } } func waitFor(t *testing.T, ok func() bool) { t.Helper() deadline := time.Now().Add(3 * time.Second) for !ok() { if time.Now().After(deadline) { t.Fatal("not within 3s") } time.Sleep(5 * time.Millisecond) } } // The consumer's identity is the mesh's (ADR 0202 §1): mesh__, lower case, `_` for anything else, // and its DNS form writes `-` for `_`. func TestTheIdentityIsTheMeshsAndItsDNSForm(t *testing.T) { if got := ConsumerIdentity("Home.Server", "my-app"); got != "mesh_home_server_my_app" { t.Fatal(got) } got, err := ServedTo(map[string]any{"bucket": "b-${consumer:as:dns}", "n": 3}, "mesh_ace_letta") if err != nil || got["bucket"] != "b-mesh-ace-letta" || got["n"] != 3 { t.Fatalf("%v %v", got, err) } if _, err := ServedTo(map[string]any{"x": "${consumer:node}"}, "mesh_ace_letta"); err == nil { t.Fatal("a fact the mesh does not state was filled") } } // A consumer's plan entry may carry what its module contributes to the provider (issue 776): the helper hands it to // the provider's adapter with the consumer, and does not write it to the bucket. func TestAConsumersContributionIsHandedToTheProviderPerConsumer(t *testing.T) { bus, m := newStandIn(), &maker{} v := &vault{values: map[string]string{ "pair/novox/postgres-database/ace/nextcloud": "a", "pair/novox/postgres-database/g14/umami": "b"}} raw := `{"node":"ace","module":"nextcloud","provisioning":{"templates":{"source":"x","digest":"y"},` + `"provisions":[{"provision":"postgres-database","provider":"novox","provider-module":"postgres",` + `"contributes":{"name":"nextcloud","extensions":["pg_trgm"]}}]}}` if err := bus.Put(context.Background(), AssignmentsBucket, "ace.nextcloud", []byte(raw)); err != nil { t.Fatal(err) } assign(t, bus, "g14", "umami", bind("postgres-database", "", "novox", "postgres")) if _, err := postgres(bus, v, m).Pass(context.Background()); err != nil { t.Fatal(err) } want := map[string]any{"name": "nextcloud", "extensions": []any{"pg_trgm"}} if got := m.contributed["ace.nextcloud.postgres-database"]; !reflect.DeepEqual(got, want) { t.Fatalf("the adapter was handed the contribution %v, want %v", got, want) } if got := m.contributed["g14.umami.postgres-database"]; got != nil { t.Fatalf("a consumer contributing nothing was handed %v", got) } if bytes.Contains(bus.get(BucketOf("postgres"), "ace.nextcloud.postgres-database"), []byte("pg_trgm")) { t.Fatal("a contribution is in the provider's bucket") } } // A consumer's plan entry carries where its provider is, which machine, and who the consumer is (issue 788): the // entry's values carry `at` and `from` as the binding file gives them, and its `as` is the plan's, so a module with a // slug keeps the login it has today. An entry of a plan without them is as it was. func TestAConsumersEntryCarriesAtFromAndTheAsOfItsPlan(t *testing.T) { bus, m := newStandIn(), &maker{} v := &vault{values: map[string]string{ "pair/novox/postgres-database/ace/claude-code": "a", "pair/novox/postgres-database/g14/umami": "b"}} raw := `{"node":"ace","module":"claude-code","provisioning":{"templates":{"source":"x","digest":"y"},` + `"provisions":[{"provision":"postgres-database","provider":"novox","provider-module":"postgres",` + `"at":"10.7.0.1","from":"novox","as":"mesh_ace_agent"}]}}` if err := bus.Put(context.Background(), AssignmentsBucket, "ace.claude-code", []byte(raw)); err != nil { t.Fatal(err) } assign(t, bus, "g14", "umami", bind("postgres-database", "", "novox", "postgres")) if _, err := postgres(bus, v, m).Pass(context.Background()); err != nil { t.Fatal(err) } var e Entry if err := json.Unmarshal(bus.get(BucketOf("postgres"), "ace.claude-code.postgres-database"), &e); err != nil { t.Fatal(err) } if e.Values["at"] != "10.7.0.1" || e.Values["from"] != "novox" || e.Values["port"] == nil { t.Fatalf("the entry's values are %v", e.Values) } if e.As != "mesh_ace_agent" || e.User != "mesh_ace_agent" || m.as["ace.claude-code.postgres-database"] != "mesh_ace_agent" { t.Fatalf("the entry is %+v, made as %q", e, m.as["ace.claude-code.postgres-database"]) } var plain Entry if err := json.Unmarshal(bus.get(BucketOf("postgres"), "g14.umami.postgres-database"), &plain); err != nil { t.Fatal(err) } if _, has := plain.Values["at"]; has || plain.As != "mesh_g14_umami" { t.Fatalf("an entry of a plan without them changed: %+v", plain) } } // A consumer's plan entry may carry the names the controller composed for it (issue 792): each is copied into the // entry's values under its key, over anything the provider serves under it. An entry without them is as it was. func TestAConsumersEntryCarriesTheNamesOfItsPlan(t *testing.T) { bus, m := newStandIn(), &maker{} v := &vault{values: map[string]string{ "pair/novox/postgres-database/ace/gitea": "a", "pair/novox/postgres-database/g14/umami": "b"}} raw := `{"node":"ace","module":"gitea","provisioning":{"templates":{"source":"x","digest":"y"},` + `"provisions":[{"provision":"postgres-database","provider":"novox","provider-module":"postgres",` + `"names":{"name":"git.example.org","internal-name":"git.mesh","name-web":"web.example.org"}}]}}` if err := bus.Put(context.Background(), AssignmentsBucket, "ace.gitea", []byte(raw)); err != nil { t.Fatal(err) } assign(t, bus, "g14", "umami", bind("postgres-database", "", "novox", "postgres")) if _, err := postgres(bus, v, m).Pass(context.Background()); err != nil { t.Fatal(err) } var e Entry if err := json.Unmarshal(bus.get(BucketOf("postgres"), "ace.gitea.postgres-database"), &e); err != nil { t.Fatal(err) } if e.Values["name"] != "git.example.org" || e.Values["internal-name"] != "git.mesh" || e.Values["name-web"] != "web.example.org" || e.Values["port"] == nil { t.Fatalf("the entry's values are %v", e.Values) } var plain Entry if err := json.Unmarshal(bus.get(BucketOf("postgres"), "g14.umami.postgres-database"), &plain); err != nil { t.Fatal(err) } if _, has := plain.Values["name"]; has { t.Fatalf("an entry of a plan without names changed: %+v", plain) } }