Skip to content

ci: reject git-ref dependencies in pyproject.toml - #104

Merged
deanq merged 2 commits into
mainfrom
deanq/guard-no-git-deps
Jul 28, 2026
Merged

ci: reject git-ref dependencies in pyproject.toml#104
deanq merged 2 commits into
mainfrom
deanq/guard-no-git-deps

Conversation

@deanq

@deanq deanq commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Stacked on #103 — review/merge that first. Base retargets to main automatically once #103 lands.

Problem

A git-ref dependency in pyproject.toml fails in two distinct ways, and #103 hit both:

  1. It silently defeats the bump workflow. Bump Runtime Dependencies bumps by diffing versions out of uv.lock. A git source has no version to bump, so the package quietly stops being tracked — no error, no signal.
  2. It hard-fails once the branch is deleted. A branch ref is mutable. When feat: bundle local (non-pip) modules for serverless endpoints runpod/flash#352 merged and its branch was deleted, every uv lock / uv sync on main started failing with couldn't find remote ref. main was broken for two weeks before anyone noticed, because the only thing exercising it was a scheduled job.

The temporary pin in a44da63 had a comment saying to revert it after release. The comment was correct and got missed anyway — a comment is not an enforcement mechanism.

Fix

scripts/check_git_deps.py fails if any dependency comes from a git ref, covering the four places one can enter a uv project:

  • project.dependencies
  • project.optional-dependencies.<extra>
  • dependency-groups.<group> (PEP 735)
  • [tool.uv.sources] entries with a git key

Wired into make quality-check (so the pre-commit hook catches it locally) and the CI lint job (so it blocks PRs).

Test plan

Built test-first — the checker did not exist when the tests were written, and they failed on the missing module before implementation.

  • 10 unit tests: each of the four git-ref locations flagged, released constraints accepted, multiple offenders all reported, main() exit codes, missing/unparseable file handling
  • A test asserting the repo's own pyproject.toml is clean, so the guard is self-checking
  • Regression-verified against the real offender: run against a44da63's pyproject.toml, the checker exits 1 and names the runpod-flash git pin. Against the fixed tree it exits 0.
  • make quality-check: 293 passed (283 existing + 10 new), coverage 81.52%, ruff + mypy clean

Note on the escape hatch

This blocks a legitimate pattern: the temporary pin during a coordinated cross-repo release, which is exactly what a44da63 was doing. There is deliberately no bypass flag — the module docstring directs you to land an explicit, time-boxed exception rather than delete the check. If that friction proves wrong in practice, an allowlist keyed to an expiry date would be the better shape, but I would not add it before there is a second real instance to design against.

deanq added 2 commits July 28, 2026 01:16
The temporary git pin added in a44da63 (SLS-360) referenced branch
deanquinanola/sls-360-local-module-bundling, which was deleted when
runpod/flash#352 merged. Any uv lock/sync on main has failed since with
"couldn't find remote ref", breaking the scheduled Bump Runtime
Dependencies workflow.

runpod-flash 1.19.0 is the first release containing
runpod_flash.runtime.module_loader, so the pin can now be replaced with
the released constraint the original comment called for.

- pyproject.toml: git ref -> runpod-flash>=1.19.0
- uv.lock: runpod-flash 1.18.0 (git) -> 1.19.0 (registry)
- uv.lock: runpod 1.10.2.dev1 (runpod-python git main) -> 1.10.1
  (registry); the git source was pulled in transitively by the flash
  branch pin and is not intended
A git-ref dependency carries no version, so the Bump Runtime Dependencies
workflow has nothing to bump and silently stops tracking that package.
The ref is also mutable: when the referenced branch is deleted, every
uv lock and uv sync on main hard-fails with "couldn't find remote ref".

Both failure modes happened for real. A temporary pin to a flash feature
branch (a44da63) silently defeated the bump workflow, then broke main for
two weeks once the branch was deleted post-merge.

Adds scripts/check_git_deps.py, covering the four places a git ref can
enter a uv project: project dependencies, optional-dependency extras,
PEP 735 dependency groups, and [tool.uv.sources]. Wired into
make quality-check and the CI lint job, so it blocks locally and on PRs.

Verified against the offending commit: the checker exits 1 and names
the runpod-flash git pin from a44da63's pyproject.toml.
Base automatically changed from deanq/sls-360-unpin-flash-release to main July 28, 2026 17:57
@deanq
deanq merged commit 84d405b into main Jul 28, 2026
@deanq
deanq deleted the deanq/guard-no-git-deps branch July 28, 2026 17:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants