package catalogue import ( "strings" "testing" ) // A provider with one credential shares it (novox/hq ADR 0158): the offer names the own secret, the // secret says how it is taken, and a consumer's need carries the name so the plan mints its copy // from the provider's value. func TestAnOfferMayNameAnOwnSecretAsItsCredential(t *testing.T) { m, err := ParseManifest([]byte(`{"module":"downloader","version":"1", "own-secrets":{"password":{"path":"/var/lib/mesh/downloader/password","taken":"at-start"}}, "provides":[{"name":"downloader-api","credential":{"own":"password"}}], "serves":{"downloader-api":{"port":8080,"username":"admin"}}}`)) if err != nil { t.Fatal(err) } if own, shared := m.SharedCredentialOf("downloader-api"); !shared || own != "password" { t.Fatalf("the offer's credential was not read: %v %v", own, shared) } if got := m.ProvisionsSharing("password"); len(got) != 1 || got[0] != "downloader-api" { t.Fatalf("the provisions sharing the secret: %v", got) } for want, raw := range map[string]string{ "declares no such secret": `{"module":"d","version":"1","provides":[{"name":"d-api","credential":{"own":"password"}}]}`, "must say how the module takes it": `{"module":"d","version":"1","own-secrets":{"password":"/p"}, "provides":[{"name":"d-api","credential":{"own":"password"}}]}`, "names no own secret": `{"module":"d","version":"1","provides":[{"name":"d-api","credential":{"own":""}}]}`, } { if _, err := ParseManifest([]byte(raw)); err == nil || !strings.Contains(err.Error(), want) { t.Errorf("expected a refusal saying %q, got %v", want, err) } } } func sharingShelf() map[string]Manifest { return shelf( Manifest{Module: "downloader", Version: "1", Provides: []Offer{{Name: "downloader-api", Scope: ScopeMesh, Credential: &OfferCredential{Own: "password"}}}, OwnSecrets: OwnSecrets{"password": {Path: "/var/lib/mesh/downloader/password", Taken: TakenAtStart}}, Serves: map[string]map[string]any{"downloader-api": {"port": 8080, "username": "admin"}}}, Manifest{Module: "manager", Version: "1", Requires: []string{"downloader-api"}}, ) } func TestAConsumersNeedCarriesTheSharedSecretsName(t *testing.T) { // On the same machine. together, err := Resolve(sharingShelf(), []string{"downloader", "manager"}, workstation(), World{}) if err != nil { t.Fatal(err) } found := false for _, n := range together.Needs { if n.Name == "downloader-api" && n.For == "manager" { found = true if n.SharedOwn != "password" { t.Fatalf("the need on one machine does not name the shared secret: %+v", n) } } } if !found { t.Fatalf("the manager's need was not resolved: %+v", together.Needs) } // Across machines, the provider known by its module. apart, err := Resolve(sharingShelf(), []string{"manager"}, onBoth("example.tld"), World{ Offered: map[string][]Provider{"downloader-api": {{Node: "home-server", At: "home-server.internal", Module: "downloader", Serves: map[string]any{"port": 8080}}}}, }) if err != nil { t.Fatal(err) } for _, n := range apart.Needs { if n.Name == "downloader-api" && n.SharedOwn != "password" { t.Fatalf("the need across machines does not name the shared secret: %+v", n) } } }