Node 25 refuses an IP address as the TLS server name, and the module reaches its server on
loopback, so every connection failed on the live machines. The certificate is trusted either way.
The mesh-mssql container goes with its Dockerfile (and the sqlcmd it fetched), build bases and bus credential. The client speaks TDS through the mssql driver its package.json names, inlined into the bundle by the builder (ADR 0198 §4): one session per call as one sqlcmd invocation was, FOR JSON rendering rows exactly as before, the consumer's password checked as a bound parameter. A caller's statement still runs only as the reader login (issue 193); the one-line rule and -x guarded against sqlcmd's own commands and variable substitution, which no longer stand between the caller and the server. The server is reached on loopback at the port the machine published (${port:1433}). The reader test drives a fake session in place of a fake sqlcmd.
Proven on a throwaway server: as the administrator a caller's $(SQLCMDPASSWORD) returned
the sa password, and a line beginning ':!!' ran a program in the tools container. The
statement now runs as mesh_mssql_reader (CONNECT ANY DATABASE, SELECT ALL USER SECURABLES),
with substitution off (-x), after the module's own text on the first line, and a line break
is refused. go-sqlcmd v1.10.0 is installed at a pinned digest: the image never had sqlcmd,
so every mssql tool failed with spawn sqlcmd ENOENT.
ALTER USER ... WITH LOGIN runs only when the user's SID is not the
login's, so an already-mapped user is left alone. The provisioner
enables a mailbox through its own method; the password tool an
operator uses keeps changing the password only.
create re-enables what holds refuses (mssql login, mosquitto client,
mailu mailbox, gitea user) and clears an expired postgres password, so
no disabled account loops. mssql and mongodb checks take the password
from the environment, never argv; mosquitto_ctrl failures no longer
repeat -P. mosquitto reads 'could not ask' as an error, not absence.
mailu checks existence and enabled only: its imap passdb cannot verify
a password. mssql checks the user's SID; gitea pages teams at 50.
holds() for postgres, mssql, mongodb, minio, lavinmq, mosquitto, mailu
and gitea, so the harness makes again a login the backend lost (hq issue
120). Each checks the mesh's password as the consumer presents it, or
compares it read-only, and returns false only when the backend says the
credential is absent or wrong; an unreachable backend throws.
Mirrors the proven catalog patterns field-for-field:
- lidarr -> the Servarr twin of radarr/sonarr (API v1, artist content); no
provisioner (it is a consumer app).
- mongodb -> postgres shape: mongodb-database provider, provisioner mints a
per-consumer db+user (ADR 0053), client shells to mongosh (no npm driver,
the psql convention).
- mssql -> postgres shape: mssql-database provider, sqlcmd client.
- mosquitto -> redis shape: mqtt-topic provider via the Dynamic Security
plugin, deliberately avoiding hal's password_file (that file is nox issue
011 exactly); provisioner mints a per-consumer MQTT client+role.
All four typecheck (strict, NodeNext) against the built @novox/mesh-sdk, and
their service images are digest-pinned to resolved registry digests. The
mesh-runtime-<mod> images keep the all-zeros placeholder the pipeline pins,
as postgres/redis do, and must bundle each module's CLI (mongosh/sqlcmd/
mosquitto_ctrl) as mesh-runtime-postgres bundles psql.
Not yet lab-verified: each module lists in-code what an integration test must
prove (auth model, provisioner reconcile, mosquitto dynsec bootstrap ordering).
Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF