GitHub Actions: "GH013: Repository rule violations found" when a workflow pushes
A step pushed a commit or a tag, often a version bump, a changelog, generated data or a formatter's changes, and a rule on that branch refused it. GH013 comes from a ruleset and GH006 from classic branch protection. The token could write; the rule applies to everyone who is not on its bypass list, and GITHUB_TOKEN cannot be added to that list. So the push needs another actor, another route into the branch, or another branch.
What it looks like
remote: error: GH013: Repository rule violations found for refs/heads/main. remote: Review all repository rules at https://github.com/OWNER/REPO/rules?ref=refs%2Fheads%2Fmain remote: - Changes must be made through a pull request. remote: - 7 of 7 required status checks are expected. ! [remote rejected] HEAD -> main (push declined due to repository rule violations)
That is vow-lang's scheduled release (#1915). With branch protection the first line is remote: error: GH006: Protected branch update failed for refs/heads/main. The lines after it name the rules that refused the push:
- "Changes must be made through a pull request."
- "Required status check "…" is expected." or "N of N required status checks are expected.": the checks must already have passed on that exact commit, and a commit made in the job has not been checked anywhere, so the push is refused even when no pull request is required (hexgate #297).
- "Changes must be made through the merge queue" (talos-hq/clud #2518).
- "Commits must have verified signatures": a commit made with
git commitin the job is not signed (fullsend #9062).
The commit itself was made, so the step before the push looks fine. In Scottcjn/rustchain-bounties a weekly snapshot was computed and thrown away for five weeks (#17026).
Why GITHUB_TOKEN cannot bypass
The documentation lists who can be on a ruleset's bypass list: repository admins and owners, the maintain or write role, teams, GitHub Apps and Dependabot. GITHUB_TOKEN belongs to the built-in GitHub Actions integration, which is not an installation in your account. truvity/github-structure tried to add it and got 422 Actor GitHub Actions integration must be part of the ruleset source or owner organization (#80). Turning the rule off is what hexgate did to get one release out, and it left main without its checks.
1. A GitHub App on the bypass list
Create a GitHub App with Contents read and write, install it on the repository, add it to the ruleset's bypass list, and push with its token. bidabil/1min-Getway made such an App the only actor that can bypass main for its semantic-release job (#139); opencode's stats job now pushes with the App token its publish job already used (#55270).
- uses: actions/create-github-app-token@v3
id: app
with:
client-id: ${{ vars.RELEASE_APP_CLIENT_ID }}
private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
- uses: actions/checkout@v7
with:
token: ${{ steps.app.outputs.token }}
- run: |
git commit -am "chore: release"
git push
- A push with the App's token starts workflows, which a push with
GITHUB_TOKENdoes not. opencode added[skip ci]to its stats commit for that reason; 1min-Getway wanted it, so that its tag starts the image build. - Anything that can use the App's key can now push past the rule. Keep the key in an environment, or in the one job that needs it.
2. A pull request
Push to a new branch and open a pull request, so the rule stays as it is. meal-planner tries the push first and falls back to a branch and gh pr create when the answer is GH013 or GH006 (#151).
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v7
- run: ./update-stats.sh
- env:
GH_TOKEN: ${{ github.token }}
run: |
branch="bot/stats-${{ github.run_id }}"
git switch -c "$branch"
git commit -am "Update stats"
git push origin "$branch"
gh pr create --base main --head "$branch" --title "Update stats" --body "From run ${{ github.run_id }}"
GITHUB_TOKENcan open the pull request only when "Allow GitHub Actions to create and approve pull requests" is on (Settings > Actions > General). The documentation: in a new repository in a personal account it is off. In rustchain-bounties it was off, so that job uses another token.- The documentation: "When a pull request is created or updated by a workflow using
GITHUB_TOKEN,pull_requestevents with theopened,synchronize, orreopenedactivity types create workflow runs that require approval." Required checks wait until someone with write access approves those runs on the pull request. [skip ci]in the commit message also stops the pull request's workflows, so its required checks stay "expected" (rustchain-bounties dropped it).- If the rule requires the merge queue, the pull request has to go through the queue as well (talos-hq/clud).
3. Verified signatures: let GitHub make the commit
A commit made with git in the job is unsigned whatever the token, unless the job signs it with a key of its own. The documentation on signature verification for bots: it "will only work if the request is verified and authenticated as the GitHub App or bot and contains no custom author information, custom committer information, and no custom signature information". So create the commit through the API with a GitHub App's token, for example with GraphQL createCommitOnBranch, which fullsend switched to for its install path (#9062 links that change). For the branch rules above, the App still needs to be on the bypass list or go through a pull request.
4. Data that does not belong on main
Charts, snapshots and caches can live on a branch that no rule covers. homelab-monitor commits its star chart to an orphan star-history branch and its README points at the raw file there (#351); scheduled-archive-runner moved its snapshots to a slot-snapshots branch (#20). Check that the ruleset's branch pattern does not match the new branch.
Publish after the push, not before
hexgate's release published to PyPI and then pushed its version bump and tag. The push was refused, so 0.3.2 was on PyPI with no tag, no version bump on main and no GitHub release (#297). Put the push, or the pull request, before the steps that cannot be undone.
Telling it apart
- "remote: Permission to … denied to github-actions[bot]" and a 403: the token could not write at all ("Permission … denied to github-actions[bot]").
- "refusing to allow a GitHub App to create or update workflow": the push changes a file under
.github/workflows/("refusing to allow a GitHub App to create or update workflow"). - GH013 with "Push cannot contain secrets": push protection found a secret in the commit. That is not a branch rule; take the secret out of the commit.
See failed jobs from IntelliJ IDEA
Pipeline Inbox for GitHub Actions Workflows, a plugin by Lesstep for JetBrains IDEs 2024.1 or later, lists the runs of all your repositories in an IDE tool window, with their jobs and steps, and your current branch's runs are in the status bar. Reading is free; re-running failed jobs, cancelling, running workflows and reviewing deployments are Pro (US$1.50 a month, with a 30-day trial).
GitHub and GitHub Actions are trademarks of GitHub, Inc.; IntelliJ IDEA is a trademark of JetBrains s.r.o. This page is not affiliated with, sponsored or endorsed by GitHub, Inc. or JetBrains.
More: "Permission … denied to github-actions[bot]" · "refusing to allow a GitHub App" · "Resource not accessible by integration" · GitHub Actions plugins for IntelliJ IDEA compared · 日本語