Six modules take their secrets from files; the rest say precisely why not

From the survey of every env-file secret (ADR 0086, issue 041): amqp-ping,
minio, mongodb and grafana use the _FILE twin their software honours;
mesh-catalog and model-usage read DATABASE_URL_FILE (a file the mesh
templates, mounted where only the runtime reads it); grafana's secret files
belong to its own account. Two dead deliveries removed: a line nothing read
in amqp-email-forwarder, and mailu's secret.env on four containers that
never read it. The 25 exceptions that remain carry the surveyed reason —
convertible and awaiting a bed, convertible through a generated config file,
the application's own code, or not convertible.
This commit is contained in:
2026-09-21 12:29:25 +02:00
parent db597bcb71
commit 1a28e5aec6
26 changed files with 106 additions and 96 deletions
+11 -10
View File
@@ -50,11 +50,11 @@
"mode": "0700"
},
{
"id": "db-env",
"id": "database-url",
"type": "file",
"path": "/var/lib/mesh-catalog/db.env",
"path": "/var/lib/mesh-catalog/database.url",
"mode": "0600",
"content": "DATABASE_URL=postgresql://${bound:postgres-database:as}:${secret:postgres-database}@${bound:postgres-database:at}:${bound:postgres-database:port}/${bound:postgres-database:as}\n"
"content": "postgresql://${bound:postgres-database:as}:${secret:postgres-database}@${bound:postgres-database:at}:${bound:postgres-database:port}/${bound:postgres-database:as}\n"
},
{
"id": "runtime",
@@ -63,19 +63,20 @@
"network": "host",
"volumes": [
"/var/lib/mesh/mesh-catalog/broker:/run/secrets/broker:ro",
"/var/lib/mesh-catalog:/run/state"
"/var/lib/mesh-catalog:/run/state",
"/var/lib/mesh-catalog/database.url:/run/secrets/database-url:ro"
],
"env": {
"MESH_BROKER_FILE": "/run/secrets/broker"
"MESH_BROKER_FILE": "/run/secrets/broker",
"DATABASE_URL_FILE": "/run/secrets/database-url"
},
"env-file": [
"/var/lib/mesh-catalog/db.env"
],
"artifact": "runtime",
"restart-on": [
"db-env"
"database-url"
],
"secrets-in-environment": "the mesh's own runtime reads MESH_STORE_* from the environment; a file twin in the SDK is the per-module work of issue 041"
"env-file": [
"/var/lib/mesh-catalog/db.env"
]
}
],
"build": {
+14 -1
View File
@@ -1,3 +1,4 @@
import { readFileSync } from "node:fs";
// The module graph (novox/hq ADR 0070, ADR 0072).
//
// **This graph links module-versions to each other and knows nothing about nodes.** Which machine
@@ -138,7 +139,9 @@ export class Graph {
private constructor(private readonly pool: PgPool) {}
static fromEnv(env: NodeJS.ProcessEnv = process.env): Graph {
const url = env["DATABASE_URL"];
// As a file first (novox/hq ADR 0086): the connection string carries the password, and the
// mesh writes it where only this process reads it; the plain variable remains for a hand-run.
const url = env["DATABASE_URL"] ?? readMaybe(env["DATABASE_URL_FILE"]);
if (!url) {
throw new Error(
"no DATABASE_URL: the catalogue holds the module graph and cannot hold it in memory, " +
@@ -390,3 +393,13 @@ export class Graph {
await this.pool.end();
}
}
/** The content of a file the environment names, its line ending gone — or undefined when it names none. */
function readMaybe(path: string | undefined): string | undefined {
if (!path) return undefined;
try {
return readFileSync(path, "utf8").replace(/\r?\n$/, "");
} catch {
return undefined;
}
}