Adopt pip-compile for Python dependency management - #380
Conversation
Manually hand-editing transitive pins in requirements.txt is what caused #378: bracex was pinned below the version wcmatch itself requires, and nothing caught the mismatch. Introduce requirements.in as the source of truth for direct dependencies (pyspelling, pymdown-extensions) and generate requirements.txt via `pip-compile`, so pip's own resolver enforces compatible transitive versions instead of relying on manual curation. This is a minimal-diff regeneration: only bracex/wcmatch move (to the same compatible versions as #379), everything else stays pinned as before. `backrefs` and `zipp` are dropped since pip-compile's resolver confirms neither is actually part of the dependency graph for pyspelling + pymdown-extensions on Python 3.14 — they were stale manual additions, not active mitigations, so removing them is not a security regression. .github/dependabot.yml already sets `versioning-strategy: lockfile-only` for the pip ecosystem, which is designed for exactly this requirements.in/requirements.txt split. No change needed there; this commit's requirements.in makes that existing setting apply correctly, and CLAUDE.md documents the new workflow. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR formalizes Python dependency management for the Docker image by introducing a pip-tools (pip-compile) workflow: requirements.in becomes the direct-dependency manifest, and requirements.txt is treated as the generated, fully pinned lockfile to prevent transitive pin drift (the root cause class behind #378/#379).
Changes:
- Add
requirements.into explicitly declare direct dependencies (pyspelling,pymdown-extensions). - Regenerate
requirements.txtviapip-compile(minimal diff) to pin a compatiblebracex==3.0.1/wcmatch==11.0pair and remove stale pins (backrefs,zipp). - Document the new dependency update workflow and Dependabot expectations in
CLAUDE.md.
Reviewed changes
Copilot reviewed 2 out of 3 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| requirements.txt | Switch to a pip-compile-generated, fully pinned lockfile (including bracex/wcmatch correction and removal of stale pins). |
| requirements.in | Introduce a manifest for direct Python dependencies used to generate requirements.txt. |
| CLAUDE.md | Document the pip-compile workflow and clarify how Dependabot’s lockfile-only strategy aligns with requirements.in/requirements.txt. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…mage contents Both techniques were used to investigate and verify the #378 fix in this PR: overriding INPUT_CONFIG_PATH to reproduce the reporter's real config, and pulling the published image directly to see what pip actually installed versus what requirements.txt says. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
@copilot resolve the merge conflicts in this pull request |
Resolved the merge conflicts by merging |
Documents the pip-compile dependency management migration (PR #380), including the backrefs/zipp removal and why it doesn't reintroduce CVE-2024-5569. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ment # Conflicts: # CHANGELOG.md
Summary
requirements.inas the source of truth for genuinely direct dependencies (pyspelling,pymdown-extensions— the latter is used directly viapymdownx.superfencesin this repo's ownspellcheck.yamlandexamples/markdown.yml).requirements.txtis now generated fromrequirements.inviapip-compile(pip-tools) instead of hand-maintained. It's still a fully pinned file installed as-is by the Dockerfile — no Dockerfile changes needed.bracex/wcmatchmove (to the same compatible pair as Bump bracex from 2.5.post1 to 3.0.1 to fix glob source matching #379 —bracex==3.0.1,wcmatch==11.0); every other package stays at its currently pinned version. A full--upgraderesolve was available but intentionally not used here to avoid bundling unrelated version bumps (beautifulsoup4, lxml, Markdown, PyYAML, six, soupsieve all have newer releases available) into a tooling-adoption PR — those stay as their own deliberate, individually-reviewed PRs as before.backrefsandzippare dropped. Neither shows up anywhere in the resolved dependency graph forpyspelling+pymdown-extensionson Python 3.14 (verified via each package's own declared metadata) — they were stale manual pins (thezippcomment even said "not directly required, pinned by Snyk to avoid a vulnerability"), not active dependencies, so removing them is not a security regression..github/dependabot.yml's pip entry already setsversioning-strategy: lockfile-only, which is specifically designed for arequirements.in(manifest) + generatedrequirements.txt(lockfile) pair. No change needed there — this PR just makes that existing setting apply the way it was presumably intended, so Dependabot should now be able to bump transitive pins likebracexon its own going forward.CLAUDE.md(Development Commands + Key Files + Dependabot Gotchas).Does removing
zippreintroduce a vulnerability?No.
zipp>=3.19.1was originally pinned in PR #204 (changelog0.39.0) to patch CVE-2024-5569, because at the timepyspellingpulled inimportlib-metadata, which depends onzipp.That chain no longer exists:
pyspelling==2.12.1's own declared metadata (Requires-Dist) lists onlybeautifulsoup4, html5lib, lxml, markdown, pyyaml, soupsieve, wcmatch— noimportlib-metadata, conditional or otherwise.pip3 listinside the rebuilt image (13 packages total) has neitherimportlib-metadatanorzipp.So
zippisn't installed in the image at all, pinned or not — a package that's absent can't be exploited through this image. The old pin was a vestigial defensive measure for a dependency edge thatpyspellinghas since dropped (likely once its minimum Python requirement rose past the point of needing theimportlib-metadatabackport). Same reasoning applies tobackrefs, which was never a declared dependency ofpymdown-extensionsat the pinned version.Verification
requirements.txt(docker build -t jonasbn/github-action-spellcheck:pipcompile .) and confirmed installed versions match (bracex==3.0.1,wcmatch==11.0, nobackrefs/zipp).arkq/bluez-alsa's.github/spellcheck.yaml, pattern**/*.{c,h}|!build/**) against this image — passes.spellcheck.yaml— passes.pre-commit runon the changed files — passes.Test plan
requirements.txtviapip-compilewith a minimal diffbackrefs/zippare genuinely unused (checked each package's declared metadata)spellcheck.yamlpre-commithooks passCLAUDE.mddocuments the newpip-compileworkflow🤖 Generated with Claude Code