Nimblesite / Nimblesite/Shipwright
[SWR-SEC-DEPENDABOT-STAGING] Shipped template's clobber-merge sweep cannot work — GITHUB_TOKEN can never push .github/workflows/*
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 0
- Forks
- 0
- Avg merge
- 1m
- Merged PRs (30d)
- 10
Description
templates/gh-actions/dependabot-automerge.yml and the [SWR-SEC-DEPENDABOT-STAGING] spec section both still describe the clobber-merge generation. That design cannot work, and the spec's own reference implementation has already moved off it.
The defect
The template sweeps with:
git merge -X theirs --no-edit "origin/${PR_HEAD}"
git push origin "HEAD:dependabot-upgrades"
and subscribes to both dependabot-upgrades and main.
Security updates are the only Dependabot PRs that reach main — GitHub ignores target-branch for them, which the spec correctly documents as fixed behaviour. But a security bump is branched off current main. Merging it into a staging branch that has drifted behind main drags main's intervening commits along, including .github/workflows/* edits.
GITHUB_TOKEN can never push workflow files. There is no permissions: key that grants the workflows scope — it is a GitHub App scope the Actions token does not have. So the push is rejected:
! [remote rejected] HEAD -> dependabot-upgrades (refusing to allow a GitHub App
to create or update workflow `.github/workflows/ci.yml` without `workflows` permission)
The rejection is permanent, and the template retries it five times before failing. The staging branch drifts behind main by construction — that is what a staging branch does — so this transitions from working to permanently broken the first time a workflow file changes on main, and never recovers.
Observed impact in a repo running the shipped template
Nimblesite/NimblesiteAgenticPlatform, template generation agent-pmo:372ce7f. Identical failure on every main-based bump from 2026-07-22 to 2026-09-04 — six weeks, always the same rejection, never once surfaced, because a merge bot going red is silent.
The damage compounds well past PR noise:
| Security PRs never retired | 10 |
| npm PR quota | 5/5 — saturated at open-pull-requests-limit |
| uv PR quota | 5/5 — saturated |
| Open Dependabot alerts | 92 (56 HIGH) |
| Routine bumps stranded on staging | 54 commits |
| Consolidation PRs ever opened | 0 |
Because nothing is ever retired, both ecosystems pin at their PR cap and Dependabot stops opening new security PRs altogether. A direct dependency (GitPython) accumulated 17 HIGH advisories without ever getting a PR.
Two further defects in the same template
-
No drain. The template flows bumps into staging and has nothing that flows them out. Nothing opens the
dependabot-upgrades → mainconsolidation PR the spec relies on, so it depends entirely on a maintainer noticing. In the repo above, zero were opened in three months while 54 commits accumulated. -
The
mainbase filter hangs a dead check on every human PR. The job can only be narrowed to Dependabot with a job-levelif:, and anif:-skipped job still materialises as a check run with conclusionskipped. Subscribing to PRs againstmaintherefore pins a permanently-skippedcheck onto every human PR forever — one that by construction can never run.
The fix already exists
Nimblesite/deslop runs agent-pmo:0b21609, which resolves all three:
- Path-restricted sweep. Copy only the files the PR itself changed (diff against its merge-base with the PR base) onto the staging tip. Immune to staging drift, and clobber semantics survive with no merge machinery left to conflict. A bump that edits
.github/workflows/*itself is squash-merged server-side, since the merge API is not a push. - Base filter
dependabot-upgradesonly, so the workflow is never instantiated for a human PR. - A drain step that opens the consolidation PR whenever staging is ahead and none is open, on a weekly
scheduleso it runs from the default branch's copy of the file.
Nimblesite/Basilisk — named in the spec as the reference implementation — is on 0b21609 too, but only partially: its dependabot.yml header still describes the clobber-merge behaviour, and its ci.yml still carries the Dependabot actor skip.
Suggested changes
- Replace
templates/gh-actions/dependabot-automerge.ymlwith the0b21609generation. - Rewrite the
[SWR-SEC-DEPENDABOT-STAGING]bullet "The sweep clobber-merges, latest wins" — it currently prescribes the broken mechanism. - Add the drain to the spec as a load-bearing part; it is currently absent, and "a consolidation PR that the maintainer opens periodically" is the part that does not happen on its own.
- Reconsider the "CI runs once, on the consolidation PR" bullet. With the base filter narrowed to staging, routine bumps never trigger a
mainworkflow at all, so thegithub.actor == 'dependabot[bot]'skip saves nothing on them — it applies only to security bumps, making the vulnerability fix the single PR class that reachesmainwith no build, no test and no dependency review. deslop has removed those skips. - Finish Basilisk's migration so the reference implementation matches the template.
Fix as applied to NAP: Nimblesite/NimblesiteAgenticPlatform#324
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with templates/gh-actions/dependabot-automerge.yml and the [SWR-SEC-DEPENDABOT-STAGING] spec section, then compare them with the 0b21609 generation in Nimblesite/deslop and Basilisk. Update the template, spec, and Basilisk reference so the path-restricted sweep, staging-only filter, drain, and CI behavior match the described fix.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- git, github-actions
- Domain
- ci-cd, devops, documentation
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100