diff --git a/02-DECISIONS/0053-a-provider-creates-the-credential-the-mesh-minted.md b/02-DECISIONS/0053-a-provider-creates-the-credential-the-mesh-minted.md index 9be49bd..b3c7bb1 100644 --- a/02-DECISIONS/0053-a-provider-creates-the-credential-the-mesh-minted.md +++ b/02-DECISIONS/0053-a-provider-creates-the-credential-the-mesh-minted.md @@ -1,5 +1,5 @@ --- -status: proposed +status: accepted date: 2026-09-05 deciders: jochen reconstructed: false @@ -93,14 +93,24 @@ consumer cannot learn is a name it cannot authenticate with. - The four current providers (redis, postgres, minio, umami) each lose their `generatePassword` + seal code and gain a `create` that takes the password it is given. Their teardown becomes "withdraw the login named `As`". -- The symmetric `seal()`/`unseal()` primitive loses its only caller. If nothing else uses it, - it leaves with the provisioner; that is checked, not assumed. -- **How this is verified:** a provider is assigned in the lab, a consumer is granted its - resource, and the consumer authenticates against the provider using only what the mesh - delivered — no `$MESH_SEAL_KEY` set anywhere, no `.credential` file written. The trail is the - consumer connecting; a provider that invented its own password fails it. This replaces the - audit-logger/redis lab beds' current use of a hand-set lab seal key, which existed only to - get the orphaned harness to start. +- The symmetric `seal()`/`unseal()` primitive loses its only caller and leaves — checked, not + assumed: nothing else in the sdk or the catalogue called it, so it is removed with the + provisioner it belonged to. +- **How this is verified:** redis is assigned as a provider in the lab, the contributions and + the unsealed password the mesh would deliver are put in its `receives` path, and a client + authenticates as that consumer with the mesh's password and gets PONG — where a provider that + invented its own password answers WRONGPASS — with `$MESH_SEAL_KEY` set nowhere and no + `.credential` file written. Proven: `provider-uses-mesh-credential` is green. + +**What this does not cover — credential provisions, not data provisions.** This decision is about a +provision whose credential is a *secret the mesh mints* — a login and password (redis, postgres, +minio). A provider that instead *generates* the thing the consumer needs, and that thing is not a +secret — umami's `analytics`, where the consumer wants back a `siteId` umami assigned — does not fit, +because a contract that returns nothing has no way to hand that data back. The seal-key fault was +never umami's (it sealed no password; it returned a public id), so removing the seal does not break +it further, and it still reconciles its sites off the mesh's contributions. But delivering +provider-generated data back to a consumer is a *return path* the mesh does not have and this +decision does not build — a separate shape, left to a separate decision. - Teardown beyond "remove the login" — data an object store leaves behind when a consumer leaves — is named by each provider's adapter, not by the harness, and is out of scope here except to say the contract must leave room for it. diff --git a/04-ISSUES/008-provider-runtime-has-no-seal-key/00-report.md b/04-ISSUES/008-provider-runtime-has-no-seal-key/00-report.md index 3583eb6..6448663 100644 --- a/04-ISSUES/008-provider-runtime-has-no-seal-key/00-report.md +++ b/04-ISSUES/008-provider-runtime-has-no-seal-key/00-report.md @@ -1,9 +1,9 @@ --- -status: open +status: resolved opened: 2026-09-04 located-in: [mesh-sdk, mesh-catalog] -fixed-by: -amended-design: +fixed-by: mesh-sdk src/provisioner rework + redis/postgres/minio/umami adapters (ADR 0053) +amended-design: 0053-a-provider-creates-the-credential-the-mesh-minted.md --- # A provider's provisioner seals with a key the mesh has no way to deliver — and does not need to @@ -107,10 +107,29 @@ not per-provider surgery, and inherited correctly by every provider after them: This is proposed as ADR 0053, which defines the corrected provider contract, for ratification. -## Open questions +## Resolution -- Does anything legitimate still use the symmetric `seal()`/`unseal()` primitive, or does it - leave with the provisioner? -- On withdrawal the mesh drops the consumer from the contributions file; is "remove the login" - the whole of teardown for every provider, or does an object store (data left behind) need a - policy the contract should name? +ADR 0053 was accepted and implemented on the branches this issue is fixed by: + +- `mesh-sdk` `src/provisioner/index.ts` now reconciles the mesh's `receives` contributions and, + per consumer, reads the mesh-minted password from the file the host unsealed, calling the + adapter to create the resource under the mesh's login. `$MESH_SEAL_KEY`, the symmetric seal, + `writeSealedCredential`, and the `*.grant.json` / `*.credential` files are gone. The symmetric + `seal()`/`unseal()` primitive had no other caller and was removed. +- The four adapters (redis, postgres, minio, umami) were re-pointed at the new contract — + `create({ as, password, values })` / `remove({ as })`, returning nothing. minio's client gained + a secret-key argument so it sets the mesh's secret rather than generating one. +- Proven in the mesh-lab: `provider-uses-mesh-credential` is green — redis creates the consumer's + login with the password the mesh minted, a client authenticates as that consumer and gets PONG, + with no seal key set anywhere. + +Two things were carved out deliberately, neither blocking: + +- **Data provisions are a separate shape.** umami's `analytics` returns a `siteId` umami + *generates*, not a secret the mesh mints, and a contract that returns nothing cannot hand that + back. ADR 0053 is scoped to credential provisions and says so; the provider→consumer return + path for generated data is left to a separate decision. umami compiles and reconciles under the + new harness; only that return is unaddressed, and it never had the seal-key fault. +- **Teardown beyond "remove the login"** — an object store's leftover data — is each adapter's to + name (minio leaves a non-empty bucket for an operator rather than deleting a consumer's data), + not the harness's.