Files
mesh-lab/provisioners
jschoubben e7f4a49e40 A grant file and a provisioned login name the module too
novox/hq 04-ISSUES/022: a consumer is a module on a machine, not a
machine. The mesh now writes <node>.<module>.secret and the provisioners
name the role and the access key after both.

The fixtures here write what the mesh writes, so they move with it —
that is the whole point of them, and a fixture that kept the old shape
would agree with the bug rather than catch it.

The object-store assertions are the ones that mattered most: one store
holds every bucket behind one endpoint, so isolation is a policy rather
than a property. One access key per machine meant every module on a node
shared it, and the policy confining each consumer to its own bucket
confined none of them.
2026-09-01 02:45:40 +02:00
..

Provisioners

The half that makes a credential real.

The mesh generates a password, seals it to the machine that must accept it, and never holds the value — so it cannot tell PostgreSQL, or MinIO, or a broker, to start accepting it. Something on that machine reads what arrived and makes it true. That something is a provisioner, and it belongs to the module that ships the software, not to the mesh.

What the mesh owns is the contract. A provider module declares:

{
  "provides": [{"name": "database", "scope": "mesh"}],
  "receives": {"database": "/var/lib/postgres/grants/mesh.json"},
  "grants":   {"database": "/var/lib/postgres/grants"}
}

and is then given, by the host, from an ordinary declaration:

mesh.json every consumer, what it asked for, and where its credential is
<node>.<module>.secret one consumer's password, alone in the file, sealed in transit and written in plain by the host. Named after both, because a consumer is a module on a machine and a node routinely runs several (novox/hq 04-ISSUES/022)

Two files rather than one because the mesh discarded the plaintext and cannot compose a document containing it. The consequence is a good one: the readable half stays readable, and the secret half changes only when the secret does.

A provisioner reconciles; it is not told what changed. It runs after every declaration and must reach the same state from wherever it starts. That means, in order:

  1. every consumer in the manifest has what it asked for, with the password it was given — set every time, not only on creation, or a rotation reports success and changes nothing
  2. everything this provisioner made that is no longer asked for is removed. A consumer that goes away otherwise leaves a working login behind for ever, and nothing says so

Step 2 is the half usually missing, and it is the same rule the host follows about removing what it declared and no longer declares.

The reference implementation lives in mesh-control/examples/postgres-provisioner, because that is where the contract is defined and where the language is already set up to read it. The lab's job is the other half: raising a real PostgreSQL and proving that what the mesh delivered becomes a login that works, a rotation that takes effect, and a revocation that bites.

Set MESH_LAB_PROVISIONER to a built one to run those.