From 5ed98cefbdea6040105b5791e8675fe90fecd5f5 Mon Sep 17 00:00:00 2001 From: KaifAhmad1 Date: Mon, 31 Aug 2026 15:43:59 +0530 Subject: [PATCH] fix(ci): hash-pin PEP 517 build isolation deps (setuptools, wheel) Qodo review on this PR: `pip install --no-deps -e .` / `pip install --no-deps .` still leaves PEP 517 build isolation on by default, which fetches [build-system] requires (setuptools==84.0.0, wheel==0.48.0) completely outside any hash checking - the --require-hashes installs right next to it didn't cover this at all. Adds .github/requirements/pep517-build.txt, hash-locked to the exact pyproject.toml [build-system] requires, and installs it before every local-source install (Dockerfile, ci.yml, benchmark.yml) with --no-build-isolation so pip reuses those hash-verified copies instead of fetching its own. --- .dockerignore | 1 + .github/requirements/README.md | 1 + .github/requirements/pep517-build.in | 2 ++ .github/requirements/pep517-build.txt | 14 ++++++++++++++ .github/workflows/benchmark.yml | 11 ++++++++++- .github/workflows/ci.yml | 11 ++++++++++- .github/workflows/container-scan.yml | 1 + Dockerfile | 17 ++++++++++++----- 8 files changed, 51 insertions(+), 7 deletions(-) create mode 100644 .github/requirements/pep517-build.in create mode 100644 .github/requirements/pep517-build.txt diff --git a/.dockerignore b/.dockerignore index 831577d3..5420b102 100644 --- a/.dockerignore +++ b/.dockerignore @@ -20,6 +20,7 @@ .github/** !.github/requirements/ !.github/requirements/explorer-extra.txt +!.github/requirements/pep517-build.txt .claude .claude/** .codex diff --git a/.github/requirements/README.md b/.github/requirements/README.md index f0b59d8e..eea12179 100644 --- a/.github/requirements/README.md +++ b/.github/requirements/README.md @@ -27,6 +27,7 @@ each file's own autogenerated header comment for its exact command). | File | Used by | Installs | | --- | --- | --- | | `bootstrap.txt` | security.yml, security-scan.yml, benchmark.yml | pip, setuptools (upgrade before anything else) | +| `pep517-build.txt` | ci.yml, benchmark.yml, Dockerfile | exact `[build-system] requires` from `pyproject.toml` (setuptools, wheel) - installed with `--no-build-isolation` before any `pip install -e .` / `pip install .`, since `--no-deps` alone doesn't stop pip's PEP 517 build isolation from fetching those two *unhashed* | | `explorer-extra.txt` | ci.yml, Dockerfile | semantica's base deps + the `explorer` extra | | `pytest-tool.txt` | ci.yml | pytest, for the pre-all-extras deterministic test | | `uv-tool.txt` | ci.yml | uv, to verify requirements-ci.txt is current | diff --git a/.github/requirements/pep517-build.in b/.github/requirements/pep517-build.in new file mode 100644 index 00000000..049fd927 --- /dev/null +++ b/.github/requirements/pep517-build.in @@ -0,0 +1,2 @@ +setuptools==84.0.0 +wheel==0.48.0 diff --git a/.github/requirements/pep517-build.txt b/.github/requirements/pep517-build.txt new file mode 100644 index 00000000..8e468f82 --- /dev/null +++ b/.github/requirements/pep517-build.txt @@ -0,0 +1,14 @@ +# This file was autogenerated by uv via the following command: +# uv pip compile .github/requirements/pep517-build.in --generate-hashes --python-version 3.11 --python-platform linux -o .github/requirements/pep517-build.txt +packaging==26.3 \ + --hash=sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79 \ + --hash=sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c + # via wheel +setuptools==84.0.0 \ + --hash=sha256:51a52592b3b99e102b609654876bd65f19f999935166d1352678931132b0c670 \ + --hash=sha256:f4695c21257f0d9b537ec2692c941d02ee143b7cc1276941349a546573b2ef73 + # via -r .github/requirements/pep517-build.in +wheel==0.48.0 \ + --hash=sha256:3217dcc807155e45db462d7ef2431f5ddda0d7273b700d05a67b271ceb1287ab \ + --hash=sha256:94800765601e9171bf5d58d066e640662842bcedcbab982b2c90787a2c987322 + # via -r .github/requirements/pep517-build.in diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index da15557c..85c3bd3e 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -33,7 +33,16 @@ jobs: # (rather than a bare `pip install -e .`) so every fetched package # is hash-verified (Scorecard Pinned-Dependencies); the local # editable install itself has nothing to hash. - pip install --no-deps -e . + # + # --no-deps only skips *runtime* dependency resolution - `-e .` + # still does a PEP 517 build, which by default creates an isolated + # build env and fetches [build-system] requires (setuptools, + # wheel) completely outside any hash checking. Install + # pep517-build.txt (pins that exact build-system.requires) first + # and pass --no-build-isolation so pip reuses those hash-verified + # copies instead of fetching its own. + pip install -r .github/requirements/pep517-build.txt --require-hashes + pip install --no-deps --no-build-isolation -e . pip install -r .github/requirements/base-deps.txt --require-hashes # NOTE: benchmarks/ does not currently exist in this repo, so this # step and the run below it fail on any real invocation - pre-existing, diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b09155ce..3dc2d7a5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -61,7 +61,16 @@ jobs: # `uv pip compile pyproject.toml --extra explorer --constraint requirements-ci.txt --generate-hashes` # - regenerate it the same way if pyproject.toml's base/explorer # deps change. - pip install --no-deps -e . + # + # --no-deps only skips *runtime* dependency resolution - `-e .` + # still does a PEP 517 build, which by default creates an isolated + # build env and fetches [build-system] requires (setuptools, + # wheel) completely outside any hash checking. Install + # pep517-build.txt (pins that exact build-system.requires) first + # and pass --no-build-isolation so pip reuses those hash-verified + # copies instead of fetching its own. + pip install -r .github/requirements/pep517-build.txt --require-hashes + pip install --no-deps --no-build-isolation -e . pip install -r .github/requirements/explorer-extra.txt --require-hashes pip install -r .github/requirements/pytest-tool.txt --require-hashes - name: Test deterministic Explorer backend path diff --git a/.github/workflows/container-scan.yml b/.github/workflows/container-scan.yml index 7fdd3ffc..2fc8b7bd 100644 --- a/.github/workflows/container-scan.yml +++ b/.github/workflows/container-scan.yml @@ -13,6 +13,7 @@ on: - 'LICENSE' - 'MANIFEST.in' - '.github/requirements/explorer-extra.txt' + - '.github/requirements/pep517-build.txt' - 'semantica/**' - 'integrations/**' - 'explorer/**' diff --git a/Dockerfile b/Dockerfile index e157cceb..eab3f444 100644 --- a/Dockerfile +++ b/Dockerfile @@ -33,7 +33,8 @@ WORKDIR /app RUN groupadd --system semantica \ && useradd --system --gid semantica --home-dir /app --shell /usr/sbin/nologin semantica -COPY pyproject.toml README.md LICENSE MANIFEST.in .github/requirements/explorer-extra.txt ./ +COPY pyproject.toml README.md LICENSE MANIFEST.in \ + .github/requirements/explorer-extra.txt .github/requirements/pep517-build.txt ./ COPY semantica/ ./semantica/ COPY integrations/ ./integrations/ COPY --from=frontend-builder /app/semantica/static ./semantica/static @@ -45,10 +46,16 @@ COPY --from=frontend-builder /app/semantica/static ./semantica/static # setuptools==84.0.0 (which also replaces the base image's vulnerable # 70.3.0, CVE-2025-47273 - nothing else in the tree pulls a newer copy). # --no-deps on the local package itself: it's our own source tree, not a -# fetch, so there's nothing to hash-pin there. -RUN pip install --no-cache-dir -r explorer-extra.txt --require-hashes \ - && pip install --no-cache-dir --no-deps . \ - && rm -f explorer-extra.txt \ +# fetch, so there's nothing to hash-pin there - but `pip install .` still +# does a PEP 517 build, which by default creates an *isolated* build env +# and fetches [build-system] requires (setuptools, wheel) completely +# outside any hash checking. pep517-build.txt pins that exact +# build-system.requires; installing it first and passing +# --no-build-isolation makes pip reuse those hash-verified copies instead +# of fetching its own. +RUN pip install --no-cache-dir -r explorer-extra.txt -r pep517-build.txt --require-hashes \ + && pip install --no-cache-dir --no-deps --no-build-isolation . \ + && rm -f explorer-extra.txt pep517-build.txt \ && chown -R semantica:semantica /app USER semantica