Skip to content

Improved Renovate handling of CVE-driven dependency updates#28040

Merged
9larsons merged 2 commits into
mainfrom
chore/renovate-security-pr-handling
May 25, 2026
Merged

Improved Renovate handling of CVE-driven dependency updates#28040
9larsons merged 2 commits into
mainfrom
chore/renovate-security-pr-handling

Conversation

@9larsons
Copy link
Copy Markdown
Contributor

@9larsons 9larsons commented May 21, 2026

Summary

CVE-driven dependency updates have been getting stranded for weeks. Renovate's weekend-only schedule and the dashboard-approval gate for major bumps apply equally to security PRs, so a green-CI security patch can sit until merge conflicts pile up. Examples: #27595 (postcss, two medium CVEs) stayed open 23+ days; #25456 (js-yaml security) merged after 141 days.

What this changes

.github/renovate.json5:

  • New vulnerabilityAlerts block. Security PRs skip the weekend schedule and the dashboard-approval gate, and are rebased on every Renovate run so conflicts don't strand them.
  • New packageRule: automerge non-major security updates. Security patch/minor/digest updates automerge after CI passes, overriding other automerge exclusions inherited from the shared preset. Security majors still require a human merge, but no longer sit indefinitely behind the dashboard-approval gate — they open on their own once the release-age soak passes.

What this deliberately does not change

  • The 72h release-age soak. It still applies to security updates — the vulnerabilityAlerts block keeps minimumReleaseAge: "3 days", matching security:minimumReleaseAgeNpm from the shared preset. This is the window for malware scanners to catch a compromised publish, and "it's a security fix, merge it fast" is exactly the framing a supply-chain attacker uses. The soak gates automerge only, so a genuinely-exploited 0-day can still be merged by hand sooner.
  • The dashboard-approval gate for non-security major bumps.
  • The schedule and automerge windows for non-security updates.

Test plan

  • CI passes (renovate.json5 is parsed by Renovate, not Ghost CI — success here is JSON5 validity)
  • After merge: the next Renovate run reflects the new config on open security PRs without needing them reopened

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 21, 2026

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 096c3f34-4768-4bb6-9aed-746d84e0d5e0

📥 Commits

Reviewing files that changed from the base of the PR and between c3c6554 and 6f92f84.

📒 Files selected for processing (1)
  • .github/renovate.json5

Walkthrough

This PR updates the Renovate configuration to automate handling of security vulnerability alerts. It adds a vulnerabilityAlerts block that schedules updates at any time, rebases when behind the base branch, requires a 3-day minimum release age, disables dependency-dashboard approval, and applies dependencies/security labels. It also adds a packageRules entry to automerge CI-passing non-major vulnerability-alert updates (patch, minor, digest) and create the automerge result as a PR (automergeType: "pr").

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Improved Renovate handling of CVE-driven dependency updates' directly and clearly summarizes the main change, which is enhancing Renovate configuration to better handle security-driven updates.
Description check ✅ Passed The description thoroughly explains the motivation, specific changes to renovate.json5, deliberate non-changes, and test plan, all directly related to the changeset and objectives.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch chore/renovate-security-pr-handling

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

- security PRs were stranded for weeks behind the weekend schedule and
  the dashboard-approval gate, then went stale from merge conflicts
- adds a vulnerabilityAlerts override so CVE updates skip the weekend
  schedule and dashboard gate and stay rebased against main; the 72h
  release-age soak is kept so a malicious "fix" publish can't fast-track
- adds a packageRule to automerge non-major security updates after CI;
  security majors still wait for human review
@9larsons 9larsons force-pushed the chore/renovate-security-pr-handling branch from 50ab52e to c3c6554 Compare May 21, 2026 15:43
@9larsons 9larsons enabled auto-merge (squash) May 21, 2026 15:45
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/renovate.json5:
- Around line 58-69: The Renovate config is incorrectly targeting vulnerability
alerts: keep the top-level "vulnerabilityAlerts" block but remove reliance on
"minimumReleaseAge" for security PR throttling and stop using the unsupported
"isVulnerabilityAlert" inside "packageRules"; instead move any rules that should
apply to vulnerability/security alerts into an "alertPackageRules" array and
explicitly match the update types you want (e.g., "matchUpdateTypes":
["patch","minor","digest"]) or other supported matchers, and ensure
automerge/approval settings that would fast-track alerts are not applied in
normal "packageRules" but are handled via "alertPackageRules" so security alerts
are not auto-merged before the intended delay.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c938e3d2-2d6b-40e5-9d12-395ffe4c52ff

📥 Commits

Reviewing files that changed from the base of the PR and between 50ab52e and c3c6554.

📒 Files selected for processing (1)
  • .github/renovate.json5

Comment thread .github/renovate.json5
Comment on lines +58 to +69
// CVE-driven updates skip the weekend schedule and the dashboard-
// approval gate, and stay rebased against main so conflicts don't
// strand them. The 72h release-age soak is deliberately kept so a
// malicious "fix" publish can't fast-track into main. Automerge is
// configured per update-type in packageRules below so security
// majors still wait for human review.
"vulnerabilityAlerts": {
"schedule": ["at any time"],
"rebaseWhen": "behind-base-branch",
"minimumReleaseAge": "3 days",
"dependencyDashboardApproval": false,
"labels": ["dependencies", "security"]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate and print relevant parts of the file with line numbers
file=".github/renovate.json5"
if [ ! -f "$file" ]; then
  echo "Missing $file"
  exit 1
fi

echo "== File: $file (line count) =="
wc -l "$file"

echo
echo "== Lines 45-90 =="
nl -ba "$file" | sed -n '45,95p'

echo
echo "== Lines 220-300 =="
nl -ba "$file" | sed -n '220,310p'

echo
echo "== Search for vulnerabilityAlerts / packageRules occurrences =="
rg -n "vulnerabilityAlerts|isVulnerabilityAlert|packageRules" "$file"

Repository: TryGhost/Ghost

Length of output: 214


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate and print relevant parts of the file with line numbers
file=".github/renovate.json5"
if [ ! -f "$file" ]; then
  echo "Missing $file"
  exit 1
fi

echo "== File: $file (line count) =="
wc -l "$file"

echo
echo "== Lines 45-90 =="
nl -ba "$file" | sed -n '45,95p'

echo
echo "== Lines 220-300 =="
nl -ba "$file" | sed -n '220,310p'

echo
echo "== Search for vulnerabilityAlerts / packageRules occurrences =="
rg -n "vulnerabilityAlerts|isVulnerabilityAlert|packageRules" "$file"

Repository: TryGhost/Ghost

Length of output: 214


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file=".github/renovate.json5"
[ -f "$file" ] || { echo "Missing $file"; exit 1; }

echo "== File: $file (line count) =="
wc -l "$file"
echo

echo "== Lines 45-95 =="
awk 'NR>=45 && NR<=95 {printf "%5d\t%s\n", NR, $0}' "$file"
echo

echo "== Lines 220-295 =="
awk 'NR>=220 && NR<=295 {printf "%5d\t%s\n", NR, $0}' "$file"
echo

echo "== Search for vulnerabilityAlerts / isVulnerabilityAlert / packageRules occurrences =="
rg -n "vulnerabilityAlerts|isVulnerabilityAlert|packageRules" "$file"

Repository: TryGhost/Ghost

Length of output: 6155


🌐 Web query:

Renovate vulnerabilityAlerts minimumReleaseAge semantics vulnerability alerts PRs skip minimumReleaseAge

💡 Result:

In Renovate, security-related updates automatically bypass the minimumReleaseAge check, allowing them to be raised as pull requests (PRs) as soon as they are detected [1][2]. Because these updates are prioritized for remediating known vulnerabilities, they do not wait for the release age threshold to pass [2]. Regarding the semantics of minimumReleaseAge, it is important to understand that Renovate does not wait for a package to stop receiving new releases; rather, it applies the waiting period to each specific version independently [1][2]. If multiple versions are released in quick succession, Renovate will evaluate each one against the threshold [1][2]. By default (as of Renovate 42), the internalChecksFilter is set to strict, meaning Renovate will not create branches or PRs for any updates that have not yet met the minimum release age requirements [2]. While security updates generally bypass this age check, there are known edge cases and complexities: 1. Vulnerability Detection: While dedicated security PRs (often triggered by platforms like GitHub or OSV) bypass the age threshold, this behavior applies specifically to updates that remediate known vulnerabilities [3][2]. 2. Limitations: The bypass mechanism does not always automatically extend to more complex scenarios, such as when an update that fixes a vulnerability is itself pending due to a newer, non-vulnerability-fixing version of the same package, or when using experimental features like osvVulnerabilityAlerts [3][4]. 3. Configuration: Because of these nuances, it is recommended to set internalChecksFilter to strict to ensure consistent application of the age gate, while relying on Renovate's built-in security detection to handle the bypasses for genuine vulnerability fixes [1][2].

Citations:


🌐 Web query:

Renovate packageRules isVulnerabilityAlert matcher key

💡 Result:

In Renovate, there is no configuration key named isVulnerabilityAlert within packageRules [1][2]. To apply rules specifically to vulnerability alert PRs, you should use the alertPackageRules configuration option instead [3]. The alertPackageRules option is designed to handle dependency updates that originate from vulnerability alerts (such as those from GitHub Dependabot alerts or OSV) [3]. It accepts the same configuration structure as packageRules, allowing you to use standard matchers like matchPackageNames, matchDatasources, matchFileNames, and matchCurrentVersion to conditionally apply settings (e.g., specific PR body notes, assignees, or labels) to security-related pull requests [3]. If you were looking for a way to detect if a pull request is a vulnerability alert within a general packageRules block, Renovate does not provide a direct matcher for this status. Use alertPackageRules to define behavior specifically for these security updates [3].

Citations:


Fix Renovate config: vulnerability alert security PRs bypass minimumReleaseAge, and packageRules[].isVulnerabilityAlert isn’t a valid matcher.

  • .github/renovate.json5 lines 64-69: minimumReleaseAge: "3 days" won’t enforce a 72h cooldown for vulnerability-alert/security updates (Renovate bypasses it).
  • .github/renovate.json5 lines 243-258: isVulnerabilityAlert isn’t supported in packageRules; if ignored, this rule will automerge all patch/minor/digest updates. Use alertPackageRules (or proper match... keys) to target vulnerability alerts specifically.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/renovate.json5 around lines 58 - 69, The Renovate config is
incorrectly targeting vulnerability alerts: keep the top-level
"vulnerabilityAlerts" block but remove reliance on "minimumReleaseAge" for
security PR throttling and stop using the unsupported "isVulnerabilityAlert"
inside "packageRules"; instead move any rules that should apply to
vulnerability/security alerts into an "alertPackageRules" array and explicitly
match the update types you want (e.g., "matchUpdateTypes":
["patch","minor","digest"]) or other supported matchers, and ensure
automerge/approval settings that would fast-track alerts are not applied in
normal "packageRules" but are handled via "alertPackageRules" so security alerts
are not auto-merged before the intended delay.

@9larsons 9larsons merged commit f1ed307 into main May 25, 2026
44 checks passed
@9larsons 9larsons deleted the chore/renovate-security-pr-handling branch May 25, 2026 14:42
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.

1 participant