Keep n8n on its own Dockerfile: since ADR 0487 a module may ship one, and the move to the upstream image only added a config value and a uuid mount (the operator, 2026-10-22)
mesh/repo-check head 68183ee4413d merged into trunk b7b9f2a3da78 beside mesh-controller#433@707bfba4 — pass: THE CHANGE ALTERS ITS OWN CHECK (merge-check.s…
mesh/check failed: unit: clipmenu/cmd/clipmenu-tools.TestTheLauncherWaitsQuietlyWhileAnotherClipmenudHoldsTheLock: manifest_test.go:199: the launcher …
mesh/merge-gate head 68183ee4413d merged into trunk 7bf63b0ac597 — pass: group feat/r4d composed: every machine composes with the change as it did without …
mesh/delivery delivered
mesh/delivery-group group feat/r4d delivered: every member is delivered

This commit is contained in:
2026-10-22 11:47:44 +02:00
parent cff5ed46b7
commit 68183ee441
3 changed files with 29 additions and 39 deletions
+20
View File
@@ -0,0 +1,20 @@
# n8n with what its workflows reach for beyond the upstream image.
#
# The base is named, not pinned here (novox/hq issue 044): module.json's `build.on` declares N8N_BASE
# as the upstream image by digest, and the mesh hands the build its own copy (ADR 0097).
ARG N8N_BASE
FROM ${N8N_BASE}
USER root
# - `media` (GID 2000), with `node` in it: the shared media library is group-writable by the
# operator's media group, and a workflow files downloads into it. A container resource cannot add
# a supplementary group, so the image's own /etc/group carries it. 2000 is the operator's media
# group today; novox/hq 153 proposes reading it from the accessed data (${access:<id>:gid}).
# - uuid, pinned to the version the workflows were written against: Code nodes require() it
# (NODE_FUNCTION_ALLOW_EXTERNAL=*), and a Code node can only require what is installed.
RUN apk add --no-cache shadow \
&& groupadd -g 2000 media \
&& usermod -aG media node \
&& npm install -g uuid@14.0.1
USER node
+1 -6
View File
@@ -1,10 +1,6 @@
# n8n
The `n8n` module of the mesh catalogue: runs the upstream image `n8nio/n8n` by digest with the `uuid` package mounted into it (ADR 0480 clauses 1, 3, 7 and 8); runs the container image `redis`; runs the container image `selenium/standalone-chrome`.
- The `server` container no longer comes from a Dockerfile. Its program is the upstream image's, bit for bit the one the module built on before (digest `4846eb2f...`; the running container reports release 1.71.3).
- `uuid` 14.0.1, which Code nodes `require`, is fetched once by its pinned sha256 from the package registry and mounted read-only at `/usr/local/lib/node_modules/uuid` (where `npm install -g` put it in the image the module built).
- The server joins the media library's group as a supplementary group, `groups` from the config key `media-gid`; the key has no default, so a machine that does not say it refuses n8n.
The `n8n` module of the mesh catalogue: runs the container image `redis`; runs the container image `selenium/standalone-chrome`.
## Files it does not know
@@ -12,5 +8,4 @@ Each directory or archive this module declares says how it treats a file it did
- `${dir:state}`: everything in it is the program's; the mesh moves nothing out (ADR 0422 §2).
- `${dir:data}`: everything in it is the program's; the mesh moves nothing out (ADR 0422 §2).
- `${dir:state}/uuid`: everything in it is the program's; the mesh moves nothing out (ADR 0422 §2).
- `${dir:cache}`: everything in it is the program's; the mesh moves nothing out (ADR 0422 §2).
+8 -33
View File
@@ -30,15 +30,6 @@
"mode": "read-write"
}
],
"config": {
"media-gid": {
"type": "number",
"description": "The number of the group that owns the media library on this machine, which the server joins as a supplementary group so a workflow can file into the library (novox/hq ADR 0480 clause 7). Set per machine; until the container takes it from the media library itself (issue 1618) nothing writes a default, so a machine that does not say it refuses n8n by name.",
"minimum": 1,
"required": true,
"trusted": true
}
},
"listens": [
{
"name": "web",
@@ -101,13 +92,6 @@
"mode": "0600",
"template": "files/server.env"
},
{
"id": "uuid",
"type": "archive",
"path": "${dir:state}/uuid",
"artifact": "uuid",
"unknown": "program"
},
{
"id": "net",
"type": "network",
@@ -135,11 +119,7 @@
"volumes": [
"${dir:data}:/home/node/.n8n",
"${dir:state}/n8n-database.secret:/run/secrets/database:ro",
"${dir:state}/uuid:/usr/local/lib/node_modules/uuid:ro",
"${access:media}:/media-library"
],
"groups": [
"${config:media-gid}"
]
},
{
@@ -171,22 +151,17 @@
}
],
"build": {
"on": [
{
"arg": "N8N_BASE",
"image": "n8nio/n8n@sha256:4846eb2f4b874ab04cde7fc1e249d2ddaec66e9aea64439beb2972cfea88e3c0"
}
],
"artifacts": [
{
"name": "server",
"kind": "upstream",
"from": "n8nio/n8n@sha256:4846eb2f4b874ab04cde7fc1e249d2ddaec66e9aea64439beb2972cfea88e3c0"
},
{
"name": "uuid",
"kind": "archive",
"url": "https://registry.npmjs.org/uuid/-/uuid-14.0.1.tgz",
"sha256": "e062c57ed120ea135478f305da04802bf69eab23fbc0ca2bae6989b6855390c4",
"version": "14.0.1",
"within": "package",
"names-on-purpose": {
"registry.npmjs.org": "the npm registry publishes the uuid package there; the build seat fetches it once, by its pinned sha256 (novox/hq ADR 0316 §2, ADR 0480 §8)"
}
"kind": "image",
"from": "Dockerfile"
},
{
"name": "files",