From 9b6b12a5da49ded488adeb4542e39f784cea55c5 Mon Sep 17 00:00:00 2001 From: emi Date: Sat, 25 Jul 2026 07:16:08 +0000 Subject: [PATCH] infra: mirror LAN dev secrets under $HOME for snap-confined Docker (#85) --- infra/.gitignore | 4 ++++ infra/deploy/deploy-dev.sh | 9 +++++++++ infra/deploy/render-secrets.sh | 17 +++++++++++++++++ infra/docker-compose.dev.yml | 17 +++++++++++++++++ 4 files changed, 47 insertions(+) diff --git a/infra/.gitignore b/infra/.gitignore index c3ac61f..c6b008f 100644 --- a/infra/.gitignore +++ b/infra/.gitignore @@ -27,3 +27,7 @@ __pycache__/ deploy/.image-tags.env deploy/.deploy.lock deploy/.stack-image-tags.env + +# LAN dev's mirror of the rendered secrets, for snap-confined Docker (see +# deploy-dev.sh / render-secrets.sh) -- plaintext, re-rendered every deploy. +deploy/dev-secrets.env diff --git a/infra/deploy/deploy-dev.sh b/infra/deploy/deploy-dev.sh index 08c501f..8149d8b 100755 --- a/infra/deploy/deploy-dev.sh +++ b/infra/deploy/deploy-dev.sh @@ -72,6 +72,15 @@ export COMPOSE_PROJECT_NAME="${COMPOSE_PROJECT_NAME:-thermograph-dev}" # genuinely needs, and nothing else. export THERMOGRAPH_SECRETS_SKIP_COMMON=1 +# (1b) Docker on this box is the snap package, confined to $HOME (plus a short +# allowlist) -- it silently can't see /etc/thermograph.env at all, so +# env_file: /etc/thermograph.env resolves to nothing for every container no +# matter how correctly it's rendered. Mirror the render to a path under +# $APP_DIR too; docker-compose.dev.yml points env_file at this copy instead of +# /etc/thermograph.env. Untracked (see infra/.gitignore); re-rendered on every +# deploy, never committed. +export THERMOGRAPH_SECRETS_ENV_FILE_MIRROR="$APP_DIR/infra/deploy/dev-secrets.env" + # (2) The age key is read from wherever it is READABLE, not necessarily # /etc/thermograph/age.key. render-secrets.sh falls back to `sudo cat` for a # root-owned 0400 key, and this box has no passwordless sudo -- under the Forgejo diff --git a/infra/deploy/render-secrets.sh b/infra/deploy/render-secrets.sh index b5de8fc..b3b5b3c 100755 --- a/infra/deploy/render-secrets.sh +++ b/infra/deploy/render-secrets.sh @@ -127,6 +127,23 @@ render_thermograph_secrets() { echo "!! cannot write /etc/thermograph.env (need file write access or passwordless sudo)" >&2 rc=1 fi + + # Optional second copy under $HOME, for a host whose docker CLI cannot read + # /etc/thermograph.env at all -- the LAN dev box's snap-packaged Docker is + # confined to $HOME (plus a short allowlist) and silently treats anything + # under /etc as nonexistent, so env_file: /etc/thermograph.env resolves to + # nothing for every container even though the file is right there and the + # shell that rendered it can read it fine. deploy-dev.sh sets this; + # prod/beta (apt-installed Docker, no snap confinement) leave it unset and + # this is a no-op for them. + if [ "$rc" = 0 ] && [ -n "${THERMOGRAPH_SECRETS_ENV_FILE_MIRROR:-}" ]; then + if ! mkdir -p "$(dirname "$THERMOGRAPH_SECRETS_ENV_FILE_MIRROR")" \ + || ! install -m 0600 "$tmp" "$THERMOGRAPH_SECRETS_ENV_FILE_MIRROR"; then + echo "!! cannot write mirror at $THERMOGRAPH_SECRETS_ENV_FILE_MIRROR" >&2 + rc=1 + fi + fi + rm -f "$tmp" return "$rc" } diff --git a/infra/docker-compose.dev.yml b/infra/docker-compose.dev.yml index 9c12a9b..86f9c53 100644 --- a/infra/docker-compose.dev.yml +++ b/infra/docker-compose.dev.yml @@ -27,12 +27,23 @@ # prod's backend=4 / frontend=2 / db=2 allocation. `!reset` drops the base # value (both the top-level `cpus:` and the Swarm-style `deploy.resources` # block the base file carries for parity). +# 4. backend/daemon/lake get a second env_file entry pointing at a copy of the +# render under $APP_DIR (deploy-dev.sh sets THERMOGRAPH_SECRETS_ENV_FILE_MIRROR +# to produce it). This box's Docker is the snap package, confined to $HOME -- +# it can't see /etc/thermograph.env at all (not a permissions error, it just +# doesn't exist as far as snap-confined Docker is concerned), so the base +# file's env_file entry silently loads nothing here. compose appends env_file +# lists across overlays (last-wins on duplicate keys), so this is additive: +# prod/beta never set the mirror var, so they only ever get the base entry. services: backend: ports: !override - "8137:8137" cpus: !reset null deploy: !reset null + env_file: + - path: ./deploy/dev-secrets.env + required: false frontend: ports: !reset null cpus: !reset null @@ -42,6 +53,9 @@ services: daemon: cpus: !reset null deploy: !reset null + env_file: + - path: ./deploy/dev-secrets.env + required: false db: cpus: !reset null deploy: !reset null @@ -53,3 +67,6 @@ services: # the default DB_MEMORY (raise DB_MEMORY to give dev more); shm_size stays (it's # required shared memory for parallel query, not a limit). mem_limit: !reset null + env_file: + - path: ./deploy/dev-secrets.env + required: false