#6595·ogx

Enforce pyproject.toml version caps with dependabot ignore rules (dependabot silently widens caps)

Author: mattfCreated Sep 19, 2026Updated Sep 19, 2026
Labelsdependenciestech-debt

What is the technical debt you think should be addressed?

Dependabot does not treat version caps in pyproject.toml as policy — it rewrites them to reach the latest release.

Incident. After the grouped python-deps config shipped (#6566), the first grouped run (PR #6587, 2026-09-18) immediately widened mcp >=1.28.1,<2.0mcp >=2.2.0,<3.0. mcp 2.x is breaking (HTTP redirect origin restriction, OAuth issuer validation, 30-min session expiry). Per-package runs had not widened it in 7.5 weeks, so the grouping change masked the mechanism.

Mechanism (verified in dependabot-core source). For any non-lockfile-only update strategy, the checker takes the :own-requirements-unlock path (update_all_versions.rb / group_update_creation.rb, identical logic, tried first). Its version discovery — latest_versionfetch_latest_release (package_latest_version_finder.rb) — never consults the existing requirement; only the lockfile-only path (latest_resolvable_version_with_no_unlockfilter_out_of_range_versions) does. The updater then mechanically rewrites the range around the target (BumpVersions: >=1.28.1,<2.0>=2.2.0,<3.0).

So any dependency with a < cap is one dependabot run away from having the cap widened. Current caps (9, across two manifests, post-#6587):

Dependency Cap Root cause issue
mcp <2.0
fastapi (root) >=0.115.0,<0.137 (CI workaround) #6594
fastapi (src/ogx_api) >=0.136.3,<1.0
elasticsearch >=9.5.1,<10.0.0
google-genai >=2.23.0,<3
transformers >=4.57.2,<5.0.0 #6588
setuptools <81
openai >=2.41.0,<2.44 (recorder bug) #6593
langchain-openai >=1.2.2,<1.3 (recorder bug) #6593

The supported enforcement mechanism is the ignore directive in .github/dependabot.yml. Group update-types is not sufficient — it only moves a major update out of the group; the individual PR would still widen the cap.

What is the benefit of addressing this technical debt?

  • Caps actually hold: dependabot may only move the floor within the cap (e.g. mcp 1.28.1 → 1.30.x, still <2.0).
  • No more manual reverts of dependabot PRs that widened a cap (#6587 already needed three: mcp, openai/langchain-openai, fastapi).
  • A documented, repeatable pattern for every future pin.

Other thoughts

Proposed change (small config PR against main, no lockfile changes):

  1. .github/dependabot.yml: add ignore rules mirroring every cap, in both uv sections:

    Section Ignore Versions
    / fastapi >=0.137.0
    / openai >=2.44.0
    / langchain-openai >=1.3.0
    / mcp >=2.0.0
    / elasticsearch >=10.0.0
    / google-genai >=3.0.0
    / transformers >=5.0.0
    / setuptools >=81
    /src/ogx_api fastapi >=1.0.0

    The PR lands directly on main so the next weekly dependabot run is protected immediately. The openai / langchain-openai / fastapi >=0.137.0 ignores are preemptive until #6587 merges — harmless, since they only ignore versions no current manifest can reach.

  2. pyproject.toml (root + src/ogx_api): comment on each capped dependency noting the cap is enforced by the matching ignore rule and both must change in the same PR.

Trade-off (documented in the YAML): ignore also filters security advisories (filter_ignored_versions runs in lowest_security_fix_version). A CVE fixed only at/above a cap will not get a dependabot security PR — a manual cap+ignore lift is required in that case.

Related: #6587 (incident PR), #6593 (openai <2.44 cap / API recorder), #6594 (fastapi <0.137 cap / route introspection), #6588 (transformers 5.x migration).