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:
@@ -39,11 +39,11 @@
|
||||
"mode": "0700"
|
||||
},
|
||||
{
|
||||
"id": "db-env",
|
||||
"id": "database-url",
|
||||
"type": "file",
|
||||
"path": "/var/lib/model-usage/db.env",
|
||||
"path": "/var/lib/model-usage/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",
|
||||
@@ -53,15 +53,16 @@
|
||||
"network": "host",
|
||||
"volumes": [
|
||||
"/var/lib/mesh/model-usage/broker:/run/secrets/broker:ro",
|
||||
"/var/lib/model-usage:/run/state"
|
||||
"/var/lib/model-usage:/run/state",
|
||||
"/var/lib/model-usage/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/model-usage/db.env"
|
||||
],
|
||||
"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"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
// The vendor-neutral usage store (novox/hq ADR 0054). ONE table holds BOTH grains — licence and
|
||||
// session — which differ only in `consumer`; a reading is one row `(licence, consumer, period,
|
||||
// metric, value)` plus its `raw` vendor payload. The store keeps the LATEST reading per
|
||||
@@ -47,7 +48,10 @@ export class UsageStore {
|
||||
/** Build a store from the resolved environment — DATABASE_URL is the granted postgres connection,
|
||||
* templated into the module's env-file from the mesh's binding (umami's DATABASE_URL precedent). */
|
||||
static fromEnv(env: NodeJS.ProcessEnv = process.env): UsageStore {
|
||||
return new UsageStore(new Pool({ connectionString: requireEnv("DATABASE_URL", env) }));
|
||||
// As a file first (novox/hq ADR 0086): the connection string carries the password.
|
||||
const url = env["DATABASE_URL"] ?? readMaybe(env["DATABASE_URL_FILE"]);
|
||||
if (!url) throw new Error("DATABASE_URL_FILE (or DATABASE_URL) is not set — model-usage cannot reach its database");
|
||||
return new UsageStore(new Pool({ connectionString: url }));
|
||||
}
|
||||
|
||||
/** Create the one table if it is not there. Run once by the migrate entry before the consumer
|
||||
@@ -84,3 +88,13 @@ export class UsageStore {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user