diff --git a/.github/renovate.json5 b/.github/renovate.json5 deleted file mode 100644 index 6d4147d6..00000000 --- a/.github/renovate.json5 +++ /dev/null @@ -1,86 +0,0 @@ -{ - $schema: "https://docs.renovatebot.com/renovate-schema.json", - - // ── Renovate replaces Dependabot for shapepipe ────────────────────────────── - // - // Why the switch: Dependabot's only noise control is grouping, and its - // security channel bypasses even that — so a same-day burst of advisories - // arrives as N separate PRs that a human must merge by hand. Renovate gives a - // single Dependency Dashboard issue plus *branch automerge*: routine updates - // land silently on green CI with no PR at all. The supply-chain posture from - // the old dependabot.yml is carried over below and, via OSV, strengthened. - // - // Requires the Renovate GitHub App (or a self-hosted runner) — see the PR - // body for the one-time org-admin step. - - extends: [ - "config:recommended", - "helpers:pinGitHubActionDigests", // keep GitHub Actions SHA-pinned, as before - ], - - // One issue is the control surface: everything pending lives there, and - // nothing that needs a human decision becomes a PR until ticked. - dependencyDashboard: true, - - // pyproject declares ABSTRACT minimums; uv.lock holds the EXACT pins. Routine - // updates therefore touch only the lockfile — abstract floors change solely by - // deliberate human edit, never by the bot. (This makes the old "floor bumps - // need maintainer sign-off" rule structural rather than a manual hold.) - rangeStrategy: "update-lockfile", - - // Supply-chain cooldown (was 14d / 30d-major in dependabot.yml). 2025-26 saw a - // wave of maintainer-compromise attacks (Shai-Hulud, …); a release-age gate - // lets a malicious version be caught and yanked before it reaches us. - minimumReleaseAge: "14 days", - internalChecksFilter: "strict", // genuinely withhold updates until aged, not "surface as pending" - - // Keep the queue calm. - prConcurrentLimit: 5, - prHourlyLimit: 2, - - // Weekly batched lockfile refresh, merged on green CI — the routine - // "keep uv.lock current" job, fully hands-off. - lockFileMaintenance: { - enabled: true, - schedule: ["before 6am on monday"], - automerge: true, - }, - - // CVE fixes (GitHub alerts + OSV, which adds malicious-package detection) skip - // the long cooldown but keep a short 3-day window, then automerge on green CI — - // fast, not instant. Flip `automerge` to false here if you want eyes on every - // security fix. - osvVulnerabilityAlerts: true, - vulnerabilityAlerts: { - minimumReleaseAge: "3 days", - automerge: true, - labels: ["security"], - }, - - packageRules: [ - { - // Routine minor / patch / digest: batch into ONE weekly branch and land - // silently on green CI — no PR, no noise. (One branch = one container-build - // CI run, which matters since that build is slow.) - matchUpdateTypes: ["minor", "patch", "pin", "digest"], - groupName: "all non-major", - schedule: ["before 6am on monday"], - automerge: true, - automergeType: "branch", - }, - { - // Majors: never silent, never auto. 30-day age, then surface on the - // dashboard for explicit approval before a PR is even opened. - matchUpdateTypes: ["major"], - minimumReleaseAge: "30 days", - dependencyDashboardApproval: true, - }, - { - // ngmix is intentionally pinned to a tag in [tool.uv.sources] - // (esheldon v2.4.0). Tag changes are a deliberate shape-measurement - // decision, not a dependency bump — Renovate must not touch it. - matchDepNames: ["ngmix"], - enabled: false, - }, - ], -} diff --git a/renovate.json b/renovate.json index 9148c8ac..8cbfa34d 100644 --- a/renovate.json +++ b/renovate.json @@ -1,16 +1,25 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", "description": [ - "Low-noise dependency updates; uv owns version resolution. pyproject keeps floor ranges and Renovate uses the org default rangeStrategy=update-lockfile, so `uv lock` picks versions jointly — cross-package conflicts (e.g. numba capping numpy) resolve silently instead of failing the batch, and un-stick themselves when upstream catches up. No minimumReleaseAge: it is unenforceable with uv resolution (renovatebot/renovate#41624 forced exact pins, which forced manual conflict caps); CI running the full suite in the container is the automerge gate.", - "Noise: all non-major updates grouped into one weekly PR that automerges when CI is green; majors surface individually; lockFileMaintenance refreshes transitive deps weekly.", - "python is guarded: Renovate classes base-image bumps like 3.12 -> 3.14 as 'minor', so it gets its own PR and never automerges — a Python upgrade gets human eyes without holding the weekly batch hostage.", - "minimumReleaseAge is EXPLICITLY zeroed, not merely absent: Mend's hosted org layer injects an age gate invisibly, and merely deleting the key here does not override inherited config — artifact updates then fail on every uv-resolved transitive that is younger than the invisible gate (see #816). An explicit '0 days' should win the merge over the inherited value; if artifact errors persist, the gate lives in Mend portal-global settings and must be removed at developer.mend.io." + "THE ONLY Renovate config file — do not add another. A forgotten .github/renovate.json5 (the original Dependabot->Renovate migration config) shadowed this file for weeks: Renovate's config discovery (and Mend's cached config-file name) preferred it, so edits here were silently ignored while its 14-day minimumReleaseAge broke every uv artifact update (renovatebot/renovate#41624). Deleted 2026-07; if Renovate ever again behaves contrary to this file, first check for a second config file (renovate.json5, .github/renovate.json*, .renovaterc*), then the Mend portal's resolved config.", + "Low-noise dependency updates; uv owns version resolution. pyproject keeps floor ranges and rangeStrategy=update-lockfile means `uv lock` picks versions jointly — cross-package conflicts (e.g. numba capping numpy) resolve silently instead of failing the batch, and un-stick themselves when upstream catches up. No minimumReleaseAge anywhere: any age gate is unenforceable with uv resolution (#41624 — uv resolves transitives past the gate and the artifact step fails); CI running the full suite in the container is the automerge gate.", + "Noise: all non-major updates grouped into one weekly PR that automerges when CI is green; majors are gated behind an explicit dashboard-approval tick; lockFileMaintenance refreshes transitive deps weekly. Security fixes (GitHub + OSV alerts) automerge on green CI without waiting for the weekly schedule.", + "python is guarded: Renovate classes base-image bumps like 3.12 -> 3.14 as 'minor', so it gets its own PR and never automerges — a Python upgrade gets human eyes without holding the weekly batch hostage. ngmix is pinned to a tag in [tool.uv.sources] as a deliberate shape-measurement decision — Renovate must not touch it." ], - "extends": ["config:recommended", "group:allNonMajor", "schedule:weekly"], - "minimumReleaseAge": "0 days", + "extends": [ + "config:recommended", + "group:allNonMajor", + "schedule:weekly", + "helpers:pinGitHubActionDigests" + ], + "rangeStrategy": "update-lockfile", "lockFileMaintenance": { "enabled": true }, + "osvVulnerabilityAlerts": true, + "vulnerabilityAlerts": { "automerge": true, "labels": ["security"] }, "packageRules": [ { "matchUpdateTypes": ["minor", "patch", "pin", "digest"], "automerge": true }, - { "matchPackageNames": ["python"], "groupName": "python", "automerge": false } + { "matchUpdateTypes": ["major"], "dependencyDashboardApproval": true }, + { "matchPackageNames": ["python"], "groupName": "python", "automerge": false }, + { "matchDepNames": ["ngmix"], "enabled": false } ] }