Skip to content

Commit 11d307f

Browse files
authored
fix(docker): prevent host node_modules from polluting builds + non-interactive pnpm (#3)
Three things compounding caused `make up` to fail with ERR_PNPM_ABORTED_REMOVE_MODULES_DIR_NO_TTY: 1. No .dockerignore meant 'COPY ui/ ./' was overlaying the host's resolved ui/node_modules onto the image's freshly-installed one, triggering pnpm's drift-detection. 2. With drift detected, pnpm decided node_modules needed to be removed and reinstalled but refused to do so without a TTY to confirm. 3. Backend builds were also susceptible to host-state contamination from .venv, .pytest_cache, __pycache__, .cerebro.json, etc. Fixes: - Add .dockerignore at repo root. Excludes node_modules, .venv, __pycache__, .pytest_cache, .mypy_cache, .ruff_cache, dist/, .gitnexus/, AGENTS.md, .docs/, openspec/, tests/, .github/, /data/, *.cerebro.json, *.db, .env (keep .env.example). Image contexts now ship only what the build actually needs. - Set ENV CI=true in docker/ui.Dockerfile so pnpm operates non-interactively if it ever decides to nuke node_modules anyway. - Set ENV CI=true in docker/backend.Dockerfile for symmetry and to keep any uv prompt path predictable. Verified locally: `docker compose build` succeeds for both images, `make up` brings both containers online, `curl localhost:3000` returns 200 with the UI's index.html.
1 parent c8da55a commit 11d307f

3 files changed

Lines changed: 99 additions & 0 deletions

File tree

.dockerignore

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# Cerebro .dockerignore — keep image-build contexts small and deterministic.
2+
#
3+
# Anything matched here is excluded from the build context Docker sends to
4+
# the daemon. The two big wins: (1) prevents the host's resolved
5+
# node_modules / .venv from being COPYed on top of the image's own
6+
# resolutions; (2) cuts context size from hundreds of MB to a few MB,
7+
# which makes builds substantially faster.
8+
9+
# ---- Node / UI build artifacts ----------------------------------------
10+
**/node_modules
11+
**/dist
12+
**/.vite
13+
**/.eslintcache
14+
*.tsbuildinfo
15+
**/coverage
16+
17+
# ---- Python build artifacts -------------------------------------------
18+
**/__pycache__
19+
**/*.py[cod]
20+
**/*$py.class
21+
**/.venv
22+
**/venv
23+
**/*.egg-info
24+
**/.pytest_cache
25+
**/.mypy_cache
26+
**/.ruff_cache
27+
**/.import_linter_cache
28+
**/.coverage
29+
**/.coverage.*
30+
**/htmlcov
31+
**/coverage.xml
32+
33+
# ---- Runtime data — never bake into images ----------------------------
34+
/data/
35+
**/*.cerebro.json
36+
**/*.db
37+
**/*.db-wal
38+
**/*.db-shm
39+
40+
# ---- Secrets / env files ----------------------------------------------
41+
.env
42+
.env.*
43+
!.env.example
44+
45+
# ---- Git / VCS --------------------------------------------------------
46+
.git
47+
.gitignore
48+
.gitattributes
49+
50+
# ---- IDE / OS ---------------------------------------------------------
51+
.DS_Store
52+
Thumbs.db
53+
.idea/
54+
.vscode/
55+
*.swp
56+
57+
# ---- Build / analysis caches that don't belong in images --------------
58+
.turbo
59+
.gitnexus/
60+
.codegraph/
61+
.claude/
62+
AGENTS.md
63+
.docs/
64+
.docs.local/
65+
66+
# ---- Specs / docs / dev tooling (not needed at runtime) ---------------
67+
openspec/
68+
docs/
69+
scripts/
70+
tests/
71+
.github/
72+
.pre-commit-config.yaml
73+
.python-version
74+
.node-version
75+
76+
# ---- Compose / Make are tooling, not image content --------------------
77+
docker-compose.yml
78+
docker-compose.*.yml
79+
Makefile
80+
81+
# ---- Top-level docs we don't need at runtime --------------------------
82+
# (backend.Dockerfile explicitly COPYs README.md, so don't ignore *.md.)
83+
ARCHITECTURE.md
84+
CLAUDE.md
85+
CODE_OF_CONDUCT.md
86+
CONTRIBUTING.md
87+
LICENSE

docker/backend.Dockerfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44
# uvicorn CMD) and digest-pinned bases land alongside the API layer.
55
FROM python:3.12-slim
66

7+
# Non-interactive flag honored by uv and most modern Python tooling.
8+
# Keeps the build deterministic if any tool decides to prompt.
9+
ENV CI=true
10+
711
# uv pinned by version (pin by digest when the build is hardened).
812
COPY --from=ghcr.io/astral-sh/uv:0.9.9 /uv /uvx /bin/
913

docker/ui.Dockerfile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@
44

55
# ---- Stage 1: builder ----
66
FROM node:22-alpine AS builder
7+
8+
# CI=true tells pnpm we're non-interactive, so it never blocks on a TTY
9+
# confirmation if it decides node_modules needs to be rebuilt mid-build
10+
# (ERR_PNPM_ABORTED_REMOVE_MODULES_DIR_NO_TTY). The .dockerignore at the
11+
# repo root prevents the host's node_modules from being COPYed in, which
12+
# is the most common cause of that decision.
13+
ENV CI=true
14+
715
RUN npm install -g pnpm@11.1.2
816
WORKDIR /build
917
COPY ui/package.json ui/pnpm-lock.yaml ui/pnpm-workspace.yaml ./

0 commit comments

Comments
 (0)