From 728cac9612884bde7a4bd0f1d842b658f29528b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niko=20H=C3=A4m=C3=A4l=C3=A4inen?= Date: Sun, 9 Aug 2026 16:39:00 +0300 Subject: [PATCH] Add 14 day cooldown before Renovate proposes updates Registries serve newly published versions to dependency resolution immediately. The 2026 attack pattern is consistent: a publish token is stolen, a malicious version is published under a genuine package name, the payload runs at install time and harvests credentials from the installing machine, and the registry pulls the version within hours. An automated consumer fetches it before detection happens, so the delay has to be implemented on the consumer side. The exposure here is CI's own secrets - GITHUB_TOKEN, repository secrets, and release.yaml's packages: write - regardless of the fact that the published features are pure shell with no third party implementation. Cost of the delay is close to zero here: no automerge, no deadlines, no SLA, and releases are triggered manually. Security fixes are unaffected - vulnerabilityAlerts defaults to minimumReleaseAge: null and prCreation: "immediate", so they bypass both this and schedule:monthly. Drop the per-package jdx/mise rule: at 1 day it would have been a hole in the global value rather than a delay, and its stated purpose (avoid errors installing a very fresh version) is served better by 14 days. Before this, only @devcontainers/cli was gated at all. prettier and shellcheck resolve through the mise registry to github-releases, not npm, so security:minimumReleaseAgeNpm never covered them. --- .github/renovate.json5 | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 3cfe67f..f7b98f2 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -5,20 +5,37 @@ ":pinAllExceptPeerDependencies", "customManagers:githubActionsVersions", "schedule:monthly", - "security:minimumReleaseAgeNpm", ], + // Also pulled in nested via `config:best-practices`. It sets 3 days in a + // packageRule, which would override the top-level minimumReleaseAge. + ignorePresets: ["security:minimumReleaseAgeNpm"], + lockFileMaintenance: { enabled: true, }, + minimumReleaseAge: "14 days", semanticCommits: "disabled", separateMinorPatch: true, packageRules: [ { - description: "Mise package settings", - matchPackageNames: ["jdx/mise"], - minimumReleaseAge: "1 day", // 1 day delay to avoid errors installing very fresh version + description: "Skip Minimum Release Age for update types that carry no usable release timestamp", + matchUpdateTypes: [ + "bump", + "lockFileMaintenance", + "lockfileUpdate", + "pin", + "replacement", + "rollback", + ], + minimumReleaseAge: null, + }, + { + // Without this, a pinned runner version would be held back forever, silently. + description: "Exempt github-runners, which provides no release timestamps to age against", + matchDatasources: ["github-runners"], + minimumReleaseAge: null, }, ], }