From 92aa8bd0ced130fdf3f0ba549d217a030dceef90 Mon Sep 17 00:00:00 2001 From: Lars Trieloff Date: Fri, 28 Aug 2026 11:45:50 +0200 Subject: [PATCH 1/2] fix: exempt untimestamped update types from minimumReleaseAge The `external fixes` and `external major` groups apply `minimumReleaseAge: "14 days"`, but several update types carry no usable release timestamp, so Renovate can never mark them as having met the requirement. Because the `renovate/stability-days` status check is computed per branch and any single pending member turns the whole branch yellow, one such update strands the entire grouped PR in a permanently pending state. Since `internalChecksAsSuccess` defaults to false, that silently blocks automerge indefinitely -- waiting does not clear it. Null out `minimumReleaseAge` for the update types Renovate documents as unsupported (pin, pinDigest, bump, lockfileUpdate, lockFileMaintenance, rollback, replacement), mirroring the carve-outs in Renovate's own `security:minimumReleaseAge*` presets, and relax `digest` to `timestamp-optional` to work around renovatebot/renovate#45236. Also enable `osvVulnerabilityAlerts`, which blocks updates to versions OSV has flagged as malicious regardless of age. This covers the case a release-age window structurally cannot: a compromised version that is never detected within the quarantine period. The 14-day window itself is unchanged. --- default.json | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/default.json b/default.json index b7bea768..1cd8615d 100644 --- a/default.json +++ b/default.json @@ -5,6 +5,7 @@ ], "timezone": "Europe/Zurich", "branchPrefix": "renovate-", + "osvVulnerabilityAlerts": true, "hostRules": [ { "matchHost": "registry.npmjs.org", @@ -87,6 +88,24 @@ "schedule": ["after 2pm on Monday"], "minimumReleaseAge": "14 days" }, + { + "description": "Renovate cannot enforce a minimum release age on these update types, because they carry no usable release timestamp. Leaving them subject to `minimumReleaseAge` makes the branch-level `renovate/stability-days` check go permanently yellow, which silently blocks automerge forever. Mirrors the carve-outs in Renovate's own `security:minimumReleaseAge*` presets.", + "matchUpdateTypes": [ + "pin", + "pinDigest", + "bump", + "lockfileUpdate", + "lockFileMaintenance", + "rollback", + "replacement" + ], + "minimumReleaseAge": null + }, + { + "description": "Digest updates do have a release timestamp at lookup time, but the branch stage does not always carry it forward (renovatebot/renovate#45236), which strands the stability check in a permanently pending state. Accept a timestamp when one is available instead of requiring it.", + "matchUpdateTypes": ["digest"], + "minimumReleaseAgeBehaviour": "timestamp-optional" + }, { "matchDatasources": ["orb"], "matchUpdateTypes": ["patch", "minor"], From d67cc0c92396f1761d84cba3fe5baf9c8ccc5901 Mon Sep 17 00:00:00 2001 From: Lars Trieloff Date: Fri, 28 Aug 2026 11:58:00 +0200 Subject: [PATCH 2/2] fix: split external dev dependencies into their own Renovate group The `renovate/stability-days` status check is computed per branch, not per package, so a single member still inside its minimum release age turns the whole grouped branch yellow and blocks automerge. With every external dependency in one group, that check is yellow most of the time. Split dev dependencies out of `external fixes` and `external major` into `external dev fixes` and `external dev major`. On helix-cli this halves the group size (44 runtime vs 16 dev at the root manifest), so each group reaches a fully-aged state far more often. Uses `matchDepTypes` rather than package names, so the split reads npm's own manifest sections and needs no maintenance as dependencies change. This is Renovate's documented grouping idiom. The two existing rules are left byte-for-byte unchanged. The new rules are appended after them, so they override only `groupName` and inherit `automerge`, `schedule` and `minimumReleaseAge` from the rule above. The catch-all rules deliberately keep no `matchDepTypes`, so anything that is not a devDependency -- runtime, optional and peer deps, npm `engines`, and every non-npm manager such as github-actions or dockerfile -- keeps its grouping and its 14-day minimum release age. The 14-day window itself is unchanged. --- default.json | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/default.json b/default.json index 1cd8615d..1b451eca 100644 --- a/default.json +++ b/default.json @@ -88,6 +88,22 @@ "schedule": ["after 2pm on Monday"], "minimumReleaseAge": "14 days" }, + { + "description": "Split dev dependencies out of the two external groups above, so each group is smaller. The `renovate/stability-days` check is computed per branch, so any single member still inside its minimum release age holds the whole group back; smaller groups reach a fully-aged state more often. Split by depType rather than by package name so it needs no maintenance as dependencies change. These rules come after the two catch-all rules above and therefore override their `groupName`; the catch-alls deliberately keep no `matchDepTypes`, so anything that is not a devDependency -- runtime, optional and peer deps, npm `engines`, and every non-npm manager such as github-actions or dockerfile -- keeps its grouping and its 14-day minimum release age.", + "groupName": "external dev fixes", + "matchDepTypes": ["devDependencies"], + "matchUpdateTypes": ["patch", "pin", "digest", "minor"], + "matchPackagePatterns": ["^.+"], + "excludePackagePatterns": ["^@adobe/"] + }, + { + "description": "Same dev/runtime split as above, for major updates.", + "groupName": "external dev major", + "matchDepTypes": ["devDependencies"], + "matchUpdateTypes": ["major"], + "matchPackagePatterns": ["^.+"], + "excludePackagePatterns": ["^@adobe/"] + }, { "description": "Renovate cannot enforce a minimum release age on these update types, because they carry no usable release timestamp. Leaving them subject to `minimumReleaseAge` makes the branch-level `renovate/stability-days` check go permanently yellow, which silently blocks automerge forever. Mirrors the carve-outs in Renovate's own `security:minimumReleaseAge*` presets.", "matchUpdateTypes": [