Files
mesh-controller/examples/postgres-provisioner/where_test.go
T
jschoubben 122680b554 A consumer can write its own connection string
novox/hq 04-ISSUES/023. A consumer was given its password, the address,
the port and where its credential lives, and still could not connect —
the user name was invented by the provisioner and recorded nowhere, and
the rest sat in a JSON binding that a program reading KEY=value cannot
use.

Both halves have the same cause: the mesh knew something and did not say
it.

**Who a consumer is, said once.** The provisioner used to derive
mesh_<node>_<module> and that string existed nowhere else — not in the
control plane, not in the binding, and above all not at the consumer,
which has to present it. Now the mesh derives it once and sends it to
both ends, so they agree by construction rather than by two conventions
that were the same on the day they were written. The provisioners refuse
to invent one if the mesh says nothing, because falling back to a name
of their own would create a role the consumer would never guess and
everything would report success.

**Bound values reach the file that needs them.** ${bound:provision:key}
is the symmetric twin of the sealed placeholder, and simpler: these
values are not secret, so the control plane fills them in before sending
and the host gains no field and learns no format. It stays
name-agnostic — at, as and from are true of any provision, and every
other key comes from what the provider said it serves.

The asymmetry it removes was backwards. The secret is the hard case,
because the mesh must not be able to read it, and the secret was the
part that already arrived.

Keycloak and Gitea now produce complete connections, asserted from the
manifests on disk rather than from fixtures: every part filled, no
placeholder surviving as a value, and the password still a hole only the
host can close. Three faults injected, each caught.
2026-09-01 03:03:07 +02:00

110 lines
4.4 KiB
Go

package main
import (
"os"
"path/filepath"
"strings"
"testing"
"github.com/novox/mesh-control/internal/catalogue"
)
// 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)
}
}
// The prefix this provisioner removes by is the prefix the mesh names by.
//
// **Two definitions on purpose.** A provisioner is a separate program and anyone may write one, so
// the prefix is part of the contract rather than a symbol to import — the same reason the grant
// file's shape is written down rather than shared. But a contract with two copies and no check is
// a contract until somebody edits one: if the mesh named `nox_` and this removed `mesh_`, every
// login it created would be permanent, and nothing would report anything at all.
func TestTheMarkAgreesWithWhatTheMeshNamesBy(t *testing.T) {
if mark != catalogue.IdentityPrefix {
t.Fatalf(
"this provisioner removes what begins with %q and the mesh names things %q, so it "+
"would never remove anything it made", mark, catalogue.IdentityPrefix)
}
}
// And a name the mesh would produce is one this provisioner accepts.
func TestWhatTheMeshNamesIsUsableAsARole(t *testing.T) {
if err := usableRole(catalogue.ConsumerIdentity("home-server", "keycloak")); err != nil {
t.Fatalf("the mesh named a consumer and this cannot make a role for it: %v", err)
}
}