From cb86d4f472a7041836116269bfe42b1605eb47c7 Mon Sep 17 00:00:00 2001 From: JacobPEvans <20714140+JacobPEvans@users.noreply.github.com> Date: Sun, 24 May 2026 18:54:37 -0400 Subject: [PATCH 1/2] fix(renovate): major-only Python lower-bound bumps + 30-day major grace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR #343 made `rangeStrategy: bump` apply to every release for pep621/pip_requirements/pip_setup/poetry/pipenv, so the `>=` floor moved on minor and patch releases too. That floods consumer repos with PRs that only re-state the floor at the latest pinpoint version — no security or compatibility signal behind them. Two changes: 1. 30-day grace period for any major-version update, org-wide. Gives upstream ecosystems time to surface breaking regressions before we adopt. CVE bumps still bypass via `vulnerabilityAlerts` (0 days). 2. Restrict the Python `>=` bump rule to `matchUpdateTypes: ["major"]`. Minor/patch updates now fall back to Renovate's default `replace` strategy, which no-ops when the existing range already satisfies the new version — exactly what we want for security/compatibility floors. After this, Renovate still produces `>=N.M.P` (e.g. `>=1.16.1`) on major bumps. Follow-up: a reusable normalization workflow that rewrites those to `>=N.0.0` so floors only express the major version. --- renovate-presets.json | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/renovate-presets.json b/renovate-presets.json index b5400c1..60cb826 100644 --- a/renovate-presets.json +++ b/renovate-presets.json @@ -65,6 +65,11 @@ ], "enabled": false }, + { + "description": "30-day grace period for any major-version update, org-wide. Gives upstream ecosystems time to surface breaking-change regressions before we adopt them. CVE-driven bumps still bypass via the top-level vulnerabilityAlerts block (0 days). Trusted-org rules later in the file override per-attribute settings like automerge, but their minimumReleaseAge values yield to this rule for major updates — Renovate merges packageRule attributes by last-match wins per key, so this 30-day floor applies whenever a later rule does not set minimumReleaseAge itself.", + "matchUpdateTypes": ["major"], + "minimumReleaseAge": "30 days" + }, { "description": "Never auto-merge major updates - require human review (overridden by trusted package rules below)", "matchUpdateTypes": ["major"], @@ -230,8 +235,9 @@ "schedule": ["after 7am on Monday", "after 7am on Thursday"] }, { - "description": "Bump Python `>=` lower bounds so they track the latest released version. Without this, Renovate's default `auto` strategy (= `replace` for pep621/pip_requirements) leaves `pyarrow>=17.0.0` untouched forever even when 24.x is current — the existing range already satisfies the new version, so `replace` no-ops. Setting `bump` forces the lower bound to move with each release, keeping security floors current. Mirrors the `rangeStrategy: bump` already used inside `vulnerabilityAlerts` so routine and CVE-driven bumps behave identically.", + "description": "Bump Python `>=` lower bounds ONLY on major releases. Minor/patch releases never trigger a floor bump because the floor expresses a security/compatibility major, not the latest released version — Renovate's default `replace` strategy already no-ops when the existing range satisfies the new version. Major bumps produce a `>=N.M.P` floor (e.g. `>=1.16.1`); see issue tracking the follow-up normalization workflow that rewrites that to `>=N.0.0`. CVE-driven bumps still use `bump` at all update types via the top-level `vulnerabilityAlerts` block.", "matchManagers": ["pep621", "pip_requirements", "pip_setup", "poetry", "pipenv"], + "matchUpdateTypes": ["major"], "rangeStrategy": "bump" } ] From b21f45eaab6c29519571ad0533d192c30ad01f29 Mon Sep 17 00:00:00 2001 From: JacobPEvans <20714140+JacobPEvans@users.noreply.github.com> Date: Sun, 24 May 2026 19:10:06 -0400 Subject: [PATCH 2/2] docs(renovate): spell out CVE-pin exception to major-only floor policy The bump rule now states the full policy: - Default: floors are `>=N.0.0` (major only). - CVE exception: pin to the OLDEST secure version (not latest) and document every CVE in an inline comment block above the floor. - Normalizer must preserve floors preceded by such a comment block. Canonical pattern lives in mlx-benchmarks/space/requirements.txt (pyarrow, pillow, orjson, idna). --- renovate-presets.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/renovate-presets.json b/renovate-presets.json index 60cb826..5a64a74 100644 --- a/renovate-presets.json +++ b/renovate-presets.json @@ -235,7 +235,7 @@ "schedule": ["after 7am on Monday", "after 7am on Thursday"] }, { - "description": "Bump Python `>=` lower bounds ONLY on major releases. Minor/patch releases never trigger a floor bump because the floor expresses a security/compatibility major, not the latest released version — Renovate's default `replace` strategy already no-ops when the existing range satisfies the new version. Major bumps produce a `>=N.M.P` floor (e.g. `>=1.16.1`); see issue tracking the follow-up normalization workflow that rewrites that to `>=N.0.0`. CVE-driven bumps still use `bump` at all update types via the top-level `vulnerabilityAlerts` block.", + "description": "Bump Python `>=` lower bounds ONLY on major releases, and only to `>=N.0.0` form. The floor expresses the oldest acceptable major; minor/patch positions are reserved exclusively for CVE-mitigation pins. Minor/patch releases never trigger a floor bump — Renovate's default `replace` strategy already no-ops when the existing range satisfies the new version. Renovate's pep440 `bump` produces `>=N.M.P` natively; the companion normalizer workflow (follow-up issue in this repo) rewrites it to `>=N.0.0` after the PR opens. CVE EXCEPTION: when a known CVE is fixed only in a specific minor/patch release, pin the floor to the OLDEST secure version (e.g. `pyarrow 17.0.0 → PYSEC-2026-113 fixed in 23.0.1` → `pyarrow>=23.0.1`), NEVER the latest release. An inline comment block citing every CVE identifier the floor mitigates is REQUIRED above any floor that exceeds `>=N.0.0` form — see `mlx-benchmarks/space/requirements.txt` for the canonical pattern. The normalizer must preserve floors preceded by such a comment block. CVE-driven Renovate bumps themselves still use `bump` at all update types via the top-level `vulnerabilityAlerts` block, so security floor bumps remain immediate.", "matchManagers": ["pep621", "pip_requirements", "pip_setup", "poetry", "pipenv"], "matchUpdateTypes": ["major"], "rangeStrategy": "bump"