From 523d7846cd8c89683a14181cb607a4cc8c3e037c Mon Sep 17 00:00:00 2001 From: jochen Date: Mon, 19 Oct 2026 22:47:56 +0200 Subject: [PATCH] Fix mesh-mail-web's manifest: operators is type list, the listen word names its port number (issue 1262) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The controller refused the manifest: config.operators declared type "array" (not one of the controller's five types, novox/hq ADR 0348 §4 — the word is "list"), and the bundle's env word MESH_MAIL_WEB_LISTEN said ${port:web} (a bundle's word takes the port NUMBER a listens entry gives, novox/hq ADR 0192; mesh-controller internal/catalogue/port_into.go portsFilledInto matches it against listens[].Port, never an endpoint's label). Fixed to type "list" and ${port:8099} (the listens entry's own port). main.go and the integration harness already read/write a plain port number, so neither needed a change. manifest_test.go now asserts both: config.operators.Type == "list", and the listen word equals ${port:}; confirmed each independently fails against the old values before this fix. --- .../cmd/mesh-mail-web/manifest_test.go | 16 ++++++++++++---- modules/mesh-mail-web/module.json | 4 ++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/modules/mesh-mail-web/cmd/mesh-mail-web/manifest_test.go b/modules/mesh-mail-web/cmd/mesh-mail-web/manifest_test.go index 6f670ec3..9b7eee7f 100644 --- a/modules/mesh-mail-web/cmd/mesh-mail-web/manifest_test.go +++ b/modules/mesh-mail-web/cmd/mesh-mail-web/manifest_test.go @@ -14,6 +14,7 @@ package main import ( "encoding/json" + "fmt" "os" "path/filepath" "reflect" @@ -109,9 +110,11 @@ func TestTheManifestSaysWhatTheCodeDoes(t *testing.T) { if len(m.Listens) != 1 || m.Listens[0].Name != "web" || m.Listens[0].From != "mesh" || m.Listens[0].Protocol != "tcp" { t.Fatalf("listens %+v, want exactly one, named web, from the mesh only", m.Listens) } + // "list" is the controller's own word for a trusted array value (novox/hq ADR 0348 §4); "array" is not + // one of its five types (number, string, boolean, object, list) and the controller refuses it. op, ok := m.Config["operators"] - if !ok || op.Type != "array" || !op.Trusted || len(op.Default) != 0 { - t.Fatalf("config.operators %+v, want a trusted array defaulting to nobody", op) + if !ok || op.Type != "list" || !op.Trusted || len(op.Default) != 0 { + t.Fatalf("config.operators %+v, want a trusted list defaulting to nobody", op) } // No database, no state bucket, no writable directory beyond the account's own state dir: only the // account (a user resource, not writable), the state directory, and the two files rendered into it. @@ -161,8 +164,13 @@ func TestTheManifestSaysWhatTheCodeDoes(t *testing.T) { t.Fatalf("the bundle reads %s at %s, which does not match resource %s's path", k, a[0].Env[k], v) } } - if a[0].Env["MESH_MAIL_WEB_LISTEN"] != "${port:web}" { - t.Fatalf("MESH_MAIL_WEB_LISTEN is %q, want the web endpoint's port", a[0].Env["MESH_MAIL_WEB_LISTEN"]) + // A bundle's word is ${port:}, never the endpoint's own name + // (novox/hq ADR 0192; mesh-controller internal/catalogue/port_into.go portsFilledInto matches it against + // listens[].Port, a plain number, not a label like "web"). len(m.Listens)==1 is already checked above. + wantListen := fmt.Sprintf("${port:%d}", m.Listens[0].Port) + if a[0].Env["MESH_MAIL_WEB_LISTEN"] != wantListen { + t.Fatalf("MESH_MAIL_WEB_LISTEN is %q, want %q (the listens entry's own port number)", + a[0].Env["MESH_MAIL_WEB_LISTEN"], wantListen) } } diff --git a/modules/mesh-mail-web/module.json b/modules/mesh-mail-web/module.json index a0dd2d7f..fd928396 100644 --- a/modules/mesh-mail-web/module.json +++ b/modules/mesh-mail-web/module.json @@ -48,7 +48,7 @@ ], "config": { "operators": { - "type": "array", + "type": "list", "description": "The Keycloak identities (the ID token's preferred_username) let to sign in; nobody by default (novox/hq ADR 0440 §3).", "trusted": true, "default": [] @@ -112,7 +112,7 @@ "env": { "MESH_MAIL_WEB_OPERATORS": "${dir:state}/operators.json", "MESH_MAIL_WEB_OIDC": "${dir:state}/oidc.json", - "MESH_MAIL_WEB_LISTEN": "${port:web}" + "MESH_MAIL_WEB_LISTEN": "${port:8099}" } }, {