Skip to content

RV-S4: Docker image can bake build/config.local.env and build/environments/env_*.sql from configured checkout #174

Closed

Description

@amar-python

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.
  • .dockerignore excludes .env files but not build/config.local.env or build/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 .dockerignore to exclude build/config.local.env and build/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 .dockerignore alone. Also helps image size.

Both layers catch future additions: the next time someone adds a config file under build/, either layer stops it.

Proposed

  1. .dockerignore: add build/config.local.env, build/config.local.env.new (post-RV-S2 fix), build/environments/env_*.sql.
  2. infra/Dockerfile: replace broad COPY 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* or build/environments/env_*.sql
  3. 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.env and build/environments/env_dev.sql. Run docker save <image> and grep -a <synthetic-secret> across the layers. Confirm absent.
  • The test fails on main at c7bebd1 without the fix.
  • The test passes with the fix.
  • No change to image functionality: existing docker run smoke 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

  1. added 2 commits that reference this issue on Nov 9, 2026
  2. added 2 commits that reference this issue on Nov 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions