From 5973d41966955db87e9c1f4843c32b8a2b9b1adf Mon Sep 17 00:00:00 2001 From: jochen Date: Tue, 8 Sep 2026 18:43:48 +0200 Subject: [PATCH] umami: read the admin password from its mounted secret file MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The whole-mesh dry-run found umami's runtime crash-looping "admin password is not set": its `admin` own-secret is mounted at /run/secrets/admin, but the client read the bare env UMAMI_ADMIN_PASSWORD, which nothing sets. Same shape as the six tool-runtime credential fixes — read the mounted file first (MESH_UMAMI_ADMIN_PASSWORD_FILE), falling back to the env. (photos and mailu remain deeper conversion jobs — a stub app image and a full Mailu config env — not credential-wiring, tracked separately.) Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF --- modules/umami/client.ts | 14 +++++++++++++- modules/umami/module.json | 3 ++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/modules/umami/client.ts b/modules/umami/client.ts index 4ef410c..17fea1e 100644 --- a/modules/umami/client.ts +++ b/modules/umami/client.ts @@ -2,6 +2,18 @@ // changes when umami's API does (novox/hq ADR 0039). Both this module's tools and its provisioner // import it; nothing outside umami does. +import { readFileSync } from "node:fs"; + +/** Read a secret from the file the mesh mounted it at, if the pointing env is set. */ +function readSecret(path: string | undefined): string | undefined { + if (!path) return undefined; + try { + return readFileSync(path, "utf8").trim() || undefined; + } catch { + return undefined; + } +} + export interface Website { id: string; name: string; @@ -23,7 +35,7 @@ export class UmamiClient { static fromEnv(env: NodeJS.ProcessEnv = process.env): UmamiClient { const url = env.MESH_PROVISION_UMAMI_URL ?? env.UMAMI_URL; const username = env.UMAMI_USERNAME ?? "admin"; - const password = env.UMAMI_ADMIN_PASSWORD; + const password = readSecret(env.MESH_UMAMI_ADMIN_PASSWORD_FILE) ?? env.UMAMI_ADMIN_PASSWORD; if (!url || !password) { throw new Error("UMAMI url or admin password is not set — umami's own code cannot reach it"); } diff --git a/modules/umami/module.json b/modules/umami/module.json index e18e025..a9bd185 100644 --- a/modules/umami/module.json +++ b/modules/umami/module.json @@ -110,7 +110,8 @@ ], "env": { "MESH_BROKER_FILE": "/run/secrets/broker", - "MESH_RECEIVES": "/var/lib/umami/grants/mesh.json" + "MESH_RECEIVES": "/var/lib/umami/grants/mesh.json", + "MESH_UMAMI_ADMIN_PASSWORD_FILE": "/run/secrets/admin" }, "env-file": [ "/var/lib/umami/provisioner.env"