A provision names the engine, because a consumer is coupled to one
Provisions were named after roles: provides "database", requires "database". Nothing distinguished engines, so a module written against PostgreSQL could be matched to a provider of SQL Server, resolve as satisfied, deploy, and fail on its first query — with nothing connecting that error back to a match made elsewhere by something that believed it had done its job. The failure is in the direction that hides. Refusing on ambiguity exists precisely so this does not happen, and the generic name walked around it: with one provider of each name nothing is ambiguous, so nothing is asked. How it got in: every resolver test had exactly one provider per name, so no mismatch was expressible and none was caught. The fixtures agreed with the design — the same fault as the imagined test output in 04-ISSUES/005, at the level of a name. Refused rather than documented, because the old naming *was* the documented convention. Providing database/db/sql/sql-database is now a parse error naming what to write instead. The rule is about coupling, not specificity everywhere: route and resolver stay role-named, because a consumer genuinely cannot tell which proxy answered. novox/hq ADR 0027.
This commit is contained in:
@@ -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")
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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",
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user