Issue 232: a consumer authenticates against a database its user does not live in

Found fixing 225: with the secrets readable the provisioner created both
users at once, and photos still could not connect because it asks for admin
while its user lives in its own database. The password was never wrong — the
grant secret and the consumer's environment hash identically.

One fault wore the other's clothes: while no user existed anywhere, the
error was a complete account of 225. Worth keeping as a habit — fix the
first and look again.
This commit is contained in:
2026-10-04 12:33:57 +02:00
parent 3afe619531
commit 3f3fb99219
@@ -0,0 +1,60 @@
---
status: resolved
opened: 2026-10-04
located-in: [mesh-catalog modules/photos]
fixed-by: mesh-catalog#264
amended-design:
---
# 232 — A consumer authenticates against a database its user does not live in, and one fault hid it behind another
## What was observed
Fixing [issue 225](../225-a-provisioner-cannot-read-the-grant-secrets-since-its-code-left-the-container/00-report.md)
on the control machine, 2026-10-04. With the grant secrets readable again the provisioner created
both consumers' users at once, and one consumer still could not connect:
```
Authentication succeeded | user: mesh_novox_invoice | authDb: mesh_novox_invoice
Authentication succeeded | user: mesh_novox_photos | authDb: mesh_novox_photos
Authentication failed | user: mesh_novox_photos | authDb: admin
UserNotFound: Could not find user "mesh_novox_photos" for db "admin"
```
The provider creates each consumer's user **in that consumer's own database**, which is what the
first two lines are. `photos` asks for `admin`. Its sibling `invoicing`, against the same
provider, asks for `${bound:mongodb-database:as}` — the name the mesh gave it — and works.
The password was never the problem: the grant secret and the value in the consumer's environment
hash identically.
## Why it matters beyond this instance
**One fault wore the other's clothes.** While the provisioner could not read its secrets at all,
*no* user existed, so `UserNotFound ... for db "admin"` was a true and complete account of issue
225. Fixing 225 is what made the wrong database visible — before that, every symptom pointed at
the thing that was already broken, and a second fault behind it was indistinguishable.
That is the general shape worth keeping: **a fault that explains the symptom is not evidence
there is only one.** The check is to fix the first and look again, rather than to close both on
one explanation.
It also says something about the interface. Which database a consumer authenticates against is
part of what `mongodb-database` means, and it is spelled out by hand in each consumer. Two
consumers of one provider wrote two different answers, and only one was right; nothing compared
them. That is the shape [issue 124](../124-a-consumer-cannot-be-told-what-its-provider-derived/00-report.md)
records for a derived bucket, here for the authentication database —
[ADR 0202](../../02-DECISIONS/0202-a-provider-declares-what-it-derives-for-each-consumer.md)'s
mechanism is what would remove it, by letting the provider say it once.
## Resolved
`photos` asks for `${bound:mongodb-database:as}`, as `invoicing` already did (mesh-catalog#264).
**How it is checked:** the module is rebuilt and pushed, and `photos-server` connects — verified
on the control machine rather than inferred from the manifest.
## What this leaves open
Nothing compares two consumers' idea of one interface. The provider could serve the
authentication database as a derived value under ADR 0202 and neither consumer would state it;
that is a candidate for the next consumer of this interface, not a repair of this one.