From 90daee7fec473a9bc837399d031385156af4dd49 Mon Sep 17 00:00:00 2001 From: jochen Date: Wed, 21 Oct 2026 13:54:33 +0200 Subject: [PATCH] n8n runs its upstream image with uuid mounted and the media group joined, in place of a Dockerfile (issue 1639, ADR 0480 clauses 1, 3, 7, 8) --- modules/n8n/Dockerfile | 20 -------------------- modules/n8n/README.md | 7 ++++++- modules/n8n/module.json | 40 ++++++++++++++++++++++++++++++++-------- 3 files changed, 38 insertions(+), 29 deletions(-) delete mode 100644 modules/n8n/Dockerfile diff --git a/modules/n8n/Dockerfile b/modules/n8n/Dockerfile deleted file mode 100644 index 7d15a2bf..00000000 --- a/modules/n8n/Dockerfile +++ /dev/null @@ -1,20 +0,0 @@ -# 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::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 diff --git a/modules/n8n/README.md b/modules/n8n/README.md index c911c864..751b5f70 100644 --- a/modules/n8n/README.md +++ b/modules/n8n/README.md @@ -1,6 +1,10 @@ # n8n -The `n8n` module of the mesh catalogue: runs the container image `redis`; runs the container image `selenium/standalone-chrome`. +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. ## Files it does not know @@ -8,4 +12,5 @@ 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). diff --git a/modules/n8n/module.json b/modules/n8n/module.json index 975247fa..5ee86819 100644 --- a/modules/n8n/module.json +++ b/modules/n8n/module.json @@ -30,6 +30,14 @@ "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, + "trusted": true + } + }, "listens": [ { "name": "web", @@ -92,6 +100,13 @@ "mode": "0600", "template": "files/server.env" }, + { + "id": "uuid", + "type": "archive", + "path": "${dir:state}/uuid", + "artifact": "uuid", + "unknown": "program" + }, { "id": "net", "type": "network", @@ -119,7 +134,11 @@ "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}" ] }, { @@ -151,17 +170,22 @@ } ], "build": { - "on": [ - { - "arg": "N8N_BASE", - "image": "n8nio/n8n@sha256:4846eb2f4b874ab04cde7fc1e249d2ddaec66e9aea64439beb2972cfea88e3c0" - } - ], "artifacts": [ { "name": "server", - "kind": "image", - "from": "Dockerfile" + "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)" + } }, { "name": "files",