Capture mesh-catalog at feat/r4g (2246ccc4) with the templates its manifests name and its predefined.json, and lay the copy out as a repository's root

The catalogue's manifests moved their content into template files and fall back to predefined keys, so a copy of
module.json alone no longer passes the catalogue's own check; the bus's Dockerfile is gone from the catalogue.
This commit is contained in:
2026-10-23 16:24:14 +02:00
parent 68c1220e87
commit 5ccc87f4d0
455 changed files with 12335 additions and 1333 deletions
@@ -0,0 +1,2 @@
INITIAL_ADMIN_PW=${secret:admin}
API_TOKEN=${secret:api-token}
@@ -0,0 +1 @@
{}
@@ -0,0 +1,5 @@
DB_FLAVOR=postgresql
DB_HOST=${bound:postgres-database:at}:${bound:postgres-database:port}
DB_USER=${bound:postgres-database:as}
DB_NAME=${bound:postgres-database:as}
DB_PW=${secret:postgres-database}
@@ -0,0 +1,78 @@
ADMIN_ADDRESS=mailu-admin
ANTISPAM_ADDRESS=mailu-antispam
ANTIVIRUS_ADDRESS=mailu-antivirus
IMAP_ADDRESS=mailu-imap
SMTP_ADDRESS=mailu-smtp
FRONT_ADDRESS=mailu-front
WEBMAIL_ADDRESS=mailu-webmail
WEBDAV_ADDRESS=mailu-webdav
REDIS_ADDRESS=mailu-redis
PORTS=25,80,443,465,993,995,4190,110,143,587
DOMAIN=${config:domain}
HOSTNAMES=${bound:route:name-web}
POSTMASTER=admin
SITENAME=${config:sitename}
WEBSITE=${config:website}
TLS_FLAVOR=letsencrypt
SUBNET=192.168.203.0/24
COMPOSE_PROJECT_NAME=mailu
ANTIVIRUS=clamav
WEBMAIL=roundcube
WEBDAV=radicale
FETCHMAIL_ENABLED=True
FETCHMAIL_DELAY=600
ADMIN=true
WEB_ADMIN=/admin
WEB_WEBMAIL=/webmail
WEBROOT_REDIRECT=/webmail
API=true
WEB_API=/api
AUTH_RATELIMIT_IP=6000/hour
AUTH_RATELIMIT_USER=1000/day
CREDENTIAL_ROUNDS=12
PASSWORD_SCHEME=PBKDF2
DISABLE_STATISTICS=True
MESSAGE_SIZE_LIMIT=50000000
MESSAGE_RATELIMIT=200/day
RECIPIENT_DELIMITER=+
POSTFIX_MYNETWORKS=127.0.0.0/8 [::1]/128
RELAYNETS=
RELAYHOST=
REJECT_UNLISTED_RECIPIENT=
DB_FLAVOR=postgresql
INITIAL_ADMIN_ACCOUNT=admin
INITIAL_ADMIN_DOMAIN=${config:domain}
INITIAL_ADMIN_MODE=ifmissing
SMTP_PORT=25
SMTPS_PORT=465
SUBMISSION_PORT=587
POP3_PORT=110
POP3S_PORT=995
IMAP_PORT=143
IMAPS_PORT=993
HTTP_PORT=7080
HTTPS_PORT=7443
AUTOMX_PORT=4243
AMX_SMTP_ADDRESS=${bound:route:name-web}
AMX_SMTP_PORT=587
AMX_IMAP_ADDRESS=${bound:route:name-web}
AMX_IMAP_PORT=143
AMX_MAIL_DOMAINS=${config:domain}
DMARC_RUA=admin
DMARC_RUF=admin
LETSENCRYPT_SHORTCHAIN=True
TZ=Etc/UTC
LOG_LEVEL=INFO
WELCOME=false
REAL_IP_HEADER=X-Real-IP
REAL_IP_FROM=${config:proxy-address}
COMPRESSION=
COMPRESS_LEVEL=
COMPRESSION_LEVEL=
BIND_ADDRESS4=127.0.0.1
BIND_ADDRESS6=::1
MAILU_VERSION=1.9
DOCKER_ORG=mailu
DOCKER_PREFIX=
WELCOME_SUBJECT=Welcome to your new email account
WELCOME_BODY=Welcome to your new email account, if you can read this, then it is configured properly!
@@ -0,0 +1 @@
SECRET_KEY=${secret:secret-key}
@@ -5,6 +5,10 @@
"policy": "record",
"why": "people's mail: any change to how its containers are declared recreates them together in one send, and the mail is down for everyone until they are up again — a person chooses the moment (hq ADR 0242, issue 295)"
},
"unhealthy": {
"severity": "urgent",
"why": "while mailu is broken, mail is refused or stuck for everyone with a mailbox here (hq ADR 0355, issue 687)"
},
"capabilities": [
"container-runtime"
],
@@ -56,6 +60,19 @@
"api-token": "${dir:state}/api-token.secret"
}
},
"tools": [
"mailu_list_users",
"mailu_create_user",
"mailu_change_password",
"mailu_delete_user",
"mailu_list_aliases",
"mailu_create_alias",
"mailu_delete_alias",
"mailu_list_domains",
"mailu_read_mail",
"mailu_search_mail",
"mailu_health"
],
"emits": [
"user.created",
"user.deleted",
@@ -198,12 +215,6 @@
"class": "rebuildable",
"why": "certificates, issued again"
},
{
"id": "automx",
"path": "${dir:data-automx}",
"class": "rebuildable",
"why": "client autoconfiguration, written again"
},
{
"id": "fetchmail",
"path": "${dir:data-fetchmail}",
@@ -231,136 +242,188 @@
}
}
},
"config": {
"domain": {
"type": "string",
"description": "The mail domain Mailu serves, such as example.org: its first mail domain, the postmaster's and the one consumers send as; the operator's, with no default (novox/hq ADR 0112).",
"trusted": true,
"required": true
},
"proxy-address": {
"type": "string",
"description": "The address of the reverse proxy in front of Mailu, whose X-Real-IP header Mailu believes; the operator's, with no default.",
"trusted": true,
"required": true
},
"sitename": {
"type": "string",
"description": "The name Mailu's web pages show for the mail service; the operator's, with no default.",
"trusted": true,
"required": true
},
"website": {
"type": "string",
"description": "The address of the website Mailu's web pages link to, as a URL; the operator's, with no default.",
"trusted": true,
"required": true
},
"url": {
"type": "string",
"description": "The address the module's tools reach Mailu's API at, as a URL; empty leaves them to MESH_MAILU_URL.",
"trusted": true,
"default": ""
},
"container": {
"type": "string",
"description": "The name of the container holding Mailu's mailboxes, which the module's tools read mail in; empty is mailu-imap.",
"trusted": true,
"default": ""
}
},
"resources": [
{
"id": "mesh-state",
"type": "directory",
"mode": "0700",
"place": "mesh"
"place": "mesh",
"unknown": "program"
},
{
"id": "state",
"type": "directory",
"mode": "0700",
"place": "."
"place": ".",
"unknown": "program"
},
{
"id": "grants",
"type": "directory",
"mode": "0700"
},
{
"id": "data-automx",
"type": "directory",
"mode": "0700"
"mode": "0700",
"unknown": "program"
},
{
"id": "config-env",
"type": "file",
"path": "${dir:state}/mailu.env",
"mode": "0644",
"content": "ADMIN_ADDRESS=mailu-admin\nANTISPAM_ADDRESS=mailu-antispam\nANTIVIRUS_ADDRESS=mailu-antivirus\nIMAP_ADDRESS=mailu-imap\nSMTP_ADDRESS=mailu-smtp\nFRONT_ADDRESS=mailu-front\nWEBMAIL_ADDRESS=mailu-webmail\nWEBDAV_ADDRESS=mailu-webdav\nREDIS_ADDRESS=mailu-redis\nPORTS=25,80,443,465,993,995,4190,110,143,587\nDOMAIN=${setting:domain}\nHOSTNAMES=${bound:route:name-web}\nPOSTMASTER=admin\nSITENAME=${setting:sitename}\nWEBSITE=${setting:website}\nTLS_FLAVOR=letsencrypt\nSUBNET=192.168.203.0/24\nCOMPOSE_PROJECT_NAME=mailu\nANTIVIRUS=clamav\nWEBMAIL=roundcube\nWEBDAV=radicale\nFETCHMAIL_ENABLED=True\nFETCHMAIL_DELAY=600\nADMIN=true\nWEB_ADMIN=/admin\nWEB_WEBMAIL=/webmail\nWEBROOT_REDIRECT=/webmail\nAPI=true\nWEB_API=/api\nAUTH_RATELIMIT_IP=6000/hour\nAUTH_RATELIMIT_USER=1000/day\nCREDENTIAL_ROUNDS=12\nPASSWORD_SCHEME=PBKDF2\nDISABLE_STATISTICS=True\nMESSAGE_SIZE_LIMIT=50000000\nMESSAGE_RATELIMIT=200/day\nRECIPIENT_DELIMITER=+\nPOSTFIX_MYNETWORKS=127.0.0.0/8 [::1]/128\nRELAYNETS=\nRELAYHOST=\nREJECT_UNLISTED_RECIPIENT=\nDB_FLAVOR=postgresql\nINITIAL_ADMIN_ACCOUNT=admin\nINITIAL_ADMIN_DOMAIN=${setting:domain}\nINITIAL_ADMIN_MODE=ifmissing\nSMTP_PORT=25\nSMTPS_PORT=465\nSUBMISSION_PORT=587\nPOP3_PORT=110\nPOP3S_PORT=995\nIMAP_PORT=143\nIMAPS_PORT=993\nHTTP_PORT=7080\nHTTPS_PORT=7443\nAUTOMX_PORT=4243\nAMX_SMTP_ADDRESS=${bound:route:name-web}\nAMX_SMTP_PORT=587\nAMX_IMAP_ADDRESS=${bound:route:name-web}\nAMX_IMAP_PORT=143\nAMX_MAIL_DOMAINS=${setting:domain}\nDMARC_RUA=admin\nDMARC_RUF=admin\nLETSENCRYPT_SHORTCHAIN=True\nTZ=Etc/UTC\nLOG_LEVEL=INFO\nWELCOME=false\nREAL_IP_HEADER=X-Real-IP\nREAL_IP_FROM=${setting:proxy-address}\nCOMPRESSION=\nCOMPRESS_LEVEL=\nCOMPRESSION_LEVEL=\nBIND_ADDRESS4=127.0.0.1\nBIND_ADDRESS6=::1\nMAILU_VERSION=1.9\nDOCKER_ORG=mailu\nDOCKER_PREFIX=\nWELCOME_SUBJECT=Welcome to your new email account\nWELCOME_BODY=Welcome to your new email account, if you can read this, then it is configured properly!\n"
"template": "files/mailu.env"
},
{
"id": "secret-env",
"type": "file",
"path": "${dir:state}/secret.env",
"mode": "0600",
"content": "SECRET_KEY=${secret:secret-key}\n"
"template": "files/secret.env"
},
{
"id": "database-env",
"type": "file",
"path": "${dir:state}/database.env",
"mode": "0600",
"content": "DB_FLAVOR=postgresql\nDB_HOST=${bound:postgres-database:at}:${bound:postgres-database:port}\nDB_USER=${bound:postgres-database:as}\nDB_NAME=${bound:postgres-database:as}\nDB_PW=${secret:postgres-database}\n"
"template": "files/database.env"
},
{
"id": "admin-env",
"type": "file",
"path": "${dir:state}/admin.env",
"mode": "0600",
"content": "INITIAL_ADMIN_PW=${secret:admin}\nAPI_TOKEN=${secret:api-token}\n"
"template": "files/admin.env"
},
{
"id": "data-certs",
"type": "directory",
"mode": "0700"
"mode": "0700",
"unknown": "program"
},
{
"id": "data-data",
"type": "directory",
"mode": "0700"
"mode": "0700",
"unknown": "program"
},
{
"id": "data-dkim",
"type": "directory",
"mode": "0700"
"mode": "0700",
"unknown": "program"
},
{
"id": "data-mail",
"type": "directory",
"mode": "0700"
"mode": "0700",
"unknown": "program"
},
{
"id": "data-mailqueue",
"type": "directory",
"mode": "0755"
"mode": "0755",
"unknown": "program"
},
{
"id": "data-filter",
"type": "directory",
"mode": "0700"
"mode": "0700",
"unknown": "program"
},
{
"id": "data-clamav",
"type": "directory",
"mode": "0700"
"mode": "0700",
"unknown": "program"
},
{
"id": "data-redis",
"type": "directory",
"mode": "0700"
"mode": "0700",
"unknown": "program"
},
{
"id": "data-webmail",
"type": "directory",
"mode": "0700"
"mode": "0700",
"unknown": "program"
},
{
"id": "data-dav",
"type": "directory",
"mode": "0700"
"mode": "0700",
"unknown": "program"
},
{
"id": "data-fetchmail",
"type": "directory",
"mode": "0700"
"mode": "0700",
"unknown": "program"
},
{
"id": "data-overrides-nginx",
"type": "directory",
"mode": "0700"
"mode": "0700",
"unknown": "program"
},
{
"id": "data-overrides-dovecot",
"type": "directory",
"mode": "0700"
"mode": "0700",
"unknown": "program"
},
{
"id": "data-overrides-postfix",
"type": "directory",
"mode": "0700"
"mode": "0700",
"unknown": "program"
},
{
"id": "data-overrides-rspamd",
"type": "directory",
"mode": "0700"
"mode": "0700",
"unknown": "program"
},
{
"id": "data-overrides-roundcube",
"type": "directory",
"mode": "0700"
"mode": "0700",
"unknown": "program"
},
{
"id": "net",
@@ -371,7 +434,7 @@
"id": "resolver",
"type": "container",
"name": "mailu-resolver",
"image": "ghcr.io/mailu/unbound@sha256:3a0fdfb364a63f4f9259526e013c1ef40f5f14de3621ce1560804b3a5909584a",
"image": "ghcr.io/mailu/unbound@sha256:2c037bc5c988b5c0ab7e1b6e6ffa762e14ba1e45c96281ac87f8b9be8eee8b6e",
"health": {
"kind": "runtime"
},
@@ -443,7 +506,12 @@
"name": "mailu-smtp",
"image": "ghcr.io/mailu/postfix@sha256:e2e49f39e53b80eac9e7a2f18d9df11edeb4914fd62dbba89b3155e8e034f62e",
"health": {
"kind": "runtime"
"kind": "tool",
"tool": "mailu_health",
"interval": "60s",
"timeout": "30s",
"looks": 3,
"grace": "120s"
},
"network": "mailu",
"env-file": [
@@ -560,7 +628,12 @@
"name": "mailu-front",
"image": "ghcr.io/mailu/nginx@sha256:36f98897cd1bc9d27628bbb4e04bdf60147af2ec7507d6da77f002c4f256896d",
"health": {
"kind": "runtime"
"kind": "exec",
"command": "curl -m3 -skfLo /dev/null http://127.0.0.1:10204/health && kill -0 $(cat /run/dovecot/master.pid) && python3 -c \"import smtplib; s = smtplib.SMTP('127.0.0.1', 25, timeout=5); s.ehlo('health'); s.quit()\" && openssl x509 -checkend 1209600 -noout -in /certs/letsencrypt/live/mailu/nginx-chain.pem",
"interval": "60s",
"timeout": "15s",
"looks": 3,
"grace": "120s"
},
"network": "mailu",
"env-file": [
@@ -591,14 +664,29 @@
"type": "file",
"path": "${dir:mesh-state}/config.json",
"mode": "0600",
"content": "{}\n",
"template": "files/config.json",
"takes-config": ["domain", "proxy-address", "sitename", "website", "url", "container"],
"merge": "json"
},
{
"id": "program-automx",
"type": "archive",
"path": "${dir:state}/automx",
"artifact": "automx",
"unknown": "program"
},
{
"id": "automx",
"type": "container",
"name": "mailu-automx",
"artifact": "automx",
"artifact": "alpine",
"health": {
"kind": "http",
"endpoint": "autoconfig",
"path": "/",
"status": 200,
"body": "Show Thunderbird-style"
},
"network": "mailu",
"env-file": [
"${dir:state}/mailu.env"
@@ -607,17 +695,18 @@
"4243"
],
"volumes": [
"${dir:data-automx}:/data"
"${dir:state}/automx:/opt/mesh:ro"
],
"args": [
"/opt/mesh/automx"
],
"restart-on": [
"program-automx",
"config-env"
]
}
],
"build": {
"on": [
{
"arg": "PYTHON_BASE",
"image": "python@sha256:25f3cfeaceca14921366af4d1240b56457ef46273bdb508c7b0e8f469f6fd228"
}
],
"artifacts": [
{
"name": "code",
@@ -637,14 +726,28 @@
"MESH_MAILU_URL": "http://127.0.0.1:${port:8080}/api/v1",
"MESH_MAILU_API_KEY_FILE": "${dir:state}/api-token.secret",
"MESH_MAILU_IMAP_CONTAINER": "mailu-imap",
"MESH_MAILU_SMTP_CONTAINER": "mailu-smtp",
"MESH_MAILU_CONFIG_FILE": "${dir:mesh-state}/config.json",
"MESH_RECEIVES": "${dir:grants}/mesh.json"
}
},
{
"name": "automx",
"kind": "image",
"from": "automx/Dockerfile"
"kind": "bundle",
"language": "go",
"system": "alpine",
"from": "cmd/automx",
"binary": "automx"
},
{
"name": "alpine",
"kind": "upstream",
"from": "alpine@sha256:28bd5fe8b56d1bd048e5babf5b10710ebe0bae67db86916198a6eec434943f8b"
},
{
"name": "files",
"kind": "archive",
"from": "files"
}
]
},
@@ -661,7 +764,7 @@
"serves": {
"smtp": {
"port": 587,
"domain": "${setting:domain}"
"domain": "${config:domain}"
}
},
"receives": {
@@ -673,7 +776,7 @@
"jails": [
{
"name": "mailu-front",
"failregex": "^.*(?:imap|pop3|submission|managesieve)-login: .*\\(auth failed, \\d+ attempts(?: in \\d+ secs)?\\):.*rip=<HOST>(?:,|$)",
"failregex": "^.*(?:imap|pop3|submission|managesieve)-login: .*\\(auth failed, \\d+ attempts(?: in \\d+ secs)?\\):.*rip=<HOST>(?:,|$)\n ^.*client login failed: \"AUTH not supported\" while in http auth state, client: <HOST>, server: \\S+:25,",
"jail": "backend = systemd\njournalmatch = CONTAINER_NAME=mailu-front\nport = smtp,submission,submissions,imap,imaps,pop3,pop3s\nmaxretry = 3\nfindtime = 1d\nbantime = 1d"
}
]