Skip to content

ci(guard): accept Dependabot security updates into main (#571) - #572

Merged
ss-o merged 1 commit into
mainfrom
hotfix-571
Sep 27, 2026
Merged

ss-o merged 1 commit into
mainfrom
hotfix-571

Conversation

@ss-o

@ss-o ss-o commented Sep 27, 2026

Copy link
Copy Markdown
Member

Description

Dependabot security updates always target the default branch (main) and ignore target-branch: next, so the Main Branch Source Guard rejected every one of them. This hotfix implements the exception that z-shell/.github#698 specifies in runbooks/branch-protection.md.

  • scripts/main-branch-guard.zsh now holds the decision. It checks the same-repository head first, then allows next, hotfix-*, or a dependabot/* branch whose pull-request author (github.event.pull_request.user.login) is dependabot[bot]. The error message names all three sources.
  • .github/workflows/main-branch-guard.yml checks out only that script, from the base branch (no ref: override under pull_request_target, persist-credentials: false, non-cone sparse checkout), sets up Zsh with z-shell/.github/actions/setup-zsh, and runs the script. Permissions change from {} to contents: read for the checkout.
  • tests/main-branch-guard.zsh covers 12 cases. The allowed cases are next, hotfix-*, and two Dependabot branches by dependabot[bot]. The rejected cases are a dependabot/ branch by a person, by app/dependabot, or with an empty author; the bot on a non-Dependabot branch; fork heads; an ordinary topic branch; and an empty ref. The new Main Branch Guard job in zsh-n.yml runs it.
  • AGENTS.md adds the Dependabot source to the branch model.

The runbook states the known limitations, which this guard does not close: a routine Dependabot update retargeted to main passes, and so do commits another user pushes onto an open dependabot/* branch, because the pull-request author does not change.

First live run happens after merge

pull_request_target runs the workflow from main, so this pull request is still judged by the current inline guard (it allows hotfix-*). The new checkout, Zsh setup, and script run for the first time on the next pull request into main after this merges; that run needs to be watched. If it fails, the required check blocks every pull request into main, and the repair needs a reviewed ruleset bypass for that one pull request.

The setup-zsh pin uses the # main comment like the other organization callers. The interim pinact exception covers reusable workflows only, so it would need attention if zi enables pinact.

After merge, main must be merged forward into next as the branch model requires.

Related issues

Closes #571
Refs z-shell/.github#487

Type of change

  • fix - bug fix (non-breaking)
  • feat - new feature (non-breaking)
  • feat! / fix! - breaking change
  • perf - performance improvement
  • refactor - code change with no functional impact
  • docs - documentation only
  • test - test addition or correction
  • build - build system or dependency change
  • ci - CI/workflow change
  • style - formatting with no behavior change
  • chore - maintenance / dependency bump
  • revert - revert of an earlier change

Checklist

  • Ordinary work targets next; only same-repository hotfixes target main
  • A next to main promotion uses a merge commit and records both parent SHAs (not a promotion)
  • Commit messages follow Conventional Commits format
  • Any Co-authored-by trailer credits a real human, never a bot, AI agent, or automation
  • I have read the contribution guidelines
  • Existing tests pass (zsh -n zi.zsh / Trunk checks)
  • Documentation updated if needed

Verification

On f9db222:

  • zsh -f tests/main-branch-guard.zsh: passed.
  • Three deliberate script mutations (dropping the author check, widening the branch pattern, dropping the repository check) each fail the test.
  • zsh -n and zcompile on both new files: passed.
  • actionlint 1.7.8 on both workflows: passed.
  • trunk check on the changed files: no issues.
  • The non-cone sparse checkout reproduced locally yields only scripts/main-branch-guard.zsh, and the guard runs from that checkout.

Dependabot security updates always target the default branch, so the
main source guard rejected every one of them. Move the decision into
scripts/main-branch-guard.zsh and also allow a same-repository
dependabot/* branch whose pull-request author is dependabot[bot].

The workflow checks out only that script from the base branch, so it
never runs pull-request code, and needs contents: read for that. The
new Main Branch Guard job runs tests/main-branch-guard.zsh.

@ss-o ss-o left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Self-review of head f9db222.

No defects found. What I checked:

  • Trust boundary: under pull_request_target, actions/checkout with no ref: checks out the base branch, and the sparse pattern limits it to scripts/main-branch-guard.zsh, so no pull-request code runs. persist-credentials: false keeps the token out of .git/config. Untrusted values (head_ref, head repository, author login) reach the script only through env:, never interpolated into run:.
  • Decision logic: the repository check runs first and also fails when REPOSITORY is empty; dependabot/* in a [[ == ]] pattern matches nested paths such as dependabot/github_actions/actions/checkout-5 (covered by a test); the author must equal dependabot[bot] exactly, so app/dependabot, a person, and an empty login all fail (covered).
  • Log output: ref names cannot contain newlines, so a branch name cannot start a new workflow-command line in the ::error:: output.
  • Test coverage: 12 cases, and three mutations (drop the author check, widen the branch pattern, drop the repository check) each fail the test.

Residual risks, not defects:

  1. The new guard path runs for the first time on the next pull request into main after this merges, because pull_request_target uses the workflow from main. That run needs watching; a failure there blocks every pull request into main.
  2. The guard now depends on apt-get update and apt-get install zsh through setup-zsh, which the inline version did not. An apt outage would fail this required check until a rerun succeeds.
  3. After merge, main must be merged forward into next.

@ss-o
ss-o merged commit 4f2c0a7 into main Sep 27, 2026
147 checks passed
@ss-o
ss-o deleted the hotfix-571 branch September 27, 2026 18:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ci(guard): accept Dependabot security updates into main

1 participant