From 101714f9f0588d993a54fb2257c7a20b3cb9705b Mon Sep 17 00:00:00 2001 From: clawbot <35+clawbot@noreply.example.org> Date: Sun, 4 Oct 2026 21:29:13 +0000 Subject: [PATCH] Keep secrets out of the Docker build context at every depth (closes #205) .dockerignore patterns without a leading **/ match only at the root of the build context, so a nested .env or private key still reached it and, through COPY . ., a build-stage layer. The file is now the standard one from sneak/prompts: every pattern that should match anywhere has **/, and private keys and environment files are matched in any letter case. pixa keeps its own differences: .git is still sent without .git/config in place of the standard .git line, which the version stamp needs, and .gitignore, /bin and /data stay out. Model: opus-5-5 --- .dockerignore | 74 ++++++++++++++++++++++++++++++++++++++++++++------- TODO.md | 6 +++++ 2 files changed, 71 insertions(+), 9 deletions(-) diff --git a/.dockerignore b/.dockerignore index 549cdb4..8790b32 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,12 +1,68 @@ -# .git is sent without its config. Without a VERSION build argument the -# stage that compiles runs `git describe --tags --always` on .git, which -# does not need .git/config; that file can hold a credential, such as a +# .dockerignore does NOT use .gitignore semantics. Docker matches with +# moby/patternmatcher: filepath.Match plus `**`, so `*` does not cross +# `/` and an unprefixed pattern is anchored at the context root. Every +# depth-independent pattern therefore needs `**/`, or `config/.env` and +# `certs/server.key` still ship while this file reads as solved. Only +# genuinely root-anchored entries go unprefixed. Never transplant these +# into .gitignore, where `**/` is wrong. +# +# Matching is case-sensitive, so secrets use character ranges rather +# than an ALL-CAPS twin, which would still miss `Server.Key`. +# +# Extend with this repo's own host-built artifacts, written anchored: +# `/myapp`, never `**/myapp`, which also matches `cmd/myapp/` and +# deletes the package directory from the context. + +# Unlike the standard file, which leaves out all of .git, pixa sends +# .git without its config. Without a VERSION build argument the stage +# that compiles runs `git describe --tags --always` on .git, which does +# not need .git/config; that file can hold a credential, such as a # password in a remote URL or the token the CI checkout step stores there. .git/config -.gitignore -.DS_Store -.env* + +# Agent scratch: one full checkout of the repo per in-flight agent. +# Anchored because it occurs once where agents run at the repo root. +# KNOWN GAP: a repo running agents in subdirectories still ships +# `services/api/.claude/` and must add its own anchored entry. .claude -node_modules -bin/ -data/ + +# Environment files. `*.env` covers bare `.env` and the `prod.env` +# convention. Re-include a committed template with a negation if the +# build needs one: `!docs/example.env`. +**/*.[eE][nN][vV] +**/.[eE][nN][vV].* +**/.[eE][nN][vV][rR][cC] + +# Private keys and the bundles carrying them. Public certificates +# (*.crt, *.cer) are deliberately absent: they are legitimate inputs. +**/*.[pP][eE][mM] +**/*.[kK][eE][yY] +**/*.[pP]12 +**/*.[pP][fF][xX] +**/[iI][dD]_[rR][sS][aA] +**/[iI][dD]_[dD][sS][aA] +**/[iI][dD]_[eE][cC][dD][sS][aA] +**/[iI][dD]_[eE][dD]25519 + +# Dependencies: restored inside the image, never copied in. +**/node_modules + +# OS metadata. +**/.DS_Store +**/Thumbs.db + +# Editor state: never a build input, and it churns COPY. +**/*.swp +**/*.swo +**/*~ +**/*.bak +**/.idea +**/.vscode +**/*.sublime-* + +# pixa's own entries. Nothing in the build reads .gitignore. On the +# host, `make build` writes bin/pixad, and the example config keeps its +# state directory in data/. +.gitignore +/bin +/data diff --git a/TODO.md b/TODO.md index 27f0147..90ecfb3 100644 --- a/TODO.md +++ b/TODO.md @@ -31,6 +31,12 @@ P2: security: per-IP rate limiting on the image routes # Completed Steps +- 2026-10-04 `.dockerignore` keeps secrets out at every depth (closes #205): the + file is now the standard one from `sneak/prompts`, whose patterns match in + every directory and, for environment files and private keys, in any letter + case, so a nested `.env` or `server.key` no longer reaches the build context. + pixa still sends `.git` without `.git/config` in place of the standard file's + `.git` line, and still leaves out `.gitignore`, `/bin` and `/data`. - 2026-10-04 an integration test of the image proxy flow (closes #80): `TestImageProxyFlow` in `internal/server` starts the database, handlers and middleware from the constructors `pixad` uses, with a fresh state directory,