Commit Graph
337 Commits
Author SHA1 Message Date
jschoubben 770c9f6a78 Merge pull request 'mongodb: its data directory is placed, not stated' (#100) from feat/mongodb-dir-is-placed into main 2026-09-26 16:03:36 +00:00
jschoubben 5427118614 mongodb: its data directory is placed, not stated
The mesh resolves it to <root>/mongodb/data — where the granted
databases already sit. The provider's own state, grants and the mesh's
plumbing stay stated.
2026-09-26 18:03:25 +02:00
jschoubben 53765335cf Merge pull request 'portainer: its data directory is placed, not stated' (#99) from feat/portainer-dir-is-placed into main 2026-09-26 16:02:42 +00:00
jschoubben 5fd2ed9686 portainer: its data directory is placed, not stated
The mesh resolves it to <root>/portainer/data — where the 16M of
endpoints and users already sit. A textual no-op on this node.
2026-09-26 18:02:25 +02:00
jschoubben f7887d706d Merge pull request 'only-office: its directories are placed, not stated' (#98) from feat/only-office-dirs-are-placed into main 2026-09-26 16:01:43 +00:00
jschoubben d6dd21a091 only-office: its directories are placed, not stated
Seven data directories drop their paths; the mesh resolves each to
<root>/only-office/<id>, which is exactly where the data already sits —
a textual no-op on this node, and the first module speaking ADR 0112's
vocabulary. The module root and the mesh's own state stay stated.
2026-09-26 18:01:31 +02:00
jschoubben a844701577 Merge pull request 'Module data lives in /var/lib, now that nothing is mid-cutover' (#97) from feat/module-data-lives-in-var-lib into main 2026-09-26 14:47:37 +00:00
jschoubben 50a99f022c Module data lives in /var/lib, now that nothing is mid-cutover
The /services paths were the adopted-node pattern doing its job: take
replaced containers over the predecessor's data without moving a byte
(gitea set it — 'its data never moved'). With every cutover done the
exception has no reason left, and the operator called it: a nox
module's world is /var/lib/<module>, data included. Six modules
repathed; mssql keeps its /services path deliberately — it is still
held, HAL-run, and moves at its own take. Both trees are one
filesystem, so each move is a rename.
2026-09-26 16:47:24 +02:00
jschoubben 382a44621e Merge pull request 'A bucket is the one the mesh derives, and the photos module named another' (#96) from fix/a-bucket-is-the-one-the-mesh-derives into main 2026-09-26 14:46:30 +00:00
jochen ddb67fc095 A bucket is the one the mesh derives, and the photos module named another
The provisioner derives a consumer's bucket from the login the mesh minted — 'derived from the
login, so teardown recomputes it with nothing to persist' — and never reads the bucket a manifest
contributed. Three modules contributed one anyway, and the value was decorative in two and wrong in
the third: photos told its container MINIO_BUCKET=photos, the predecessor's bucket, while its minted
key is scoped to mesh-novox-photos. Deployed as it stood, it would have authenticated and then been
denied on every object.

photos now names the bucket the mesh actually provisions, and the contributed bucket is gone from
all three: a value nothing reads, that reads as though it decides.

Verified against the live store before changing anything: the derived names are the populated ones —
mesh-novox-ncloud (77,886 objects, 174.9 GiB), mesh-novox-photos and mesh-novox-invoice. Nothing has
to move.
2026-09-26 16:46:10 +02:00
jschoubben 78595e4db3 Merge pull request 'lavinmq: the broker TLS directory is the operator's, read by whoever needs it' (#95) from fix/the-broker-tls-directory-is-the-operators into main 2026-09-26 14:12:45 +00:00
jschoubben 37634de1e3 lavinmq: the broker TLS directory is the operator's, read by whoever needs it
The controller now accesses /var/lib/mesh-broker-tls (mesh-controller
#54) and the push refused whole: lavinmq declared the directory as an
owned resource, and shared data is the operator's, owned by no module
(ADR 0051). lavinmq only ever reads the certs — genesis laid them down
— so it declares a read access like the controller does, and the
directory belongs to nobody.
2026-09-26 16:12:29 +02:00
jschoubben 36c5f87130 Merge pull request 'route-adapter: write a body limit as the predecessor's buffering middleware' (#94) from feat/a-route-may-limit-the-body-it-carries into main 2026-09-26 14:02:03 +00:00
jochen b2e39eb2cd route-adapter: write a body limit as the predecessor's buffering middleware
The adapter skips what its one file shape cannot say. A body limit is the exception: the predecessor
has a buffering middleware and served its own registry name with exactly it, so this is written
rather than skipped, named after the router so the two halves cannot drift.

A limit that is not a whole positive number of bytes takes the route with it. Written without the
limit, the predecessor would carry what the module said not to carry and this module would report
success. Silence stays silence — no middleware, the predecessor's default.
2026-09-26 16:01:23 +02:00
jschoubben 3d73c9f54e Merge pull request 'nextcloud: real mesh module, MariaDB→PostgreSQL, S3 via _FILE secrets' (#59) from feat/nextcloud-module-postgres-migration into main 2026-09-26 13:06:32 +00:00
jschoubben fb95eb6e46 Merge main 2026-09-26 15:06:11 +02:00
jschoubben 4d715f8b73 Merge pull request 'minio: the real 4-node/8-drive erasure-coded cluster, both public routes, verified live on novox' (#58) from feat/minio-real-cluster-not-single-node into main 2026-09-26 13:05:57 +00:00
jochen afe8aae826 Merge main
# Conflicts:
#	modules/minio/module.json
2026-09-26 15:05:40 +02:00
jschoubben fa91be4941 Merge pull request 'postgres: declare the data directory's real owner; keycloak: use the port template' (#55) from fix/postgres-owner-and-keycloak-port-template into main 2026-09-26 13:05:10 +00:00
jschoubben 87f73dce6a Merge main 2026-09-26 15:04:47 +02:00
jschoubben fc5ccdfe2a Merge pull request 'mailu: one WEBMAIL_ADDRESS, the mesh's container name' (#93) from fix/one-webmail-address into main 2026-09-26 13:04:44 +00:00
jschoubben 4489e56935 mailu: one WEBMAIL_ADDRESS, the mesh's container name
The env block carried the key twice — mailu-webmail from #79's address
sweep, and a stray =webmail further down that survived it. Last write
wins in an env file, so the front resolved a name that answers nowhere
on the mesh's network and 502'd every logged-in webmail request. Latent
since the cutover: the SSO redirect the checks watched never touches
the upstream; the operator's first real login did.
2026-09-26 15:04:32 +02:00
jschoubben 08e947e4c8 Merge pull request 'The npm registry is a seat gitea holds, and gitea holds the git seat a build's source can live on' (#69) from feat/seats-are-a-closed-set into main 2026-09-26 12:31:10 +00:00
jschoubben 7fb9dd0254 Merge main 2026-09-26 14:29:28 +02:00
jschoubben 420d05e8dd Merge pull request 'mailu certifies itself, take two — the fall-through is now a behaviour' (#92) from fix/mailu-certifies-itself-take-two into main 2026-09-26 12:27:56 +00:00
jschoubben 6769e66c82 mailu certifies itself, take two — the fall-through is now a behaviour
Take one (#90) died on two real edge bugs, both fixed and pinned by
tests in mesh-controller (#66: autocert 404s unknown tokens itself;
#67: the internal authority 403s every public name before the token
lookup). The challenge path verified end to end reaching mailu's own
nginx before this flip.
2026-09-26 14:27:45 +02:00
jschoubben 15b35b53db Merge pull request 'mailu: back to the copied cert — the edge's fall-through is a belief, not a behaviour' (#91) from fix/mailu-back-to-cert-while-the-fallthrough-is-fixed into main 2026-09-26 12:19:17 +00:00
jschoubben 6177565741 mailu: back to the copied cert — the edge's fall-through is a belief, not a behaviour
The letsencrypt flavor served certbot's April-expired state to live IMAPS
users within minutes: autocert's HTTPHandler answers 404 itself for
tokens it does not hold and never consults the fallback for challenge
paths, so mailu's own client cannot answer through the path-scoped
route. cert flavor (valid to Nov 27) until route-proxy's handler
actually falls through.
2026-09-26 14:19:05 +02:00
jschoubben 6b2ea0972a Merge pull request 'mailu certifies itself: the edge passes unknown ACME tokens through now' (#90) from fix/mailu-certifies-itself into main 2026-09-26 12:15:24 +00:00
jschoubben a978b53d1c mailu certifies itself: the edge passes unknown ACME tokens through now
PR #82 set TLS_FLAVOR=cert as the honest interim while the predecessor's
proxy owned /.well-known/acme-challenge outright. route-proxy took port
80 today and its handler passes unknown tokens through to routed paths
by design — the one line #82 promised, made now. The copied cert (valid
to Nov 27) stays on disk untouched; mailu's own certbot takes over from
here.
2026-09-26 14:15:12 +02:00
jschoubben 7501c1db9e Merge pull request 'portainer: serve its public name, hold its real data, run the image the machine runs' (#89) from fix/portainer-serves-its-name into main 2026-09-26 01:46:24 +00:00
jschoubben 00ada1e9f7 portainer: serve its public name, hold its real data, run the image the machine runs
The manifest predated the working deployment on three axes: it declared a
data directory the running portainer never used (taking it would have
started empty), pinned an image digest the machine has moved past (issue
099), and contributed no route while portainer.novox.be rides a traefik
container label today. Now: the predecessor's portainer_data path, the
running image's digest, 9090:9000 kept as the predecessor's machine port
with the route contribution naming it, and 9443 kept for the runtime
sidecar's own TLS conversation.
2026-09-26 03:46:11 +02:00
jschoubben 67b443d5ad Merge pull request 'only-office: pin the machine side of its port' (#88) from fix/only-office-pins-its-machine-port into main 2026-09-26 01:44:59 +00:00
jschoubben a2da2e4910 only-office: pin the machine side of its port
A bare '80' tried to bind the node's port 80 — the edge's — instead of
auto-allocating. 9070 is the predecessor's number and the one the route
contribution already names.
2026-09-26 03:44:47 +02:00
jschoubben bcb9ca8f93 Merge pull request 'invoicing: MONGO_DB says the granted database's name' (#87) from fix/invoicing-names-its-database into main 2026-09-26 01:34:09 +00:00
jschoubben 2409afda60 invoicing: MONGO_DB says the granted database's name
The app reads MONGO_DB (default 'invoicing') for every operation and
uses the URL only to connect — listCollections ran against a database
the granted user cannot see. Same fault and same fix as photos' MONGO_DB,
found by the API's own logs at take.
2026-09-26 03:34:00 +02:00
jschoubben 511200ed9c Merge pull request 'invoicing: the photos lessons, applied before its window' (#86) from fix/invoicing-learns-the-photos-lessons into main 2026-09-26 01:15:38 +00:00
jschoubben b704bf5ad8 invoicing: the photos lessons, applied before its window
The mongo credential authenticates against its own database and the
database is the granted one (mesh_novox_invoice), not the contributed
name the provisioner ignores. Same for the store: the key is sealed to
the derived bucket (mesh-novox-invoice) — the data mirrors in during the
window, the ncloud/photos pattern. And the api gets the route
contribution it always needed: invoicing-api.novox.be is today a traefik
container label, invisible to every file survey, and it must be a grant
before the edge can ever flip.
2026-09-26 03:15:26 +02:00
jschoubben 142d65c52a Merge pull request 'mongodb: the server container is mongodb-server, not the predecessor's name' (#85) from fix/mongodb-coexists-with-the-predecessor into main 2026-09-26 00:37:51 +00:00
jschoubben ccb6e7500e mongodb: the server container is mongodb-server, not the predecessor's name
The adopted node still runs the predecessor's mongo container, and it must
keep running: invoicing points at novox.be:27017 and is not migrating in
this window. A module container named 'mongo' would be held at assign and
would replace the predecessor at take, cutting invoicing off its database.
The mesh's server coexists instead — fresh data directory, its own name,
auto-allocated machine port — and the predecessor retires with its last
consumer.
2026-09-26 01:37:41 +02:00
jschoubben bbda88c13b Merge pull request 'Every credential provider says whether it still holds a consumer (hq issue 120)' (#84) from fix/120-redis-says-what-it-holds into main 2026-09-25 23:31:28 +00:00
jochen 620b47d309 mssql remaps a user only when orphaned; mailu's operator tool no longer re-enables
ALTER USER ... WITH LOGIN runs only when the user's SID is not the
login's, so an already-mapped user is left alone. The provisioner
enables a mailbox through its own method; the password tool an
operator uses keeps changing the password only.
2026-09-26 01:30:15 +02:00
jochen 6fd93afc6c Review fixes: holds and create agree, and no password leaves a check
create re-enables what holds refuses (mssql login, mosquitto client,
mailu mailbox, gitea user) and clears an expired postgres password, so
no disabled account loops. mssql and mongodb checks take the password
from the environment, never argv; mosquitto_ctrl failures no longer
repeat -P. mosquitto reads 'could not ask' as an error, not absence.
mailu checks existence and enabled only: its imap passdb cannot verify
a password. mssql checks the user's SID; gitea pages teams at 50.
2026-09-26 01:24:32 +02:00
jochen 0cb0f814b4 Every credential provider says whether it still holds a consumer
holds() for postgres, mssql, mongodb, minio, lavinmq, mosquitto, mailu
and gitea, so the harness makes again a login the backend lost (hq issue
120). Each checks the mesh's password as the consumer presents it, or
compares it read-only, and returns false only when the backend says the
credential is absent or wrong; an unreachable backend throws.
2026-09-26 01:09:52 +02:00
jochen 3d271f72ea redis: say whether it still holds a consumer's ACL user
The server keeps ACL users in memory only, so a restart forgets every
consumer while the provisioner keeps running (hq issue 120). holds()
checks ACL GETUSER for the user, enabled, with the mesh's password, so
the harness makes a forgotten user again. Needs mesh-sdk 0.1.1.
2026-09-26 00:53:13 +02:00
jschoubben 76ca479f37 Merge pull request 'mailu: the queue is root's and traversable, which is postfix's own convention' (#83) from fix/the-queue-is-traversable into main 2026-09-25 22:17:54 +00:00
jschoubben a055334c9b mailu: the queue is root's and traversable, which is postfix's own convention
The declared 0700 was applied at take and broke mail quietly: postfix's
master runs as root but pickup and smtpd drop to uid postfix, and a
spool root they cannot traverse is a maildrop they cannot scan and a
rewrite socket they cannot open — auth succeeded and MAIL FROM hung.
0755 root is exactly what postfix's own set-permissions makes of
/var/spool/postfix. Fixed live by chmod first; declared here so the
next push stops undoing it.
2026-09-26 00:17:41 +02:00
jschoubben d5b169b6b6 Merge pull request 'mailu: cert flavor while the predecessor's proxy owns the challenge path' (#82) from fix/mailu-tls-cert-behind-the-predecessors-proxy into main 2026-09-25 22:11:26 +00:00
jschoubben 8ecc5a7249 mailu: cert flavor while the predecessor's proxy owns the challenge path
letsencrypt was the aspiration and cannot work yet, proven live: the
predecessor's own ACME machinery owns /.well-known/acme-challenge on
port 80 outright (unknown tokens get its 404) and its entrypoint
redirect owns every other path — the hand-authored passthrough never
matched anything, which is why mailu's certbot state had quietly
expired in April while the copied files carried the name. cert flavor
serves those files (valid to Nov 27). Mailu certifying itself becomes
possible the day route-proxy takes port 80, whose handler falls through
unknown tokens by design — that flip is one line here, made then.
2026-09-26 00:11:11 +02:00
jschoubben 29f00f33a5 Merge pull request 'automx: the seed writes the schema 2021.6 reads' (#81) from fix/automx-seed-knows-prio into main 2026-09-25 22:06:36 +00:00