fix(ci): scope package-age gate to npm, add target_url and merge_group - #740
Open
Corina (corinagum) wants to merge 2 commits into
Open
fix(ci): scope package-age gate to npm, add target_url and merge_group#740Corina (corinagum) wants to merge 2 commits into
Corina (corinagum) wants to merge 2 commits into
Conversation
The gate looked every Dependabot update up on the npm registry. For `github_actions` PRs no package-lock.json changes, so it fell back to parsing the PR body, produced names like `actions/checkout@7.0.1`, and got a 404 from registry.npmjs.org. That tripped the "unverifiable age" fail-safe and reported a permanent red `package-age/7-day` status that could never clear (e.g. #734). Only npm packages resolve through the CFS feed that enforces the quarantine; actions are fetched from github.com and are never quarantined. Detect the ecosystem from the Dependabot branch name (`dependabot/<ecosystem>/<slug>`, which is not customizable unlike labels) and report a passing "not applicable" status for non-npm ecosystems. An unrecognized branch shape still runs the full check. Also improves the status UX and makes the check safe to require: - Set `target_url` to the workflow run, giving reviewers the untruncated package list in the job log plus a native "Re-run all jobs" button to refresh the gate on demand. - Re-check twice daily instead of once, halving how long a cleared package stays yellow. - Add a `merge_group:` trigger so the status also reports on the merge queue's temporary ref. Without it, adding `package-age/7-day` to the ruleset's required status checks would stall the queue forever. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR hardens the “Dependabot Package Age Gate” workflow so the package-age/7-day commit status is meaningful and actionable across more Dependabot scenarios (especially non-npm ecosystems and merge queue refs), while improving status debuggability.
Changes:
- Scope the age gate to Dependabot’s npm ecosystem and return a passing “not applicable” status for non-npm ecosystems.
- Add a
merge_grouptrigger and a merge-queue-safe success path to ensure the required status is reported on merge queue temporary refs. - Add
target_urlon all statuses (linking to the workflow run) and increase scheduled refresh frequency to twice daily.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| .github/workflows/dependabot-package-age-gate.yml | Adds merge_group trigger, increases schedule frequency, and clarifies that only npm Dependabot PRs are gated. |
| .github/scripts/dependabot-pr-age-check.mjs | Implements ecosystem scoping, merge-queue status publishing, and target_url support for commit statuses. |
Suppressed comments (2)
.github/scripts/dependabot-pr-age-check.mjs:223
- The inline comment refers to the GitHub Actions ecosystem as
github_actions, but Dependabot usesgithub-actions(and this repo’sdependabot.ymluses that spelling).
// Only npm packages flow through the CFS feed that enforces the quarantine.
// `github_actions` (and any other non-npm ecosystem) resolves from github.com,
// so its versions can never be quarantined -- and looking them up on the npm
// registry would 404 and wrongly trip the fail-safe.
.github/scripts/dependabot-pr-age-check.mjs:210
getDependabotEcosystemcurrently relies only on the branch name shape. If branch naming is customized or doesn’t match the default pattern, this returns null and the script falls back to parsing the PR body for dependency names—reintroducing the originalgithub-actions404/fail-safe problem on non-npm PRs. Consider also extracting the ecosystem from the Dependabot PR body (e.g. thepackage-manager=query param in the compatibility badge) when the branch pattern doesn’t match.
function getDependabotEcosystem(pullRequest) {
const match = DEPENDABOT_BRANCH_PATTERN.exec(pullRequest.head?.ref ?? '');
return match?.groups?.ecosystem ?? null;
}
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Review feedback caught a fail-open hole in the ecosystem shortcut. The
skip was expressed as "not in QUARANTINED_ECOSYSTEMS", so *any* slug
other than `npm_and_yarn` reported success -- including an npm PR whose
branch slug ever differs (e.g. `dependabot/npm/...`). A quarantined
package would then sail through with a green check, inverting the
script's fail-safe design.
Two changes:
- Invert the set to NON_NPM_ECOSYSTEMS, an allowlist of ecosystems known
not to resolve through the CFS feed. Anything unrecognized now runs the
full check instead of being skipped.
- Evaluate the lockfile diff *before* the ecosystem shortcut. A changed
package-lock.json is ground truth that npm versions moved, so they are
gated regardless of what the branch name claims.
Verified against live GitHub/npm data. With slug `dependabot/npm/...` and
a 1-day-old hono@4.13.3, the previous code returned `success` ("not
applicable"); it now returns `pending` with the eligible date. #734
(github_actions) still reports not-applicable and #737 still passes via
the lockfile path.
Also documents that Dependabot's branch slugs differ from the
`package-ecosystem` keys in dependabot.yml (`github-actions` ->
`github_actions`, `npm` -> `npm_and_yarn`), which prompted the review
comments.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
package-age/7-daywas permanently red on #734 with:It is a
github_actionsupdate, so nopackage-lock.jsonchanged → the script fell back to parsing the PR body → produced names likeactions/checkout@7.0.1→ looked them up onregistry.npmjs.org/actions%2Fcheckout→ 404 → tripped the "unverifiable age" fail-safe. A status that could never clear, no matter how many days passed.CFS quarantine only applies to npm packages resolved through the Azure Artifacts feed. GitHub Actions are fetched from github.com by the runner and are never quarantined, so a fresh action release can't break
npm ci.What changed
Ecosystem scoping. Read the ecosystem from the Dependabot branch slug (
dependabot/<slug>/<update>) — chosen over labels because labels are customized in this repo (javascript, notnpm_and_yarn) while branch names are not. Note the slug differs from thedependabot.ymlkey:package-ecosystem: "github-actions"branches asgithub_actions, andnpmasnpm_and_yarn.The skip is an allowlist of ecosystems known not to reach the CFS feed, and the lockfile diff is evaluated before the shortcut. So a changed
package-lock.jsonis always gated regardless of what the branch claims, and an unrecognized slug runs the full check rather than being skipped. This matters because the naive form ("skip anything that is notnpm_and_yarn") fails open — see the review thread; caught there and fixed in ba56199.Status UX. Every status now carries a
target_urlpointing at the workflow run. That's a real GitHub-hosted page, so it supplies both missing pieces at once: the job log has the untruncated package list (statuses clip at 140 chars), and the run page has a native "Re-run all jobs" button as an on-demand refresh. No page to manufacture, no Check Runs machinery needed.Freshness. Cron goes from daily to twice daily (
17 8,20 * * *), halving how long a cleared package sits yellow.Merge-queue safety. Added a
merge_group:trigger.mainhas a merge queue, and a required status check must also report on the queue's temporary ref — without this, addingpackage-age/7-dayto the ruleset would stall the queue forever waiting on a status that never arrives. Queued PRs already passed the gate at PR time and packages only get older, so the merge-group path reports success.Verification
Dry-run harness against live GitHub + npm data, intercepting the status POST:
github_actionsfailuresuccess— "Ecosystem "github_actions" is not served by the CFS npm feed"npm_and_yarn, aged depssuccessvia lockfile pathhono@4.13.3(1.3d old)pending— "hono@4.13.3 is 1d old (<7d CFS quarantine). Eligible 2026-08-25 UTC."merge_groupeventsuccesson merge refnpm(unrecognized) +hono@4.13.3(1.3d)success— skipped (fail-open)pending— blockedsuccess— skippedpending— blockedRows 3-6 are the red-green checks. Row 3 confirms the npm gate still blocks young packages and reports the eligible date. Rows 5-6 are the fail-open regression from review — their Before column is the first commit on this branch (b0a4fc5), run directly against the same inputs to confirm the old logic really did return
success.target_urlis present on every status.Workflow YAML re-parsed to confirm
merge_groupregisters as a trigger key (merge_group: null, same shape as the existingworkflow_dispatch:).Follow-up (needs repo admin, not in this PR)
package-age/7-dayis not currently merge-blocking — themainruleset'srequired_status_checkslists onlyBuild & Test & Lint (24.x). Once this merges, addpackage-age/7-dayto that list to actually block quarantined packages. Themerge_group:trigger here is the prerequisite that makes it safe to do.