Merge pull request 'Issue 124: a consumer cannot be told a value its provider derived for it' (#127) from issue/124-a-consumer-cannot-be-told-what-its-provider-derived into main
This commit was merged in pull request #127.
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
---
|
||||
status: located
|
||||
opened: 2026-09-26
|
||||
located-in: [mesh-controller internal/catalogue/declaration.go, mesh-sdk src/provisioner, mesh-catalog modules/minio]
|
||||
fixed-by:
|
||||
amended-design:
|
||||
---
|
||||
|
||||
# 124 — A consumer cannot be told a value its provider derived for it, so it transcribes one
|
||||
|
||||
## What was observed
|
||||
|
||||
The object-store interface gives each consumer a bucket. The provider **derives** which one: it
|
||||
takes the login the mesh minted for that consumer and normalises it into a bucket name, then creates,
|
||||
checks and removes exactly that. Its own comment states the reasoning — derived from the login, so
|
||||
teardown recomputes it with nothing to persist — and it never reads the bucket a consumer's
|
||||
definition named.
|
||||
|
||||
The consumer still has to tell its own software which bucket to use. It has no way to be told, so
|
||||
all three consumers wrote the answer down by hand. Two transcribed it correctly. The third named the
|
||||
predecessor's bucket, while the key the mesh scopes for it admits only the derived one: it would have
|
||||
authenticated successfully and been refused on every object, which reads like a credential fault and
|
||||
is not one. That was found by reading, not by running, and it was filed as part of the fix.
|
||||
|
||||
## Why the value cannot arrive
|
||||
|
||||
A definition may interpolate five things: a secret, a seat, a port, a machine fact, and a **bound**
|
||||
value — what a provider said a consumer must know. Everything about the arrangement is already
|
||||
delivered that way: the endpoint, the port, the region, the login itself.
|
||||
|
||||
The bound values come from what the provider `serves`, and **`serves` is a literal block in the
|
||||
provider's definition**: the same values for every consumer. A value derived *per consumer* has no
|
||||
way into it. Nothing else can carry it either — a provisioner's contract takes the provision and
|
||||
returns nothing, so what it derived stays inside it.
|
||||
|
||||
So the mesh has a value it computed, a consumer that needs exactly that value, and no channel
|
||||
between them. The gap is not that the answer is unknown; it is that the answer cannot be passed.
|
||||
|
||||
## Why it matters beyond this instance
|
||||
|
||||
Every interface where the provider names the resource has this shape. A database provisioner that
|
||||
prefixed database names, a queue provider that scoped vhosts, an object store that derives buckets —
|
||||
each would force the consumer to reproduce the provider's rule in its own definition. That is a copy
|
||||
of somebody else's logic, kept in agreement by hand, which is the failure
|
||||
[issue 119](../119-a-module-definition-decides-where-its-files-live/00-report.md) records for paths
|
||||
and this one records for names.
|
||||
|
||||
It also shifts a rule out of the place that can enforce it. The provider knows its own naming rule
|
||||
and can refuse a bad one; a transcription in a consumer's definition is a string, and no check
|
||||
compares it to what the provider will actually create. The one wrong instance was well-formed.
|
||||
|
||||
## Open questions
|
||||
|
||||
- Should a provider be able to return consumer-visible values from provisioning — the natural
|
||||
channel, since the provider is what derived them, but it means a grant carries data the provider
|
||||
wrote rather than only data the mesh minted.
|
||||
- Or should `serves` be able to say a value is derived from the consumer's identity, with the
|
||||
mesh performing the derivation — which keeps the provider declarative, and requires the mesh to
|
||||
know normalisation rules belonging to somebody else's protocol. It already knows one: the identity
|
||||
limit is 20 characters *because* of what an object store's access key accepts.
|
||||
- Either way: should a consumer that names a resource its provider will not use be **refused** rather
|
||||
than ignored? The contributed bucket was read by nothing, and looked authoritative for months.
|
||||
- What would have caught the wrong instance? A test that resolves a consumer's grant and compares the
|
||||
bucket in its own configuration against the one the provider would create is a check that could
|
||||
exist today, for any interface, without the mechanism above.
|
||||
Reference in New Issue
Block a user