ci: test and SBOM against requirements.lock — the versions the image ships - #146
Open
MrChengLen wants to merge 1 commit into
Open
MrChengLen wants to merge 1 commit into
MrChengLen wants to merge 1 commit into
Conversation
…ships The image installs requirements.lock with --require-hashes, but four workflows still installed requirements.txt, whose >= ranges resolve to the newest PyPI releases. So CI tested, and the SBOM described, versions the image does not ship. lint-and-test: installs requirements-dev.txt with the lockfile's pins as constraints. SQLAlchemy 2.1.0 reached CI unpinned and failed a test on every branch while the image stayed on 2.0.52. The hashes are stripped into $RUNNER_TEMP/constraints.txt because pip switches the whole install to --require-hashes as soon as one constraint carries a hash (checked with pip 26.2.1), and the dev tools are unhashed. The step fails if any lockfile entry does not become a constraint, instead of letting it install unpinned. The dev-only tools are not in the lockfile: a pip dry-run for cp314/manylinux resolves them to the same pytest, ruff, uv, aiosqlite, httpx, pip-audit, pyinstaller and bs4 versions as without constraints, and 76 of the 77 locked packages at their locked version (uvloop, Linux-only, was skipped on the Windows host that ran it). A floor raised past the locked version (the usual Dependabot pip PR) now fails this install as well as lockfile-drift; recompiling fixes both. A dev tool that needs a newer locked package fails here with lockfile-drift green; the ci.yml comment gives the --upgrade-package recompile for that case. deps-latest (new): the unpinned install plus pytest, weekly on Mondays and on demand, gating nothing. It keeps the early warning that caught 2.1 before any lockfile bump. Not a continue-on-error job in ci.yml: that still shows a red check on every PR whenever upstream breaks. sbom / release: the SBOM described the runner's own Python after `pip install -r requirements.txt` plus cyclonedx-bom. main's SBOM at 1d7bad6 had 106 components against 77 in the lockfile: 19 at versions the image does not contain, 28 from the generator itself, and packaging downgraded from 26.3 to 25.0 by the generator's install. Now: a fresh venv installed the Dockerfile's way, the generator outside it, and `cyclonedx-py environment <venv python>` (checked with cyclonedx-bom 5.5.0). Rejected `cyclonedx-py requirements requirements.lock`: it parses the hashed lockfile fine but emits no licences and no dependency graph (main's SBOM carries 70 licensed components, 61 graph entries). The docs now say which workflow builds the release SBOM (release.yml, not sbom.yml) and that system packages are not in it. verapdf: built its PDF/A fixture with the newest pikepdf; it now installs the lockfile the image's way (all 77 locked versions have cp314 manylinux wheels). build-desktop.yml still installs requirements.txt: it builds on Windows, the lockfile is Linux-only. docker.yml: renormalized to LF. PR #129 committed it with CRLF via an API commit despite `*.yml text eol=lf`, so every checkout showed it as modified. No content change. tests/test_supply_chain_hygiene.py pins all of it, including that deps-latest keeps lint-and-test's system packages and pytest call; each of 10 simulated reverts fails a guard. Local suite 1239 passed, 63 skipped (native-library tests run in CI); ruff clean; python-version gate green; i18n and pip-audit inputs untouched. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
MrChengLen
force-pushed
the
pr-ci-lockfile-parity
branch
from
September 25, 2026 18:02
744d4a5 to
9a41431
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
The Docker image installs
requirements.lock(pip install --require-hashes). Four workflows still installedrequirements.txt, whose>=ranges resolve to the newest PyPI releases, so CI tested (and the SBOM described) versions the image does not ship. This PR fixes the three findings from the #137/#139 reviews, plus the same defect in the veraPDF gate.ci.yml→lint-and-testpip install -r requirements-dev.txt(unpinned; SQLAlchemy 2.1.0 in CI vs 2.0.52 in the image)-cwith the lockfile's pins (hashes stripped)deps-latest.ymlsbom.yml,release.ymlpip install -r requirements.txt+ the generatorverapdf.ymlpip install -r requirements.txtpip install --require-hashes -r requirements.lockdocker.ymlDetails
-c: pip turns on--require-hashesfor the whole install as soon as a single constraint carries a hash, and the dev tools are unhashed (reproduced with pip 26.2.1: "In --require-hashes mode, all requirements must have their versions pinned with =="). The step fails with an::error::if any lockfile entry didn't become a constraint (checked against an extras line, a URL line and an empty lock), instead of letting that package install unpinned.-c: ruff, uv, aiosqlite, pytest, httpx, pip-audit, pyinstaller and bs4 aren't in the lockfile, so-cleaves them alone. A pip dry run for cp314/manylinux resolves them to the same versions as without constraints, and resolves 76 of the 77 locked packages at their locked version. The 77th,uvloop, is Linux-only and was skipped because the dry run ran on Windows. A dependency they share with the app (packaging, requests, …) stays at its locked version.ci.ymlanddependabot.yml:lint-and-test's install as well aslockfile-drift. Recompiling the lockfile fixes both.lint-and-testfails whilelockfile-driftstays green. The comment inci.ymlgives theuv pip compile --upgrade-package <name>recompile for that case, which doesn't change the lockfile header.continue-on-errorstill puts a red check on every PR whenever upstream breaks. That's the noise this PR removes. A guard test keepsdeps-latest's system packages and pytest call in step withlint-and-test, so a red weekly run really does point at upstream.1d7bad6): 106 components against 77 in the lockfile. 19 of them had versions the image doesn't contain (SQLAlchemy 2.1.1 vs 2.0.52). 28 belong to the generator itself, and its install had downgradedpackagingfrom 26.3 to 25.0.cyclonedx-py requirements requirements.lockwas considered. It parses the hashed lockfile fine, but its SBOM has no licences and no dependency graph (main's SBOM has 70 licensed components and 61 graph entries).environmentstays, pointed at the lockfile venv. That was checked locally with cyclonedx-bom 5.5.0.pip.pip's own version follows the runner's Python patch release.development.mdandthird-party-licenses.mdsaidsbom.ymlbuilds the release SBOM, but that'srelease.ymlsince fix(ci): attach SBOM from release.yml #52.patch-policy.mdnow says what the SBOM covers: the app's Python dependencies at the shipped versions, not system packages.tests/test_supply_chain_hygiene.pypins all of it, and each of 10 simulated reverts fails a guard.Not in this PR (pre-existing, flagged by the security review)
contents: write, restores the shared pip cache and keeps the checkout's credentials. This PR cuts the unverified install there from about 105 packages to about 28.build-desktop.ymlhas never run: itsrelease: publishedtrigger doesn't fire for releases published withGITHUB_TOKEN.release.ymlfeeds a tag-derived${{ }}value into a shell script, andverapdf/cli:latestis unpinned.Verification
lint-and-testruns the constrained install, which is also the first full test run against the locked versions in a while.verapdfruns the lockfile install.sbom.ymlis dispatched on this branch; its artifact gets checked against the lockfile.release.ymlonly runs on tags. Its SBOM step runs the same commands assbom.yml.deps-latest.ymlcan only be dispatched once it is onmain, so it gets one manual run after merge.🤖 Generated with Claude Code