diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..cdaa694dc --- /dev/null +++ b/.dockerignore @@ -0,0 +1,47 @@ +# Build context for `docker build -t ouroboros-web .` (Dockerfile: COPY . .). +# Keep secrets, host environments and local runtime/operator state out of image +# layers. Do NOT exclude .git, tests/ or sources: CI builds this image and +# runs pytest inside it, and the agent needs its own Git history. +# tests/test_build_scripts.py::TestDockerignore pins both halves. + +# Secrets (mirrors .gitignore) +**/.env +**/.env.* +**/*.key +**/*.pem + +# Host environments, IDE state and caches +.venv/ +venv/ +env/ +**/node_modules/ +**/__pycache__/ +**/*.pyc +.pytest_cache/ +.mypy_cache/ +.ruff_cache/ +.cursor/ +.vscode/ +.idea/ + +# Local runtime, review and operator state (never tracked; see .gitignore) +/data/ +/logs/ +/.tmp-data-*/ +/.review-drive/ +/.claudexor/ +/.adversarial-review/ +/.review-evidence-iter2/ + +# Build output and bundled runtimes +/dist/ +/build/ +/python-standalone/ +/node-standalone/ +/ripgrep-standalone/ +/betterleaks-standalone/ +/claudexor-runtime/ + +# Other +/.devcontainer +/graphify-out diff --git a/.gitignore b/.gitignore index b324113f0..4c1834814 100644 --- a/.gitignore +++ b/.gitignore @@ -103,4 +103,6 @@ MagicMock/ devtools/benchmarks/editbench/fixtures_v2/ # Other -.devcontainer +# Anchored to the repo root, like /logs/ and /ocr_pages/ above. +/.devcontainer +/graphify-out diff --git a/docs/architecture/08-git-branching-ci-and-build.md b/docs/architecture/08-git-branching-ci-and-build.md index dced7e5da..90c467b21 100644 --- a/docs/architecture/08-git-branching-ci-and-build.md +++ b/docs/architecture/08-git-branching-ci-and-build.md @@ -58,4 +58,6 @@ Public installer naming and links ride the same projection: `release_sync.py::RE Docker runs the web and server runtime without PyWebView. The image binds `0.0.0.0` and sets no network password by default: a missing password only warns, and `NetworkAuthGate` permits requests when no password is configured — publishing the container port without setting `OUROBOROS_NETWORK_PASSWORD` therefore exposes the owner surface. Set the password (or keep the port unpublished); packaging adds no stronger boundary of its own. +The root `.dockerignore` filters `COPY . .`: secrets, host virtualenvs, `node_modules`, caches and runtime/review/operator state stay out of image layers; `.git`, `tests/` and sources stay in, because CI runs pytest inside the image. + --- diff --git a/tests/test_build_scripts.py b/tests/test_build_scripts.py index 9d3e6647d..df5a001d1 100644 --- a/tests/test_build_scripts.py +++ b/tests/test_build_scripts.py @@ -511,6 +511,38 @@ class TestBuildWindowsPs1: # Dockerfile (Docker / web runtime) # --------------------------------------------------------------------------- +class TestDockerignore: + """The root .dockerignore owns the build context of Dockerfile's COPY . . + + Both halves matter: private local state must stay out of image layers, + and the paths CI needs inside the image (Git history, tests, sources) + must stay in.""" + + def _patterns(self): + lines = _read(".dockerignore").splitlines() + return {ln.strip() for ln in lines if ln.strip() and not ln.lstrip().startswith("#")} + + def test_private_state_is_excluded(self): + patterns = self._patterns() + required = { + "**/.env", "**/.env.*", "**/*.key", "**/*.pem", + ".venv/", "venv/", "env/", "/data/", + "/.review-drive/", "/.claudexor/", "/.adversarial-review/", + } + missing = sorted(required - patterns) + assert not missing, f".dockerignore must exclude private local state: {missing}" + + def test_ci_needed_paths_stay_in_context(self): + patterns = self._patterns() + for kept in (".git", "tests", "ouroboros", "web", "prompts", "docs", + "supervisor", "pyproject.toml", "uv.lock", "server.py"): + for spelling in (kept, kept + "/", "/" + kept, "/" + kept + "/", "**/" + kept): + assert spelling not in patterns, ( + f".dockerignore must not exclude {kept}: CI runs pytest inside the image" + ) + assert "*" not in patterns and "**" not in patterns + + class TestDockerfile: """Dockerfile must install Playwright Chromium/WebKit binaries so browser tools work out of the box in the container without additional setup.""" diff --git a/tests/test_reference_book_budgets.py b/tests/test_reference_book_budgets.py index 8dc8777e7..3347c74c5 100644 --- a/tests/test_reference_book_budgets.py +++ b/tests/test_reference_book_budgets.py @@ -141,7 +141,10 @@ CHAPTER_BYTE_BUDGETS: dict[str, int] = { # `ouroboros` push included), the per-checkout static/VERSION provenance a boot # and a restart prove, and the scrubbed roots plus the single dependency-sync # chokepoint. The `ui-smoke` row it replaces was rewritten, not appended to. - "docs/architecture/08-git-branching-ci-and-build.md": 20560, + # 20560 -> 20800 (PR #1255; measured 20768): the Docker subsection maps the new root + # .dockerignore (what it keeps out of image layers and why .git/tests/ must stay in), + # a config BIBLE P6 requires on the map. + "docs/architecture/08-git-branching-ci-and-build.md": 20800, # 12405 -> 14400 (issue #1142): the ordinary-close paragraph gains the mechanism the chapter had # no text for — graceful stop signals the server PID only, the server half (stop event at the # signal, bounded uvicorn drain) is self-sufficient against an old group-SIGTERM launcher.