diff --git a/internal/catalogue/brokered_test.go b/internal/catalogue/brokered_test.go index c404992..3a927ae 100644 --- a/internal/catalogue/brokered_test.go +++ b/internal/catalogue/brokered_test.go @@ -27,13 +27,13 @@ func onNetwork(nodes ...string) map[string][]Provider { for _, n := range nodes { out = append(out, Provider{Node: n, At: n + ".internal"}) } - return map[string][]Provider{"database": out} + return map[string][]Provider{"postgres-database": out} } func brokeredShelf() map[string]Manifest { return shelf( - Manifest{Module: "postgres", Version: "1", Provides: FromAnywhere("database")}, - Manifest{Module: "meshboard", Version: "1", Requires: []string{"database"}}, + Manifest{Module: "postgres", Version: "1", Provides: FromAnywhere("postgres-database")}, + Manifest{Module: "meshboard", Version: "1", Requires: []string{"postgres-database"}}, ) } @@ -60,7 +60,7 @@ func TestWhatAMachineTakesFromElsewhereIsRecorded(t *testing.T) { if len(got.Needs) != 1 { t.Fatalf("got %v", got.Needs) } - if got.Needs[0].Name != "database" || got.Needs[0].From != "anchor" { + if got.Needs[0].Name != "postgres-database" || got.Needs[0].From != "anchor" { t.Fatalf("got %v", got.Needs[0]) } if got.Needs[0].For != "meshboard" { @@ -99,7 +99,7 @@ func TestSayingWhichOneSettlesIt(t *testing.T) { got, err := Resolve(brokeredShelf(), []string{"meshboard"}, reachable(), World{ Offered: onNetwork("anchor", "archive"), - Pinned: map[string]string{"database": "archive"}, + Pinned: map[string]string{"postgres-database": "archive"}, }) if err != nil { t.Fatal(err) @@ -115,7 +115,7 @@ func TestBeingPointedAtAMachineThatDoesNotProvideItIsRefused(t *testing.T) { _, err := Resolve(brokeredShelf(), []string{"meshboard"}, reachable(), World{ Offered: onNetwork("anchor", "archive"), - Pinned: map[string]string{"database": "somewhere-else"}, + Pinned: map[string]string{"postgres-database": "somewhere-else"}, }) if err == nil { t.Fatal("a machine was silently given a different database from the one chosen") @@ -131,7 +131,7 @@ func TestOneProviderDoesNotOverruleAChoice(t *testing.T) { _, err := Resolve(brokeredShelf(), []string{"meshboard"}, reachable(), World{ Offered: onNetwork("anchor"), - Pinned: map[string]string{"database": "archive"}, + Pinned: map[string]string{"postgres-database": "archive"}, }) if err == nil { t.Fatal("the only database was used although another was chosen") @@ -145,9 +145,9 @@ func TestACatalogueThatDisagreesAboutScopeIsRefused(t *testing.T) { // If one module says a database is local and another says it is anywhere, the same // requirement means two things depending on which one happens to answer it. _, err := Resolve(shelf( - Manifest{Module: "postgres", Version: "1", Provides: FromAnywhere("database")}, - Manifest{Module: "sqlite", Version: "1", Provides: Offers("database")}, - Manifest{Module: "meshboard", Version: "1", Requires: []string{"database"}}, + Manifest{Module: "postgres", Version: "1", Provides: FromAnywhere("postgres-database")}, + Manifest{Module: "sqlite", Version: "1", Provides: Offers("postgres-database")}, + Manifest{Module: "meshboard", Version: "1", Requires: []string{"postgres-database"}}, ), []string{"meshboard"}, workstation(), World{}) if err == nil { t.Fatal("a catalogue that disagrees about where a database lives was accepted") @@ -200,10 +200,10 @@ func TestASiteScopedProvisionIsRefused(t *testing.T) { func boundShelf() map[string]Manifest { return shelf( - Manifest{Module: "postgres", Version: "1", Provides: FromAnywhere("database"), - Serves: map[string]map[string]any{"database": {"port": 5432, "driver": "postgres"}}}, - Manifest{Module: "meshboard", Version: "1", Requires: []string{"database"}, - Binds: map[string]string{"database": "/etc/meshboard/database.json"}}, + Manifest{Module: "postgres", Version: "1", Provides: FromAnywhere("postgres-database"), + Serves: map[string]map[string]any{"postgres-database": {"port": 5432, "driver": "postgres"}}}, + Manifest{Module: "meshboard", Version: "1", Requires: []string{"postgres-database"}, + Binds: map[string]string{"postgres-database": "/etc/meshboard/database.json"}}, ) } @@ -227,7 +227,7 @@ func TestAnAppIsToldWhereItsDatabaseIs(t *testing.T) { // Knowing it needs the anchor's database is useless to the program that needs it unless the // program is told. This is the whole point of the field. got, err := Resolve(boundShelf(), []string{"meshboard"}, reachable(), - World{Offered: map[string][]Provider{"database": {{Node: "anchor", At: "anchor.internal", + World{Offered: map[string][]Provider{"postgres-database": {{Node: "anchor", At: "anchor.internal", Serves: map[string]any{"port": 5432, "driver": "postgres"}}}}}) if err != nil { t.Fatal(err) @@ -246,7 +246,7 @@ func TestItSaysItCarriesNoCredential(t *testing.T) { // A missing field looks like a bug; a stated absence looks like a boundary. Somebody wiring // this up must not spend an afternoon looking for the password field. got, _ := Resolve(boundShelf(), []string{"meshboard"}, reachable(), - World{Offered: map[string][]Provider{"database": {{Node: "anchor", At: "anchor.internal"}}}}) + World{Offered: map[string][]Provider{"postgres-database": {{Node: "anchor", At: "anchor.internal"}}}}) told := binding(t, mustDeclare(t, got)) note, _ := told["generated"].(string) if !strings.Contains(note, "no credential") { @@ -264,7 +264,7 @@ func TestTwoMachinesThatCannotReachEachOtherAreRefused(t *testing.T) { // that reports itself configured and does not work. Said here rather than discovered as a // connection timing out. _, err := Resolve(boundShelf(), []string{"meshboard"}, workstation(), // not on the network - World{Offered: map[string][]Provider{"database": {{Node: "anchor", At: "anchor.internal"}}}}) + World{Offered: map[string][]Provider{"postgres-database": {{Node: "anchor", At: "anchor.internal"}}}}) if err == nil { t.Fatal("an app was pointed at a database it has no path to") } @@ -279,7 +279,7 @@ func TestTwoMachinesThatCannotReachEachOtherAreRefused(t *testing.T) { func TestTheProviderBeingOffTheNetworkIsAlsoRefused(t *testing.T) { // Both directions, because the failure is identical from either end and the remedy differs. _, err := Resolve(boundShelf(), []string{"meshboard"}, reachable(), - World{Offered: map[string][]Provider{"database": {{Node: "anchor"}}}}) + World{Offered: map[string][]Provider{"postgres-database": {{Node: "anchor"}}}}) if err == nil { t.Fatal("an app was pointed at a database that is not on the private network") } @@ -307,7 +307,7 @@ func TestBindingSomethingAnsweredHereWritesNothing(t *testing.T) { func TestBindingWhatYouDoNotRequireIsRefused(t *testing.T) { _, err := ParseManifest([]byte(`{"module":"app","version":"1", - "binds":{"database":"/etc/app/db.json"}}`)) + "binds":{"postgres-database":"/etc/app/db.json"}}`)) if err == nil { t.Fatal("a module was told about something it never asked for") } @@ -318,7 +318,7 @@ func TestBindingWhatYouDoNotRequireIsRefused(t *testing.T) { func TestServingWhatYouDoNotProvideIsRefused(t *testing.T) { _, err := ParseManifest([]byte(`{"module":"app","version":"1", - "serves":{"database":{"port":5432}}}`)) + "serves":{"postgres-database":{"port":5432}}}`)) if err == nil { t.Fatal("a module served something it does not provide") } diff --git a/internal/catalogue/contributes_test.go b/internal/catalogue/contributes_test.go index a8ceefc..fc0aac8 100644 --- a/internal/catalogue/contributes_test.go +++ b/internal/catalogue/contributes_test.go @@ -227,9 +227,9 @@ func TestAnEmptyContributionIsRefused(t *testing.T) { func provider() Manifest { return Manifest{Module: "postgres", Version: "1", - Provides: FromAnywhere("database"), - Receives: map[string]string{"database": "/var/lib/postgres/grants/mesh.json"}, - Grants: map[string]string{"database": "/var/lib/postgres/grants"}, + Provides: FromAnywhere("postgres-database"), + Receives: map[string]string{"postgres-database": "/var/lib/postgres/grants/mesh.json"}, + Grants: map[string]string{"postgres-database": "/var/lib/postgres/grants"}, } } @@ -241,7 +241,7 @@ func oneGrant(t *testing.T) []map[string]any { t.Fatal(err) } out, err := got.Declaration(Rendering{Grants: []Grant{{ - Provision: "database", Consumer: "workstation", From: "meshboard", + Provision: "postgres-database", Consumer: "workstation", From: "meshboard", Values: map[string]any{"name": "meshboard"}, Sealed: "c2VhbGVk", }}}) if err != nil { @@ -343,9 +343,9 @@ func TestAConsumerThatStoppedAskingIsWithdrawn(t *testing.T) { t.Fatal(err) } out, err := got.Declaration(Rendering{Grants: []Grant{ - {Provision: "database", Consumer: "still-here", From: "meshboard", + {Provision: "postgres-database", Consumer: "still-here", From: "meshboard", Values: map[string]any{"name": "meshboard"}, Sealed: "c2VhbGVk"}, - {Provision: "database", Consumer: "gone-away", Sealed: "c3RhbGU="}, + {Provision: "postgres-database", Consumer: "gone-away", Sealed: "c3RhbGU="}, }}) if err != nil { t.Fatal(err) diff --git a/internal/catalogue/manifest.go b/internal/catalogue/manifest.go index 0ecfb78..6686e17 100644 --- a/internal/catalogue/manifest.go +++ b/internal/catalogue/manifest.go @@ -68,7 +68,7 @@ func (c Claim) At() string { // making every manifest say so would bury the few that are not: // // "provides": ["shell"] -// "provides": [{"name": "database", "scope": "mesh"}] +// "provides": [{"name": "postgres-database", "scope": "mesh"}] type Offer struct { Name string `json:"name"` // Scope defaults to the node, which is where most things must be to be usable. @@ -442,6 +442,15 @@ func ParseManifest(raw []byte) (Manifest, error) { if !name.MatchString(p) { problems = append(problems, fmt.Sprintf("%q is not a usable name to provide", p)) } + if instead, generic := engineGeneric[p]; generic { + // A consumer is written against an engine, not a role (novox/hq ADR 0027). Providing + // the role means a requirement for it matches any engine, resolves as satisfied, and + // fails on the first query — with nothing pointing back at the match. + problems = append(problems, fmt.Sprintf( + "%s provides %q, which hides which engine it is: a requirement for %q would match "+ + "any of them and fail on the first query. Name the engine — %s", + m.Module, p, p, instead)) + } if s := offer.At(); s != ScopeNode && s != ScopeMesh { // Site scope is meaningful for a claim — one DHCP server per segment — and is not // yet meaningful for a provision, because nothing knows how to reach "the one at my diff --git a/internal/catalogue/naming.go b/internal/catalogue/naming.go new file mode 100644 index 0000000..7198cd8 --- /dev/null +++ b/internal/catalogue/naming.go @@ -0,0 +1,17 @@ +package catalogue + +// Provision names that say a role where the consumer is coupled to an implementation. +// +// **A consumer's code is written against PostgreSQL or against SQL Server, never against a +// database** (novox/hq ADR 0027). A requirement naming the role matches any engine, resolves as +// satisfied, deploys, and fails on the first query — with nothing connecting the error back to a +// match made elsewhere by something that thought it had done its job. +// +// Refused rather than documented, because the previous naming *was* the documented convention. +// A rule states how it is checked (novox/hq 00-META/how-we-build.md §5). +var engineGeneric = map[string]string{ + "database": "postgres-database, mssql-database, mariadb-database", + "db": "postgres-database, mssql-database, mariadb-database", + "sql": "postgres-database, mssql-database, mariadb-database", + "sql-database": "postgres-database, mssql-database, mariadb-database", +} diff --git a/internal/catalogue/naming_test.go b/internal/catalogue/naming_test.go new file mode 100644 index 0000000..617730f --- /dev/null +++ b/internal/catalogue/naming_test.go @@ -0,0 +1,39 @@ +package catalogue + +import ( + "strings" + "testing" +) + +// A provision names what the consumer is coupled to (novox/hq ADR 0027). +// +// The fault this defends against does not look like a fault: resolution succeeds, the module +// deploys, and the first query fails somewhere else entirely. Every earlier test had exactly one +// provider of each name, so no mismatch was expressible and none was caught. +func TestAModuleMayNotProvideAGenericDatabase(t *testing.T) { + for _, hidden := range []string{"database", "db", "sql", "sql-database"} { + _, err := ParseManifest([]byte(`{"module":"postgres","version":"1", + "provides":[{"name":"` + hidden + `","scope":"mesh"}]}`)) + if err == nil { + t.Fatalf("providing %q was accepted; a requirement for it matches any engine", hidden) + } + for _, want := range []string{hidden, "postgres-database", "first query"} { + if !strings.Contains(err.Error(), want) { + t.Errorf("refusing %q did not mention %q, so nobody learns what to write:\n%v", + hidden, want, err) + } + } + } +} + +// The rule is about coupling, not about specificity everywhere. Naming `route` after a particular +// proxy would be the same error in the other direction. +func TestARoleNameIsFineWhereTheConsumerCannotTellTheDifference(t *testing.T) { + for _, role := range []string{"route", "resolver", "artifact-store", "postgres-database"} { + if _, err := ParseManifest([]byte(`{"module":"m","version":"1", + "provides":[{"name":"` + role + `","scope":"mesh"}]}`)); err != nil { + t.Errorf("providing %q was refused, and it names what a consumer actually gets: %v", + role, err) + } + } +} diff --git a/internal/inventory/catalogue_test.go b/internal/inventory/catalogue_test.go index 300f081..13dbf43 100644 --- a/internal/inventory/catalogue_test.go +++ b/internal/inventory/catalogue_test.go @@ -375,29 +375,29 @@ func TestAPinSurvivesAndCanBeChanged(t *testing.T) { t.Fatal(err) } } - if err := inv.PinProvision(ctx, "user", "database", "first"); err != nil { + if err := inv.PinProvision(ctx, "user", "postgres-database", "first"); err != nil { t.Fatal(err) } // Changing the answer replaces it rather than adding a second, or a machine would be told to // use two databases and nothing would say which. - if err := inv.PinProvision(ctx, "user", "database", "second"); err != nil { + if err := inv.PinProvision(ctx, "user", "postgres-database", "second"); err != nil { t.Fatal(err) } pins, err := inv.PinsFor(ctx, "user") if err != nil { t.Fatal(err) } - if len(pins) != 1 || pins["database"] != "second" { + if len(pins) != 1 || pins["postgres-database"] != "second" { t.Fatalf("got %v", pins) } - if err := inv.UnpinProvision(ctx, "user", "database"); err != nil { + if err := inv.UnpinProvision(ctx, "user", "postgres-database"); err != nil { t.Fatal(err) } if pins, _ := inv.PinsFor(ctx, "user"); len(pins) != 0 { t.Fatalf("the choice outlived being removed: %v", pins) } // Removing something that was never said is a mistake worth reporting, not a silent success. - if err := inv.UnpinProvision(ctx, "user", "database"); err == nil { + if err := inv.UnpinProvision(ctx, "user", "postgres-database"); err == nil { t.Fatal("unpinning something nobody pinned reported success") } } @@ -412,7 +412,7 @@ func TestAPinGoesWhenTheProviderLeavesTheMesh(t *testing.T) { t.Fatal(err) } } - if err := inv.PinProvision(ctx, "consumer", "database", "provider"); err != nil { + if err := inv.PinProvision(ctx, "consumer", "postgres-database", "provider"); err != nil { t.Fatal(err) } if _, err := inv.store.Pool().Exec(ctx, `delete from node where name = 'provider'`); err != nil { diff --git a/internal/inventory/secrets_test.go b/internal/inventory/secrets_test.go index 9c70925..915cb47 100644 --- a/internal/inventory/secrets_test.go +++ b/internal/inventory/secrets_test.go @@ -54,11 +54,11 @@ func TestASecretIsMadeOnceAndKept(t *testing.T) { // Regenerating on every declaration would restart both ends on every push, and — worse — the // password a provider was told to create would never be the one its consumer was given. inv, ctx := twoNodesWithKeys(t) - first, err := inv.SecretFor(ctx, "database", "consumer", "provider") + first, err := inv.SecretFor(ctx, "postgres-database", "consumer", "provider") if err != nil { t.Fatal(err) } - second, err := inv.SecretFor(ctx, "database", "consumer", "provider") + second, err := inv.SecretFor(ctx, "postgres-database", "consumer", "provider") if err != nil { t.Fatal(err) } @@ -72,7 +72,7 @@ func TestTheStoredSecretIsNotTheSecret(t *testing.T) { // what an encrypted column does not achieve, because whoever runs the control plane can read // through it. inv, ctx := twoNodesWithKeys(t) - got, err := inv.SecretFor(ctx, "database", "consumer", "provider") + got, err := inv.SecretFor(ctx, "postgres-database", "consumer", "provider") if err != nil { t.Fatal(err) } @@ -105,7 +105,7 @@ func TestANewSealingKeyMeansANewSecret(t *testing.T) { // A node that rejoined generated a new key and can no longer open what was sealed to the old // one. Keeping the blob would deliver something unreadable for ever, reported as configured. inv, ctx := twoNodesWithKeys(t) - before, err := inv.SecretFor(ctx, "database", "consumer", "provider") + before, err := inv.SecretFor(ctx, "postgres-database", "consumer", "provider") if err != nil { t.Fatal(err) } @@ -117,7 +117,7 @@ func TestANewSealingKeyMeansANewSecret(t *testing.T) { if err := inv.RecordSealingKey(ctx, node.ID, fresh); err != nil { t.Fatal(err) } - after, err := inv.SecretFor(ctx, "database", "consumer", "provider") + after, err := inv.SecretFor(ctx, "postgres-database", "consumer", "provider") if err != nil { t.Fatal(err) } @@ -133,14 +133,14 @@ func TestANewSealingKeyMeansANewSecret(t *testing.T) { func TestRotatingReachesBothEnds(t *testing.T) { inv, ctx := twoNodesWithKeys(t) - before, err := inv.SecretFor(ctx, "database", "consumer", "provider") + before, err := inv.SecretFor(ctx, "postgres-database", "consumer", "provider") if err != nil { t.Fatal(err) } - if err := inv.RotateSecret(ctx, "database", "consumer", "provider"); err != nil { + if err := inv.RotateSecret(ctx, "postgres-database", "consumer", "provider"); err != nil { t.Fatal(err) } - after, err := inv.SecretFor(ctx, "database", "consumer", "provider") + after, err := inv.SecretFor(ctx, "postgres-database", "consumer", "provider") if err != nil { t.Fatal(err) } @@ -175,7 +175,7 @@ func TestAProviderIsToldEveryCredentialItMustCreate(t *testing.T) { t.Fatal(err) } for _, who := range []string{"consumer", "second-consumer"} { - if _, err := inv.SecretFor(ctx, "database", who, "provider"); err != nil { + if _, err := inv.SecretFor(ctx, "postgres-database", who, "provider"); err != nil { t.Fatal(err) } } @@ -206,7 +206,7 @@ func TestANodeWithNoSealingKeyCannotBeGivenASecret(t *testing.T) { t.Fatal(err) } } - _, err := inv.SecretFor(ctx, "database", "consumer", "provider") + _, err := inv.SecretFor(ctx, "postgres-database", "consumer", "provider") if err == nil { t.Fatal("a credential was made for nodes that cannot open one") } @@ -217,7 +217,7 @@ func TestANodeWithNoSealingKeyCannotBeGivenASecret(t *testing.T) { func TestSecretsGoWhenANodeLeaves(t *testing.T) { inv, ctx := twoNodesWithKeys(t) - if _, err := inv.SecretFor(ctx, "database", "consumer", "provider"); err != nil { + if _, err := inv.SecretFor(ctx, "postgres-database", "consumer", "provider"); err != nil { t.Fatal(err) } if _, err := inv.store.Pool().Exec(ctx, `delete from node where name = 'consumer'`); err != nil { @@ -333,14 +333,14 @@ func TestACredentialGoesWhenTheConsumerStopsAskingForIt(t *testing.T) { // only fires if the mesh stops asking. inv, ctx := twoNodesWithKeys(t) if err := inv.RegisterModule(ctx, catalogue.Manifest{ - Module: "meshboard", Version: "1", Requires: []string{"database"}, + Module: "meshboard", Version: "1", Requires: []string{"postgres-database"}, }, Source{}); err != nil { t.Fatal(err) } if err := inv.Assign(ctx, "consumer", "meshboard"); err != nil { t.Fatal(err) } - if _, err := inv.SecretFor(ctx, "database", "consumer", "provider"); err != nil { + if _, err := inv.SecretFor(ctx, "postgres-database", "consumer", "provider"); err != nil { t.Fatal(err) } @@ -370,7 +370,7 @@ func TestACredentialGoesWhenEitherMachineDoes(t *testing.T) { // The case that must not leave a live login behind: a machine removed from the mesh. Its // credentials go with it, and the provider stops being told to keep them. inv, ctx := twoNodesWithKeys(t) - if _, err := inv.SecretFor(ctx, "database", "consumer", "provider"); err != nil { + if _, err := inv.SecretFor(ctx, "postgres-database", "consumer", "provider"); err != nil { t.Fatal(err) } if _, err := inv.store.Pool().Exec(ctx, `delete from node where name = 'consumer'`); err != nil { @@ -464,7 +464,7 @@ func TestEveryHolderOfACredentialCanBeNamed(t *testing.T) { t.Fatal(err) } for _, consumer := range []string{"consumer", "third"} { - if _, err := inv.SecretFor(ctx, "database", consumer, "provider"); err != nil { + if _, err := inv.SecretFor(ctx, "postgres-database", consumer, "provider"); err != nil { t.Fatal(err) } } @@ -473,7 +473,7 @@ func TestEveryHolderOfACredentialCanBeNamed(t *testing.T) { t.Fatal(err) } - holders, err := inv.HoldersOf(ctx, "database", "") + holders, err := inv.HoldersOf(ctx, "postgres-database", "") if err != nil { t.Fatal(err) } @@ -481,14 +481,14 @@ func TestEveryHolderOfACredentialCanBeNamed(t *testing.T) { t.Fatalf("a holder of the credential was not named: %+v", holders) } for _, h := range holders { - if h.Provision != "database" { + if h.Provision != "postgres-database" { t.Fatalf("rotating one provision would have touched %q", h.Provision) } } // One machine's, when that is what was asked for. Rotating the other nine because one is // suspected is a great deal of disruption for one suspicion. - one, err := inv.HoldersOf(ctx, "database", "third") + one, err := inv.HoldersOf(ctx, "postgres-database", "third") if err != nil { t.Fatal(err) } @@ -500,14 +500,14 @@ func TestEveryHolderOfACredentialCanBeNamed(t *testing.T) { // And rotating gives both ends a new credential, together — the same one. func TestRotatingGivesBothEndsTheSameNewCredential(t *testing.T) { inv, ctx := twoNodesWithKeys(t) - before, err := inv.SecretFor(ctx, "database", "consumer", "provider") + before, err := inv.SecretFor(ctx, "postgres-database", "consumer", "provider") if err != nil { t.Fatal(err) } - if err := inv.RotateSecret(ctx, "database", "consumer", "provider"); err != nil { + if err := inv.RotateSecret(ctx, "postgres-database", "consumer", "provider"); err != nil { t.Fatal(err) } - after, err := inv.SecretFor(ctx, "database", "consumer", "provider") + after, err := inv.SecretFor(ctx, "postgres-database", "consumer", "provider") if err != nil { t.Fatal(err) } @@ -534,14 +534,14 @@ func TestRotatingGivesBothEndsTheSameNewCredential(t *testing.T) { if err := inv.RecordSealingKey(ctx, third.ID, key); err != nil { t.Fatal(err) } - untouched, err := inv.SecretFor(ctx, "database", "third", "provider") + untouched, err := inv.SecretFor(ctx, "postgres-database", "third", "provider") if err != nil { t.Fatal(err) } - if err := inv.RotateSecret(ctx, "database", "consumer", "provider"); err != nil { + if err := inv.RotateSecret(ctx, "postgres-database", "consumer", "provider"); err != nil { t.Fatal(err) } - again, err := inv.SecretFor(ctx, "database", "third", "provider") + again, err := inv.SecretFor(ctx, "postgres-database", "third", "provider") if err != nil { t.Fatal(err) } diff --git a/internal/link/enrol_shape_test.go b/internal/link/enrol_shape_test.go index 2724b87..58aceac 100644 --- a/internal/link/enrol_shape_test.go +++ b/internal/link/enrol_shape_test.go @@ -77,7 +77,7 @@ func TestWhatANodeSaysWhenItJoinsIsWhatThisMeshReads(t *testing.T) { t.Fatal(err) } - secret, err := inv.SecretFor(ctx, "database", request.Node, "the-other-end") + secret, err := inv.SecretFor(ctx, "postgres-database", request.Node, "the-other-end") if err != nil { t.Fatalf("nothing could be sealed to a key that arrived from a real node: %v", err) }