From 4c5ee96e36772d5be56fa5e6fb9357333672c85a Mon Sep 17 00:00:00 2001 From: Marcel Date: Sat, 16 May 2026 08:52:42 +0200 Subject: [PATCH] docs(adr): correct ADR-016 Decision section to match two-source env model The Decision section described an operator-managed /opt/familienarchiv/.env that CI does not touch. The actual implementation is a two-source model: obs.env (git-tracked, non-secret config) + obs-secrets.env (CI-written fresh from Gitea secrets on every deploy). Also updates the Consequences bullet that incorrectly stated secrets are decoupled from CI. Co-Authored-By: Claude Sonnet 4.6 --- docs/adr/016-obs-stack-co-location-ci-push.md | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/docs/adr/016-obs-stack-co-location-ci-push.md b/docs/adr/016-obs-stack-co-location-ci-push.md index 839d08f6..0e181597 100644 --- a/docs/adr/016-obs-stack-co-location-ci-push.md +++ b/docs/adr/016-obs-stack-co-location-ci-push.md @@ -32,9 +32,14 @@ The observability stack is co-located with the main application deployment at `/ - `docker-compose.observability.yml` → `/opt/familienarchiv/docker-compose.observability.yml` - `infra/observability/` → `/opt/familienarchiv/infra/observability/` -The nightly CI job (`nightly.yml`) copies these files from the workspace checkout to `/opt/familienarchiv/` using `cp -r` on every run (CI-push model). Containers always read config from the permanent location; a workspace wipe has no effect on running containers. +Both the nightly CI job (`nightly.yml`) and the release job (`release.yml`) copy these files from the workspace checkout to `/opt/familienarchiv/` using `cp -r` on every run (CI-push model). Containers always read config from the permanent location; a workspace wipe has no effect on running containers. -Secrets are stored in `/opt/familienarchiv/.env` on the server. This file is managed by the operator — CI does not write or delete it. Docker Compose auto-reads it when started from `/opt/familienarchiv/`. The required key inventory is documented in `docs/DEPLOYMENT.md §4`. +Environment variables follow a two-source model: + +- `infra/observability/obs.env` (git-tracked, non-secret): all non-sensitive config — host ports, public URLs (`GLITCHTIP_DOMAIN`, `GF_SERVER_ROOT_URL`), and the default `POSTGRES_HOST`. Changes go through PR review. No credentials. +- `/opt/familienarchiv/obs-secrets.env` (CI-written, per-deploy): passwords and secret keys only (`GRAFANA_ADMIN_PASSWORD`, `GLITCHTIP_SECRET_KEY`, `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_HOST`), injected fresh from Gitea secrets on every nightly and release deploy. Gitea is the single source of truth for secrets — rotating a secret takes effect on the next deploy without manual server action. + +Both files are passed explicitly via `--env-file` to every obs compose command (config dry-run and `up`). There is no implicit auto-read `.env`. The required key inventory is documented in `docs/DEPLOYMENT.md §4`. The CI runner mounts `/opt/familienarchiv` as a bind mount into job containers (see `runner-config.yaml`). This requires a one-time `mkdir -p /opt/familienarchiv/infra` on the server and a runner restart after updating `runner-config.yaml` (see ADR-015 and `docs/DEPLOYMENT.md §3.1`). @@ -44,7 +49,7 @@ The CI runner mounts `/opt/familienarchiv` as a bind mount into job containers ( - Bind-mount sources survive workspace wipes by definition — they are on a persistent host path. - Config is always in sync with the repo after each nightly run. - No new infrastructure dependencies; the CI-push model mirrors how the main app stack is deployed. -- Secrets (`/opt/familienarchiv/.env`) are decoupled from CI — a deployment cannot accidentally overwrite them. +- Secret rotation requires no manual server action — Gitea secrets are the authoritative store; `obs-secrets.env` is rewritten from scratch on every deploy so a secret change takes effect on the next nightly or release run. **Negative:** - `cp -r` does not remove deleted files; a config file removed from the repo persists in `/opt/familienarchiv/infra/observability/` until manually deleted. Acceptable for this project's change frequency. A `rsync -a --delete` would give a clean mirror if this becomes a problem.