Repository navigation
Description
What happened
External repository review at commit c7bebd1 found that build/config.local.env and generated build/environments/env_*.sql can be baked into a Docker image when built from a configured checkout. Static reading of infra/Dockerfile L47–59 and .dockerignore L13–17; no live image was inspected.
Mechanism:
- Dockerfile copies all of
build/into the image. .dockerignoreexcludes.envfiles but notbuild/config.local.envorbuild/environments/env_*.sql.- Both files are gitignored, which does not affect Docker build context.
- Running
docker build .from a locally configured checkout produces an image containing the developer's dev credentials.
The review labels this "conditional exposure": not evidence that an existing registry image contains secrets, but the mechanism by which one could.
Why this matters
Docker image layers are immutable and cached indefinitely. Once credentials land in an image layer pushed to a registry (even private), rotation of the leaked password is the only remediation, and only if someone notices.
No current trigger: no Azure deployment exists (#31, #32, #34 open), no Docker-based CI pipeline. The hazard is latent. Trigger: first time anyone builds the image locally for testing or in a CI pipeline and pushes it anywhere.
Related to RV-S1 / #172: that fix must avoid committing a populated env_prod.sql to the image, which would recreate this exposure.
Decision taken 3 Nov 2026
Both fixes together in one PR, defense in depth:
- (a) Update
.dockerignoreto excludebuild/config.local.envandbuild/environments/env_*.sql. Immediate one-line safety net. - (b) Dockerfile uses explicit source list. Replace
COPY build/ /app/build/with specific COPY statements for the files the image actually needs (schema files, launchers, migration scripts). Everything else omitted by not being copied, safer than relying on.dockerignorealone. Also helps image size.
Both layers catch future additions: the next time someone adds a config file under build/, either layer stops it.
Proposed
.dockerignore: addbuild/config.local.env,build/config.local.env.new(post-RV-S2 fix),build/environments/env_*.sql.infra/Dockerfile: replace broadCOPY build/with specific paths. Draft list to confirm during implementation:COPY build/schema/ /app/build/schema/COPY build/csv/ /app/build/csv/COPY build/*.sh /app/build/- Explicitly do NOT copy
build/config.local.env*orbuild/environments/env_*.sql
- Document in
infra/README.md(or create one) why these exclusions matter.
Done when
- Verification test: build image from a checkout that has synthetic secrets in
build/config.local.envandbuild/environments/env_dev.sql. Rundocker save <image>andgrep -a <synthetic-secret>across the layers. Confirm absent. - The test fails on
mainatc7bebd1without the fix. - The test passes with the fix.
- No change to image functionality: existing
docker runsmoke test still passes with the explicit source list. - CI replica run quoted on the PR (counts in passed / failed / skipped form).
If Docker is not available for the verification step, equivalent evidence is acceptable: run docker build --no-cache . 2>&1 | grep -i copy and compare the file list before and after the fix, confirming the sensitive files are no longer in the build context.
Reference
Tracker row G37 (main tab). Repo review finding RV-S4. Related: G34 / #172 (RV-S1 production DB config — must not reintroduce this exposure), G36 / #173 (RV-S3 credential file naming). All Standards P1 touching deployment and credential safety.
Activity
fix: align the production database across Terraform, deployer and ent…
Merge pull request #204 from amar-python/fix/174-no-baked-secrets-in-…
fix(ui): list each log step once; test it from the source
Merge pull request #234 from amar-python/fix/174-test-layout-and-cata…