needs is now own-secrets, named for whose it is
It sat beside `secrets` — where a *provision's* credential lands on a consumer. Both were name-to-path, both held something secret, and the names distinguished them not at all. Reaching for the wrong one parsed cleanly and failed somewhere else entirely, which is the shape of fault this whole design exists to prevent, sitting in the manifest format. The axis that separates them is not how secret they are — both are — but whose. `secrets` is keyed by the provision it is for and belongs to a relationship with another machine. `own-secrets` is keyed by a name the module chose and belongs to nobody else. A manifest using the old name is told the new one rather than refused with "unknown field": whoever wrote it knew what they meant, and the mesh knows what it is called now. An invented key is still refused as one rather than guessed at. Found by auditing the 19 manifest fields for whether any could be mistaken for another. This was the only pair that could — and while checking it, a second instance of the same collision turned up one layer down: `Manifest.Needs` and `Resolution.Needs` were different concepts sharing a name in Go. The rename separates those too.
This commit is contained in:
@@ -14,7 +14,7 @@ import (
|
||||
func needy() Manifest {
|
||||
return Manifest{
|
||||
Module: "postgres", Version: "1",
|
||||
Needs: map[string]string{"superuser": "/var/lib/mesh/postgres/superuser"},
|
||||
OwnSecrets: map[string]string{"superuser": "/var/lib/mesh/postgres/superuser"},
|
||||
Resources: []map[string]any{
|
||||
{"id": "store", "type": "container", "name": "mesh-postgres", "image": "postgres@sha256:x"},
|
||||
},
|
||||
@@ -62,7 +62,7 @@ func TestADeclaredNeedThatWasNotMadeIsRefused(t *testing.T) {
|
||||
|
||||
func TestANeedIsAnAbsolutePath(t *testing.T) {
|
||||
_, err := ParseManifest([]byte(`{"module":"postgres","version":"1",
|
||||
"needs":{"superuser":"superuser.txt"}}`))
|
||||
"own-secrets":{"superuser":"superuser.txt"}}`))
|
||||
if err == nil {
|
||||
t.Fatal("a relative path was accepted")
|
||||
}
|
||||
@@ -74,7 +74,7 @@ func TestANeedIsAnAbsolutePath(t *testing.T) {
|
||||
func TestAModuleMayNeedSeveralThings(t *testing.T) {
|
||||
// A password and a token, say. Telling them apart is the module's business, not the mesh's.
|
||||
m := needy()
|
||||
m.Needs["replication"] = "/var/lib/mesh/postgres/replication"
|
||||
m.OwnSecrets["replication"] = "/var/lib/mesh/postgres/replication"
|
||||
got, _ := Resolve(shelf(m), []string{"postgres"}, reachable(), World{})
|
||||
out, err := got.Declaration(Rendering{Needed: map[string]map[string]string{
|
||||
"postgres": {"superuser": "b25l", "replication": "dHdv"},
|
||||
@@ -92,3 +92,33 @@ func TestAModuleMayNeedSeveralThings(t *testing.T) {
|
||||
t.Fatalf("two needs did not land as two secrets: %v", seen)
|
||||
}
|
||||
}
|
||||
|
||||
// A manifest written against the old name is told what the field became.
|
||||
//
|
||||
// `needs` and `secrets` were both name-to-path and differed only in whose secret it was, so
|
||||
// reaching for the wrong one parsed cleanly and failed somewhere else entirely. Refusing the old
|
||||
// name with "unknown field" would be correct and unhelpful: whoever wrote it knew what they meant,
|
||||
// and the mesh knows what it is called now.
|
||||
func TestAManifestUsingTheOldNameIsToldTheNewOne(t *testing.T) {
|
||||
_, err := ParseManifest([]byte(
|
||||
`{"module":"postgres","version":"1","needs":{"superuser":"/var/lib/superuser"}}`))
|
||||
if err == nil {
|
||||
t.Fatal("a manifest using the old name was accepted, so two fields now mean one thing")
|
||||
}
|
||||
for _, want := range []string{"needs", "own-secrets"} {
|
||||
if !strings.Contains(err.Error(), want) {
|
||||
t.Fatalf("the refusal does not mention %q: %v", want, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// And an ordinary unknown key is still refused as one, rather than being guessed at.
|
||||
func TestAnInventedKeyIsNotTreatedAsARename(t *testing.T) {
|
||||
_, err := ParseManifest([]byte(`{"module":"postgres","version":"1","nonsense":{}}`))
|
||||
if err == nil {
|
||||
t.Fatal("an invented key was accepted")
|
||||
}
|
||||
if strings.Contains(err.Error(), "is now called") {
|
||||
t.Fatalf("an invented key was reported as a rename: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user