From ea24c8214d535f4818eaf925822c6b5caa828146 Mon Sep 17 00:00:00 2001 From: DoRmAmMu1997 Date: Fri, 4 Sep 2026 19:37:38 +0530 Subject: [PATCH] fix(SEC-004): stop shipping pytest in the production image `requirements.txt` declared `pytest` as a runtime dependency under a "Test runner." heading. The Dockerfile installs `requirements.txt` and nothing else, so the test runner and its dependency tree were baked into the deployed image - on both the Render web service and the daily-scan cron. It was already declared in `requirements-dev.txt`, so this was a duplicate that bought nothing and only widened the production surface. Remove it, and add a policy guard so it cannot drift back. The guard checks the whole class of developer tooling (pytest, pytest-cov, ruff, bandit, pip-audit, mypy, pre-commit) and asserts each one is absent from requirements.txt AND still present in requirements-dev.txt - so the fix cannot be "solved" by deleting the dependency outright either. Verified by re-adding pytest to requirements.txt and watching the guard fail. The existing `constraints.txt` pin for pytest is untouched and still correct: constraints only pin versions for whatever is actually being installed, and CI installs both requirements files. Closes #121 Co-Authored-By: Claude Opus 5 --- requirements.txt | 3 --- tests/test_supply_chain_policy.py | 25 +++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/requirements.txt b/requirements.txt index 892842d..504368e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -41,6 +41,3 @@ beautifulsoup4 lxml pdfplumber claude-agent-sdk - -# Test runner. -pytest diff --git a/tests/test_supply_chain_policy.py b/tests/test_supply_chain_policy.py index bdc545a..e8f9577 100644 --- a/tests/test_supply_chain_policy.py +++ b/tests/test_supply_chain_policy.py @@ -246,6 +246,31 @@ def test_runtime_requirements_install_the_documented_postgres_driver(): assert re.search(r"^psycopg\[binary\]$", text, flags=re.IGNORECASE | re.MULTILINE) +def test_developer_tools_stay_out_of_the_runtime_requirements(): + """Verification tooling must not ship inside the production image. + + Beginner note (SEC-004): + `Dockerfile` installs `requirements.txt` and nothing else, so every name in + that file lands in the deployed container. `pytest` was listed there under a + "Test runner." heading as well as in `requirements-dev.txt`, so the test + runner and its dependency tree were shipped to production for no benefit. + Each of the names below has a legitimate home in `requirements-dev.txt`; the + point of this guard is that they only have one home. + """ + runtime = (ROOT / "requirements.txt").read_text(encoding="utf-8") + dev = (ROOT / "requirements-dev.txt").read_text(encoding="utf-8") + + dev_only = ("pytest", "pytest-cov", "ruff", "bandit", "pip-audit", "mypy", "pre-commit") + for name in dev_only: + pattern = rf"^{re.escape(name)}(?:\[[^\]]+\])?\s*$" + assert not re.search(pattern, runtime, flags=re.IGNORECASE | re.MULTILINE), ( + f"{name} is a developer tool and must not be in requirements.txt" + ) + assert re.search(pattern, dev, flags=re.IGNORECASE | re.MULTILINE), ( + f"{name} should still be declared in requirements-dev.txt" + ) + + def test_readme_documents_local_quality_and_security_commands(): """The README should teach users how to reproduce the CI checks locally.""" text = (ROOT / "README.md").read_text(encoding="utf-8")