Repository navigation
Feature request: minimum release age (cooldown) for resolved pins #132
Copy link
Copy link
Open
Labels
Description
Summary
Add an option to exclude releases published less than N days ago when resolving action references into lockfile pins — the same "cooldown" concept as pinact's -min-age, Dependabot's cooldown, or the npm ecosystem's minimumReleaseAge settings, applied to actions.lock.
Motivation
- Avoiding freshly-published releases is one of the cheapest supply-chain defenses. Recent research found that most compromised packages are detected and removed within about a week of publication (see https://nesbitt.io/2026/03/04/package-managers-need-to-cool-down.html), so simply not adopting versions younger than a few days moves consumers out of the blast window.
- Automated update paths already have workarounds: tools like Renovate (
minimumReleaseAge) and Dependabot (cooldown) can gate their own update proposals. - But when a maintainer runs
gh actions-lockorgh actions-lock --relockmanually, the tool always resolves the current latest SHA. There is no substitute on this path — unless the tool itself offers an age gate, manual relocking can pull in a release published minutes ago.
Prior art
- Dependabot
cooldown(default-days,semver-*-days): version updates wait out a cooldown by default (3 days); security updates bypass it. Same vendor, same problem space. - npm ecosystem: npm CLI
min-release-age, pnpmminimumReleaseAge(on by default since pnpm 11), YarnnpmMinimalAgeGate, Buninstall.minimumReleaseAge. - pinact
-min-age/--verify-min-age: the direct predecessor for pinning GitHub Actions; filters candidate versions by tag commit date / release publish date, and can verify existing pins against the same floor. - action-locker
--min-age-days: a third-party lockfile tool with the same feature, including a fallback mode that walks back to the newest release that clears the age floor instead of hard-failing. - Renovate
minimumReleaseAge: feasible here because GitHub tag/release lookups expose release timestamps — the same data sourcesactions.lockresolution already touches.
Proposed semantics (strawman)
- A
--min-age <duration>flag and/or a lockfile/config field. - Applied wherever a version is selected: initial pinning,
--relock, and ref narrowing (e.g.@v4resolves to the newestv4.x.ytag that clears the age floor). - When no version satisfies the window: either fail-closed with a clear error, or fall back to the newest release that does (action-locker style) — open to maintainer preference.
--verify/--no-fixcould additionally flag pins younger than the window (the pinact--verify-min-ageequivalent), so CI can enforce the policy without restricting manual runs.
Notes
- Checked
gh actions-lock --help(v0.1.6): no age-related option exists. - I couldn't find an existing issue or discussion covering this (searched this repo's issues,
github/actions-lockfile,cli/cliRFC #13314, andgithub/roadmap).
Reacted by Jesse Houwing and kageyamountain
Activity
jessehouwing commentedon Sep 27, 2026
A problem here is that you can't know what the tag pointed to 3 days ago. So the cooldown will also not update to a less recent Sha unless you run it every cooldown days.
The real solution is to not pin to floating tags and depend on renovate or dependabot for your cooldown I'm afraid.
mkusaka commentedon Sep 27, 2026
Update: this is already implemented on main via #104 — cooldown is read from the repo's Dependabot
github-actionsconfig, falling back to a user config file. Not yet in a stable release; waiting on v0.1.7.Closing as implemented.
mkusaka commentedon Sep 27, 2026
I closed this assuming #104 already covered the request — that was premature on my part, sorry. Re-checking
main: the cooldown config is read, but I can't find an age gate on the path that adopts a resolved SHA during initial pinning or--relock. And when a cooldown is configured, the post-pin fresh-tag notification is skipped on the assumption that the resolver already filtered. So the core of this issue — not adopting too-fresh candidates during a manual lock — is still unresolved, hence reopening.@jessehouwing thanks for the input. I understand we can't know which SHA a floating tag pointed to N days ago. This proposal doesn't try to restore that history — the lockfile still pins a commit SHA; the cooldown would only govern which candidate SHA gets adopted at lock time, not leave the action floating at runtime. Whether a too-fresh candidate should be skipped or replaced with another version that clears the floor is something I'd like to discuss; in the latter case the workflow ref and the lockfile SHA would need to stay coherent.
Renovate/Dependabot cooldown works on their own update proposals, but a maintainer running
gh actions-lock/--relockgoes through no updater — so we'd like a gate with the same purpose on this path too. For the date source, dependabot/dependabot-core#15350 is a useful reference: for GitHub Actions it consults the Releasepublished_at, then the annotated tag's creation date, then the commit date, in that order. To be clear, I'm not claiming that the choice of date source alone reveals floating-tag retarget history.Enforce release cooldown before adopting new pins
Enforce release cooldown before adopting new pins
Enforce release cooldown before adopting new pins
Enforce release cooldown before adopting new pins
Enforce release cooldown before adopting new pins
Enforce release cooldown before adopting new pins
Warn on fresh tags when a cooldown is configured (#224)