# runner-config.yaml — only the relevant section container: # passed as DOCKER_HOST inside the job container docker_host: "unix:///var/run/docker.sock" # Job workspaces are stored here on the NAS and mounted at the same # absolute path inside job containers. Identical host ↔ container path # is the requirement: Docker Compose resolves relative bind mounts to # $(pwd) inside the job container and passes that absolute path to the # host daemon — the daemon must find the file at that exact host path. # Prerequisite: mkdir -p /srv/gitea-workspace on the host, and add # - /srv/gitea-workspace:/srv/gitea-workspace # to the runner service volumes in gitea's compose.yaml. workdir_parent: /srv/gitea-workspace # whitelists volumes that workflow steps may bind-mount valid_volumes: - "/var/run/docker.sock" - "/srv/gitea-workspace" - "/opt/familienarchiv" # appended to `docker run` when the runner spawns a job container # SECURITY WARNING: This mount configuration grants CI job containers: # 1. Root-equivalent access to the host Docker daemon (via the socket). # 2. Read/write access to /opt/familienarchiv/ — including the main app's # compose files, Caddy config, and observability configs. A malicious # workflow step could overwrite any file in that directory. # Both are acceptable ONLY because this runner is single-tenant: it executes # code exclusively from this private repo with a fixed set of trusted authors. # WARNING: Do NOT add this runner to any repo with external contributors or # untrusted PRs — the blast radius includes the entire production deployment. # See ADR-016 for the reasoning behind the /opt/familienarchiv mount. options: "-v /var/run/docker.sock:/var/run/docker.sock -v /srv/gitea-workspace:/srv/gitea-workspace -v /opt/familienarchiv:/opt/familienarchiv" # keep network mode default (bridge) — Testcontainers handles its own networking force_pull: false