Repository navigation
fix(ci): the dependency audit fails loudly when it cannot open its pull request - #1230
Merged
antoinetoussaint-byte merged 1 commit intoOct 23, 2026
Merged
Conversation
…ll request The job remediated correctly and force-pushed its branch, then died on `gh pr create` with "GitHub Actions is not permitted to create or approve pull requests". Because that call aborted the step, the `gh workflow run` line after it never ran, so the pushed head got no CI either, and no pull request existed to make the remediation visible. Six consecutive daily runs failed that way while three critical advisories sat remediated on the branch; the pull request had to be opened by hand (#1228). Adopt the DEPS_COMBINE_TOKEN that combine-deps.yml already documents for this exact constraint, falling back to GITHUB_TOKEN so the remediation half keeps working without it. A create that cannot succeed now records its status instead of aborting, prints what a maintainer must do, and lets the CI dispatch run before the step exits non-zero. The failure is deliberate, and the obvious alternative is wrong: by then the working tree holds the remediated lockfiles, so a passing step would let the residual audit gate report a clean audit and take the whole run green with an advisory on a branch nobody is looking at. The release-gate contract test pins the dispatch to run after a new or updated pull request and the dispatch's status to propagate; both still hold. It gains the token dimension it never had — the one this failure lived in — asserting that a refused create still pushes, still dispatches, still fails, and names DEPS_COMBINE_TOKEN as the remedy. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
antoinetoussaint-byte
force-pushed
the
fix/dep-audit-cannot-open-its-pull-request
branch
from
October 23, 2026 15:48
4c46172 to
5cc34ac
Compare
antoinetoussaint-byte
deleted the
fix/dep-audit-cannot-open-its-pull-request
branch
October 25, 2026 17:07
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.
Dependency audit auto-remediationhas failed every day since at least 18 October— six consecutive runs — and not at the audit. It remediates correctly, passes
module/tools/module-verify.mjs, force-pusheschore/dep-audit-remediation, and thendies on the next line:
Both the organisation and this repository have
can_approve_pull_request_reviews: false,so
GITHUB_TOKENcannot open the pull request.combine-deps.ymlalready documentsthis exact constraint and answers it with a
DEPS_COMBINE_TOKENorg secret — which isnot set, so that workflow has failed every week since at least 21 September for the
same reason.
dep-audit.ymlnever adopted the token at all.Why it was worse than a red badge
gh pr createsits before thegh workflow run ci.ymlline, so when it failed:Three critical advisories sat correctly remediated on that branch for six days —
unauthenticated RCE in the Next.js Image Optimization API and in
use cache, a DoS inApp Router Server Actions, three
dompurifybypasses and a@sentry/nextjsmiddlewarebypass — while
Enforce first-party vulnerability gateblocked every open pull requestin the repository. The remediation pull request had to be opened by hand (#1228).
What this changes
DEPS_COMBINE_TOKEN, falling back toGITHUB_TOKEN. An unset secret isfalsy, so the remediation half keeps working exactly as today without it.
the CI dispatch after it still runs and the pushed head always carries evidence.
That last point is the one worth reviewing closely, because the obvious choice is wrong.
By the time the create is attempted the working tree holds the remediated lockfiles,
so letting the step pass would let the residual audit gate report a clean audit and the
whole run go green — with an advisory sitting on a branch nobody is looking at. That is
precisely the silence this job exists to prevent. The residual audit gate itself is
untouched.
The contract test caught my first attempt
My first version moved the dispatch before the create and wrapped it in
|| true.scripts/ci/release-gates.test.mjsrefused it, and it was right to: that test executesthe real step body against stubs and pins both the dispatch-after-create ordering and
the propagation of the dispatch's own exit status. Reordering was the lazy fix.
The restructure here satisfies every assertion that existed — verified by running the
test with
HAVE_PR_TOKEN=trueagainst the unmodified test file, where it passesuntouched. What the test never had was a token dimension, which is exactly where
this failure lived: with
gh pr createstubbed to always succeed, no amount ofiteration over
existing × changed × dispatchStatuscould see it. So the test gainsthat dimension and asserts a refused create still pushes, still dispatches CI exactly
once, still fails the run, and names
DEPS_COMBINE_TOKENas the remedy. Nothing wasrelaxed to make room for it: 125 pass, 0 fail.
One honest trade: the dispatch stays unconditional, so with a PAT configured the push
raises its own workflow event and the dispatch fires, and that head may get two CI
runs. A head with two runs beats a head with none, and narrowing it would break the
pinned ordering contract for a cosmetic gain.
What this does not fix
The token still has to exist. Minting it is a credential decision for a maintainer: a
PAT or GitHub App token with
reposcope, added as an organisation secret, sharedwith
combine-deps.yml. Until then this job still fails when there is something toremediate — but now it fails having pushed the branch, triggered its CI, and printed the
remedy, instead of dying on a raw GraphQL error.
Turning on "Allow GitHub Actions to create and approve pull requests" would also work
and needs no secret, but it grants every workflow in scope the ability to approve
pull requests as well, which is a review-bypass path.
combine-deps.ymlalready chosethe token over that trade; this follows it rather than reopening it.
Verified
node --test scripts/ci/release-gates.test.mjs scripts/ci/ci-performance.test.mjs:125 pass, 0 fail, run with
env -u HAVE_PR_TOKENso no value leaked in from theshell that wrote it.
HAVE_PR_TOKEN=true, which is what shows the restructure preserves the old contractrather than bending it.
rather than from the diff.
module/tools/naming-gate.mjs messagepasses on the commit message and on this body.Not verified: the no-PAT path end to end on a real advisory — that needs a day when
audit fixproduces a diff. The paths that run today are the earlygit diff --quietexit (main is clean once #1228 lands) and the already-open-pull-request exit.
🤖 Generated with Claude Code