From 90eeb082effffa899aa823990fa58a3ee98cda55 Mon Sep 17 00:00:00 2001 From: jochen Date: Sat, 26 Sep 2026 19:23:13 +0200 Subject: [PATCH] Become a nox mesh module: smtp granted, the shared channel accepted MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The mailu smtp grant replaces the hand-carried mailbox credential — the module contributes account amqp-forwarder and composes its login from the binding, the de-spiegel pattern. The AMQP side stays the operator's on purpose: EMAILDELIVERY_T is a vhost external publishers share, which the consumer-owned-vhost provision deliberately cannot express, so the URL rides as an accepted secret. Built from source; the old image's registry no longer exists. --- Dockerfile | 4 +++- module.json | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 module.json diff --git a/Dockerfile b/Dockerfile index f69259f..bef7a7b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,6 @@ -FROM node:22-alpine +# The base arrives pinned from module.json's build.on. +ARG NODE_BASE +FROM ${NODE_BASE} WORKDIR /app COPY package.json ./ RUN npm install --production diff --git a/module.json b/module.json new file mode 100644 index 0000000..17a812c --- /dev/null +++ b/module.json @@ -0,0 +1,65 @@ +{ + "module": "amqp-email-forwarder", + "version": "1", + "slug": "forwarder", + "capabilities": [ + "container-runtime" + ], + "requires": [ + "smtp" + ], + "contributes": { + "smtp": { + "account": "amqp-forwarder" + } + }, + "binds": { + "smtp": "${dir:state}/smtp.json" + }, + "secrets": { + "smtp": "${dir:state}/smtp.secret" + }, + "own-secrets": { + "amqp-url": "${dir:state}/amqp-url.secret" + }, + "resources": [ + { + "id": "state", + "type": "directory", + "place": ".", + "mode": "0700" + }, + { + "id": "env", + "type": "file", + "path": "${dir:state}/forwarder.env", + "mode": "0600", + "content": "AMQP_URL=${secret:amqp-url}\nAMQP_EXCHANGE=News.TransactionalEmailing.Command\nAMQP_QUEUE=email-forwarder\nSMTP_HOST=${bound:smtp:at}\nSMTP_PORT=${bound:smtp:port}\nSMTP_USER=amqp-forwarder@${bound:smtp:domain}\nSMTP_PASSWORD=${secret:smtp}\nNOTIFY_FROM=amqp-forwarder@${bound:smtp:domain}\nNOTIFY_TO=jochen.schoubben@mediahuis.be\n" + }, + { + "id": "server", + "type": "container", + "name": "amqp-email-forwarder", + "artifact": "server", + "env-file": [ + "${dir:state}/forwarder.env" + ], + "secrets-in-environment": "the application reads AMQP_URL and SMTP_PASSWORD from the environment (app.js); converting is this repository's change. The AMQP credential is the operator's: the EMAILDELIVERY_T vhost is a channel external publishers share, which the consumer-owned-vhost amqp provision deliberately cannot express, so the mesh carries the credential as an accepted secret rather than minting one nobody else would know" + } + ], + "build": { + "on": [ + { + "arg": "NODE_BASE", + "image": "node@sha256:0a7108bf6c7bf5de370ffb1a3ed6be93d405b43ff159f681a8d18c0e2bc2e402" + } + ], + "artifacts": [ + { + "name": "server", + "kind": "image", + "from": "Dockerfile" + } + ] + } +}