Files
mesh-controller/examples/postgres-provisioner/where_test.go
T
jschoubben 0af3ea1acf A consumer is a module on a machine, not a machine
novox/hq 04-ISSUES/022. A credential was keyed by provision, consumer
node and provider node, so "who is asking" was answered by naming a
host. The node this mesh exists to take over runs eight modules against
one database server.

The symptom had two halves and only one was loud. The provider refused,
naming the modules and explaining they would share one credential, which
reads as a decision rather than a limit. The consumer did not refuse: it
resolved cleanly, wrote one module's credential file and left the others
absent — a service that starts and cannot authenticate, with nothing
saying why. That is 021 again on a different axis.

Three modules wanting one database produced one need, carrying whichever
module mentioned it first, because the resolution walk is a work-list
over names. The fan-out now happens in one place, after the walk. The
record path already did this correctly and said why: a consumer here is
a module on a machine. It is the same rule.

Downstream: the secret's key gains the consuming module, the grant file
is named after both halves, needs are matched by provision and module
rather than provision alone, and the provisioners name the role and the
access key after the module. The refusal in ContributionsTo is gone
because there is nothing left to refuse.

Worth stating plainly: without that refusal, gitea's login would have
opened keycloak's database. From the provisioner's side it created
exactly what it was asked to create.

Existing secrets are discarded rather than backfilled. They cannot say
which module they were for, and a secret is remade and delivered to both
ends on the next push — so this costs one rotation and invents nothing.

Also guards the role name against PostgreSQL's 63-byte truncation, which
is a notice rather than an error and would reintroduce exactly this
collision at a length nobody tests.

Three faults injected — the fan-out removed, needs matched by name
alone, the grant file named after the machine — each caught.
2026-09-01 02:40:09 +02:00

86 lines
3.2 KiB
Go

package main
import (
"os"
"path/filepath"
"strings"
"testing"
)
// The password comes from a file, because that is how the mesh delivers one.
//
// A provisioner told to take a superuser password from an environment variable needs somebody to
// read the sealed file and pass it in — a person in the middle of the one path that exists so
// there is not one. It is also the difference between a credential in a file and one in a process
// listing: `docker inspect` prints environment.
func TestTheSuperuserPasswordComesFromTheFileTheMeshWrote(t *testing.T) {
path := filepath.Join(t.TempDir(), "superuser")
if err := os.WriteFile(path, []byte("the-sealed-one\n"), 0o600); err != nil {
t.Fatal(err)
}
t.Setenv("MESH_PROVISION_POSTGRES", "postgres://postgres@127.0.0.1:5433/postgres?sslmode=disable")
t.Setenv("MESH_PROVISION_PASSWORD_FILE", path)
where, err := connectionString()
if err != nil {
t.Fatal(err)
}
if !strings.Contains(where, "the-sealed-one") {
t.Fatalf("the password the mesh wrote is not in the connection: %s", where)
}
if !strings.Contains(where, "127.0.0.1:5433") || !strings.Contains(where, "sslmode=disable") {
t.Fatalf("the rest of the connection was lost: %s", where)
}
}
// An empty file connects as nobody and is refused by the database three layers away, as an
// authentication problem with no cause anybody changed.
func TestAnEmptyPasswordFileIsRefusedHere(t *testing.T) {
path := filepath.Join(t.TempDir(), "superuser")
if err := os.WriteFile(path, []byte("\n"), 0o600); err != nil {
t.Fatal(err)
}
t.Setenv("MESH_PROVISION_POSTGRES", "postgres://postgres@127.0.0.1:5433/postgres")
t.Setenv("MESH_PROVISION_PASSWORD_FILE", path)
if _, err := connectionString(); err == nil {
t.Fatal("a provisioner with no password reported one")
}
}
// And a provisioner somebody runs by hand still works with the URL alone.
func TestAConnectionWithNoPasswordFileIsLeftAlone(t *testing.T) {
t.Setenv("MESH_PROVISION_POSTGRES", "postgres://postgres:typed@127.0.0.1:5433/postgres")
t.Setenv("MESH_PROVISION_PASSWORD_FILE", "")
where, err := connectionString()
if err != nil {
t.Fatal(err)
}
if where != "postgres://postgres:typed@127.0.0.1:5433/postgres" {
t.Fatalf("the connection was rewritten when it should have been left alone: %s", where)
}
}
func TestAProvisionerWithNoDatabaseSaysSo(t *testing.T) {
t.Setenv("MESH_PROVISION_POSTGRES", "")
t.Setenv("MESH_PROVISION_PASSWORD_FILE", "")
if _, err := connectionString(); err == nil {
t.Fatal("a provisioner that does not know which database it owns reported one")
}
}
// PostgreSQL cuts an identifier at 63 bytes and says so only as a notice, so two consumers whose
// role names agree that far would quietly become one login — 022 again, at a length nobody tests.
func TestARoleNameTooLongToBeDistinctIsRefused(t *testing.T) {
if err := usableRole("mesh_anchor_gitea"); err != nil {
t.Fatalf("an ordinary name was refused: %v", err)
}
long := "mesh_" + strings.Repeat("n", 40) + "_" + strings.Repeat("m", 40)
err := usableRole(long)
if err == nil {
t.Fatal("a role name PostgreSQL would shorten was accepted")
}
if !strings.Contains(err.Error(), "share the login") {
t.Errorf("the refusal does not say what goes wrong: %v", err)
}
}