Skip to content

fix(automerge): pass --admin, and stop swallowing a failed merge - #2551

Merged
0xkkonrad merged 1 commit into
mainfrom
fix/automerge-admin-flag
Jul 28, 2026
Merged

fix(automerge): pass --admin, and stop swallowing a failed merge#2551
0xkkonrad merged 1 commit into
mainfrom
fix/automerge-admin-flag

Conversation

@Hugo0

@Hugo0 Hugo0 commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

The content pipeline is currently broken — nothing is reaching production. The end-to-end test found the real defect, on the last hop.

What the test showed

Everything worked until the merge itself:

Hop Result Elapsed
push → mono 7d255265
mirror → peanut-content 63abb439 +20s
auto-PR → main #2546 +48s
guard + handoff ✅ content-only → merge-on-green +67s
supersede on collision #2546 auto-closed when #2547 opened +3.5m
merge
Merging #2547 — diff is exactly src/content, ci-success green (2/2)
merge failed for #2547 (already merged, or bypass unavailable)

Cause

Being an OrganizationAdmin does not make gh pr merge bypass "Protect Prod". gh enforces the branch policy and requires an explicit --admin:

X Pull request #2544 is not mergeable: the base branch policy prohibits the merge.
  To use administrator privileges to immediately merge the pull request, add the `--admin` flag.

I hit that exact error merging #2544 by hand an hour earlier, added the flag, and never carried it back into the workflow.

--admin also waives the required status check — note what it is not waiving. This job has already established, itself, that the diff is exactly src/content and that every ci-success run on the commit is green. The gate is enforced in code above; --admin only drops the human review, which is the entire purpose of this workflow.

And the reason nobody noticed for 40 minutes

|| echo "::warning::merge failed" — the run went green while content sat unpublished. A merge we decided to make and then failed to make now fails the run loudly. That silent-warning pattern is precisely what this project exists to eliminate, and it was sitting in the middle of it.

Two more, found by running the step under bash -e

  • set +e with explicit checks. GitHub runs steps as bash -e; an unguarded non-zero kills the loop mid-flight with no output. (Same bug class as fix(watchdog): stop the script dying silently under bash -e #2544.)
  • Numeric validation of TOTAL/GREEN/PRS. gh prints its JSON error body to stdout, so on an API failure the loop was iterating over the words of an error message as if they were PR numbers.

QA

Executed the step under bash -e against real APIs:

bogus SHA (422):        ci-success not green (-1/0) — nothing to merge.   EXIT=0
real commit, no PR:     No open content-publish candidates.               EXIT=0

After merge

#2550 is open with Konrad's real content waiting. Once this lands, the next Tests completion on it should merge it automatically — which is the end-to-end proof finishing itself.

Summary by CodeRabbit

  • Bug Fixes
    • Improved reliability of automatic content updates after successful tests.
    • Prevented transient service or data errors from being overlooked during processing.
    • Added clearer failure reporting when an automatic merge cannot be completed.
    • Blocked merges when validation results are incomplete or invalid.

The end-to-end test found the real defect. merge-on-green did everything right
for #2547 — content-only diff, ci-success 2/2 green — then failed at the last
step:

    Merging #2547 — diff is exactly src/content, ci-success green (2/2)
    merge failed for #2547 (already merged, or bypass unavailable)

Being an OrganizationAdmin does not make `gh pr merge` bypass "Protect Prod".
gh enforces the branch policy and requires an explicit `--admin`. I hit this
exact error merging #2544 by hand an hour earlier, added the flag, and did not
carry it back into the workflow.

`--admin` also waives the required status check, so note what it is not waiving:
this job has already established for itself that the diff is exactly
`src/content` and that every ci-success run on the commit is green. The gate is
enforced in code above; --admin only drops the human review, which is the entire
purpose of this workflow.

A merge we decided to make and then failed to make now fails the run loudly
instead of logging a warning and going green. That warning is why the pipeline
looked healthy for 40 minutes while Konrad's content sat unpublished — the exact
silent failure this work exists to remove.

Two more from the same class, found by running the step under `bash -e`:
`set +e` with explicit checks, because -e kills the loop mid-flight with no
output; and numeric validation of TOTAL/GREEN/PRS, because gh prints its JSON
error body to stdout and the loop was iterating over the words of an error
message as if they were PR numbers.

Verified under `bash -e`: bogus SHA -> "not green (-1/0)", exit 0; real commit
with no candidate PR -> "No open content-publish candidates", exit 0.
@cursor

cursor Bot commented Jul 28, 2026

Copy link
Copy Markdown

Bugbot is not enabled for your account, so this pull request was not reviewed.

Enable Bugbot in the Cursor dashboard to get automatic reviews on future PRs.

@vercel

vercel Bot commented Jul 28, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
peanut-wallet Ready Ready Preview, Comment Jul 28, 2026 1:02pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The content publish automerge workflow now tolerates transient GitHub CLI failures, validates CI status counts, safely processes PR identifiers and diffs, captures merge errors, and fails the job when content-only merges remain incomplete.

Changes

Content automerge hardening

Layer / File(s) Summary
Harden CI status gating
.github/workflows/content-publish-automerge.yml
Shell failures no longer terminate iteration silently; CI totals default safely and are validated as numeric before merge decisions.
Report PR merge failures
.github/workflows/content-publish-automerge.yml
PR IDs and diffs are handled defensively, merges use --admin with captured output, and any failed merge causes a non-zero job exit.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main workflow fix: adding --admin to merges and surfacing failed merges instead of swallowing them.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/automerge-admin-flag

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

Code-analysis diff

Painscore total: 6309.47 → 6309.47 (0)
Findings: 0 net (+0 new, -0 resolved)

@github-actions

Copy link
Copy Markdown
Contributor

🧪 UI test report — ✅ all green

Suites

  • unit: 2234 ran, 0 failed, 0 skipped, 35.3s

📊 Coverage (unit)

metric %
statements 61.7%
branches 45.1%
functions 51.0%
lines 62.1%
⏱ 10 slowest test cases
time test
3.6s src/components/Card/share-asset/__tests__/shareAssetLayout.test.ts › never places two stickers in heavy overlap (broad seed sweep)
1.1s src/utils/__tests__/demo-api.test.ts › isDemoMode() is false when not running under Capacitor
0.4s src/components/Card/share-asset/__tests__/shareAssetLayout.test.ts › every sticker stays within canvas at any count
0.3s src/app/actions/__tests__/api-headers.test.ts › should include Content-Type in validateInviteCode
0.3s src/app/(mobile-ui)/withdraw/__tests__/withdraw-states.test.tsx › Bank withdrawal keeps the $1 minimum for sub-$1 amounts
0.3s src/app/actions/__tests__/api-headers-extended.test.ts › should not include apiKey in validateInviteCode body
0.2s src/components/Card/share-asset/__tests__/shareAssetLayout.test.ts › keeps stickers off the username pill (final pass respects the keep-out)
0.2s src/utils/__tests__/url.utils.test.ts › uses the public BASE_URL in Capacitor, not the localhost WebView origin
0.1s src/utils/__tests__/demo-balance.test.ts › auto-refills a wallet older than the TTL on cold start
0.1s src/utils/__tests__/demo-balance.test.ts › auto-refills a stored balance that has no timestamp (legacy install)
📍 Inline annotations are in the **Unit test report** check above. Coverage artifact: `coverage-unit`. Generated by `.github/workflows/tests.yml`.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/content-publish-automerge.yml:
- Around line 176-180: Update the gh pr merge invocation in the merge workflow
to include --match-head-commit "$SHA", ensuring the administrative merge only
proceeds when the pull request head matches the validated SHA. Preserve the
existing repository, merge, admin, and error-handling behavior.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: de4e60be-6a65-42cf-a240-3507d97cf18b

📥 Commits

Reviewing files that changed from the base of the PR and between 6910f75 and 458e964.

📒 Files selected for processing (1)
  • .github/workflows/content-publish-automerge.yml

Comment on lines +176 to +180
if ! MERGE_ERR=$(gh pr merge "$PR" --repo "$REPO" --merge --admin 2>&1); then
# A merge we decided to make and then failed to make is the exact
# silent failure this pipeline exists to prevent. Be loud.
echo "::error::MERGE FAILED for #$PR — content will NOT reach production. $MERGE_ERR"
FAILED=1

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the workflow around the cited lines.
file=".github/workflows/content-publish-automerge.yml"
wc -l "$file"
sed -n '140,210p' "$file"

Repository: peanutprotocol/peanut-ui

Length of output: 3059


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check whether the workflow already tracks a validated SHA and whether gh supports the guard.
rg -n --no-heading --context 2 'match-head-commit|gh pr merge|SHA|head_sha|merge' .github/workflows/content-publish-automerge.yml

Repository: peanutprotocol/peanut-ui

Length of output: 415


🌐 Web query:

gh pr merge --match-head-commit documentation merge race head commit admin GitHub CLI

💡 Result:

The --match-head-commit flag in the GitHub CLI (gh pr merge) is a safety mechanism that allows you to specify the expected commit SHA of the pull request's head branch [1][2]. By providing this flag, the merge operation will only proceed if the head of the pull request matches the SHA you provide [1][3]. This functionality is analogous to --with-lease in Git, preventing you from accidentally merging code that has changed since you last reviewed or tested it [3]. While this flag helps ensure that the state of the branch is what you expect, it does not inherently resolve all race conditions related to the base branch. In situations where the base branch is modified concurrently by other processes, the GitHub CLI has implemented separate retry logic to handle transient errors—specifically, the CLI will automatically retry the merge operation up to 3 times if it encounters a "Base branch was modified" error [4]. Regarding the --admin flag mentioned in your request: it is used to bypass merge requirements (such as passing status checks or merge queues) and force the merge, regardless of whether the branch meets the repository's configuration settings [1][5]. It does not interact directly with the --match-head-commit check, which operates as an independent precondition for the API request [6][2]. In summary: - --match-head-commit: Ensures the PR head hasn't moved unexpectedly [3]. - --admin: Bypasses standard repository merge requirements [1]. - Race conditions: Handled by automated retry logic in the CLI for specific "Base branch was modified" errors [4].

Citations:


Pin the merge to the validated head SHA.

gh pr merge --admin can still merge the PR’s current head if it moves after CI passes. Add --match-head-commit "$SHA" so the merge only proceeds when the head still matches the commit that was tested.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/content-publish-automerge.yml around lines 176 - 180,
Update the gh pr merge invocation in the merge workflow to include
--match-head-commit "$SHA", ensuring the administrative merge only proceeds when
the pull request head matches the validated SHA. Preserve the existing
repository, merge, admin, and error-handling behavior.

@0xkkonrad 0xkkonrad left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approving per Konrad to unblock the content publish pipeline. The gate that matters is still enforced in-code above the merge — diff must be exactly src/content and every ci-success run on the commit must be green — and --admin only waives the human review, which is this workflow's whole purpose. Failure handling is fail-closed throughout: GREEN=-1 on an API error makes the equality check impossible to pass, non-numeric PR ids are skipped, and an unreadable diff becomes UNKNOWN which never equals src/content.

@0xkkonrad
0xkkonrad merged commit 2b599ee into main Jul 28, 2026
24 of 26 checks passed
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.

2 participants