diff --git a/04-ISSUES/225-a-provisioner-cannot-read-the-grant-secrets-since-its-code-left-the-container/00-report.md b/04-ISSUES/225-a-provisioner-cannot-read-the-grant-secrets-since-its-code-left-the-container/00-report.md index 16435c0..1e21bfd 100644 --- a/04-ISSUES/225-a-provisioner-cannot-read-the-grant-secrets-since-its-code-left-the-container/00-report.md +++ b/04-ISSUES/225-a-provisioner-cannot-read-the-grant-secrets-since-its-code-left-the-container/00-report.md @@ -1,8 +1,8 @@ --- -status: open +status: resolved opened: 2026-10-04 located-in: [mesh-host internal/apply, mesh-controller internal/catalogue] -fixed-by: +fixed-by: mesh-controller#263 amended-design: --- @@ -73,3 +73,25 @@ their containers and made a silent fault visible as a restarting one. The dates is right once and wrong four thousand times is a message that hides its own meaning. - Which other modules' files did the runtime move leave behind? The sweep is the same question for every path the mesh writes for a module: directories, bundles, received files. + +## Resolved, 2026-10-04 + +A grant secret is composed with the account that will read it: the node's account where the +module's code is a bundle the runtime runs, its declared `secrets-owner` where it is still a +container, root where it says neither. The same rule the module's own secrets already followed, +reaching the other kind of secret the mesh writes for a module (mesh-controller#263). + +`givenTo` could not have reached these: it claims the files a bundle's *words* name, and the +harness composes a grant secret's path from the contributions file, which no word names. + +And the harness stops calling a permanent refusal a race (mesh-sdk#22, 0.1.9). After about a +minute it says so plainly, rarely rather than every five seconds, and names what to look at — +who owns the file and who the process runs as. That is the half that cost three hours. + +**How it was checked:** on the control machine, after the push — the grant secrets belong to the +operator's account, **zero `EACCES` since 12:30:10** where there had been 4330, both users were +created, and `mongodb-server` logs `Authentication succeeded` for each. + +It also uncovered [issue 232](../232-a-consumer-authenticates-against-a-database-its-user-does-not-live-in/00-report.md), +which this fault had been hiding: with no user anywhere, "not found in admin" was a complete +account of *this* issue and said nothing about the consumer asking the wrong database. \ No newline at end of file diff --git a/04-ISSUES/226-the-stores-sweep-stops-at-the-first-reference-recorded-with-an-address/00-report.md b/04-ISSUES/226-the-stores-sweep-stops-at-the-first-reference-recorded-with-an-address/00-report.md index ca4c401..b615e34 100644 --- a/04-ISSUES/226-the-stores-sweep-stops-at-the-first-reference-recorded-with-an-address/00-report.md +++ b/04-ISSUES/226-the-stores-sweep-stops-at-the-first-reference-recorded-with-an-address/00-report.md @@ -1,8 +1,8 @@ --- -status: open +status: resolved opened: 2026-10-04 located-in: [mesh-controller cmd/mesh-controller/collect.go, mesh-controller internal/inventory/collection.go] -fixed-by: +fixed-by: mesh-controller#263 amended-design: --- @@ -56,3 +56,21 @@ reports the right number while doing it, which is what made it look healthy. - Only a refusal *by the store* ends a sweep. - **How it is checked:** a sweep over records holding one address-recorded reference and one kept one collects the second; a sweep against a store that refuses stops at the first. + +## Resolved, 2026-10-04 + +Two changes, deliberately separate. + +**Normalising moved to where the provenance is known.** Every reference the sweep handles came +from a build record, so every one is the mesh's own and `Recorded` may read an address-era +reference as the kept one. Not in `LetGo` — it cannot tell `docker.io` from the mesh's store, and +an attempt to put it there was caught at once by the test that says a foreign reference is never +asked about. The guard stays strict; the records speak the one vocabulary. + +**A reference the sweep will not address is `ErrNotOurs`:** skipped, not marked collected, never +a reason to stop. Only the store refusing ends a sweep. + +**How it was checked:** the first build after the roll-out printed *"the artifact store let go of +200 artifact(s) the mesh no longer keeps — 1126 more to collect; the next build asks again"*. +Two hundred is the per-sweep bound working as intended; the backlog is falling with every build +instead of standing at 1681 for ever. \ No newline at end of file diff --git a/04-ISSUES/227-the-photo-apps-admin-client-asks-for-the-port-the-proxy-holds/00-report.md b/04-ISSUES/227-the-photo-apps-admin-client-asks-for-the-port-the-proxy-holds/00-report.md index 906b001..986197c 100644 --- a/04-ISSUES/227-the-photo-apps-admin-client-asks-for-the-port-the-proxy-holds/00-report.md +++ b/04-ISSUES/227-the-photo-apps-admin-client-asks-for-the-port-the-proxy-holds/00-report.md @@ -1,8 +1,8 @@ --- -status: open +status: resolved opened: 2026-10-04 located-in: [mesh-catalog modules/photos] -fixed-by: +fixed-by: mesh-catalog#263, mesh-controller#263 amended-design: --- @@ -42,3 +42,19 @@ gradually. is composed, rather than failing on the machine every pass. The mesh assigns ports ([ADR 0038](../../02-DECISIONS/0038-the-mesh-assigns-the-port.md)); a fixed 80 beside a proxy is a statement it could check. + +## Resolved, 2026-10-04 + +The three photo modules publish the endpoint they declare — `4001:80`, `4012:80`, `4013:80` — +so the software's own port reaches the machine at the port the mesh assigned, and nothing asks +for 80. + +**The rule, rather than three repairs.** A container may publish only a port its module declares: +the short form `"80"` means *publish what the software calls 80*, and the mesh fills in the +machine's half from the port it assigned — which it can only do for a port the module declared. +Four modules publish 80 quite safely because they declare 80. The difference is the declaration, +not the number. A catalogue-wide test in mesh-controller#263 says so, and names all three +offenders against the catalogue as it was. + +**How it was checked:** `photos-admin-client` has been up since the push, where before it failed +on every pass. \ No newline at end of file diff --git a/04-ISSUES/232-a-consumer-authenticates-against-a-database-its-user-does-not-live-in/00-report.md b/04-ISSUES/232-a-consumer-authenticates-against-a-database-its-user-does-not-live-in/00-report.md new file mode 100644 index 0000000..04d174a --- /dev/null +++ b/04-ISSUES/232-a-consumer-authenticates-against-a-database-its-user-does-not-live-in/00-report.md @@ -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.