Skip to content

feat(auto-rebase): trigger Claude agentic rebase on merge conflict#280

Closed
don-petry wants to merge 7 commits into
mainfrom
feat/auto-rebase-claude-agentic
Closed

feat(auto-rebase): trigger Claude agentic rebase on merge conflict#280
don-petry wants to merge 7 commits into
mainfrom
feat/auto-rebase-claude-agentic

Conversation

@don-petry

@don-petry don-petry commented May 13, 2026

Copy link
Copy Markdown
Contributor

Summary

  • auto-rebase-reusable.yml: when the merge strategy fails with a conflict, the existing sentinel comment (<!-- auto-rebase-conflict -->) now tells the author that Claude will attempt an automatic rebase. Manual fallback instructions are updated from git merge to git rebase --continue / --force-with-lease.
  • claude-code-reusable.yml: new claude-rebase job triggered by issue_comment events where github-actions[bot] posts a comment containing <!-- auto-rebase-conflict --> on a PR. Claude checks out the branch, rebases onto the base branch, resolves conflicts with best-effort judgment, pushes, and posts a result summary. Aborts cleanly if conflicts require human judgment.

How the trigger works

push to main
  → auto-rebase-reusable.yml runs
    → conflict detected (HTTP 422)
      → posts comment with <!-- auto-rebase-conflict --> sentinel
        → issue_comment event fires
          → claude-rebase job: checks condition
            (github-actions[bot] + sentinel present)
              → Claude rebases, resolves, pushes

The sentinel is idempotent — auto-rebase won't re-post it on subsequent runs, so Claude only gets one automatic attempt per conflict. If Claude's rebase also fails it posts a clear summary and a human takes over.

Conflict resolution strategy Claude uses

File type Strategy
Workflow YAML / action pins Accept main's version if it has a newer SHA; keep PR's if it's the newer fix
.gitignore, config Merge both sides, preserve all unique entries
Application code Careful merge; abort + explain if too complex

Test plan

  • Merge a PR that causes another open PR to conflict → confirm auto-rebase posts the updated conflict comment
  • Confirm claude-rebase job fires on that comment
  • Confirm Claude successfully rebases a simple conflict (workflow YAML SHA pin)
  • Force a complex conflict → confirm Claude aborts cleanly and posts an explanation
  • Confirm idempotency: re-running auto-rebase on a branch Claude already rebased does not re-trigger

Closes #279

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Automated PR rebasing on base branch updates with AI-powered conflict resolution for common merge conflicts
    • Intelligent failure handling with notifications when manual intervention is required for unresolvable conflicts
  • Tests

    • Added comprehensive test suite for auto-rebase automation workflow including shell script validation

Review Change Stack

When auto-rebase-reusable.yml encounters a conflict it cannot resolve
via the merge strategy, it already posts a sentinel comment
(<!-- auto-rebase-conflict -->). This commit wires that sentinel to a
new claude-rebase job that fires when github-actions[bot] posts that
comment on a PR, giving Claude a chance to rebase the branch and resolve
conflicts before escalating to a human.

Changes:
- auto-rebase-reusable.yml: update conflict comment to mention Claude
  will attempt an automatic rebase; switch manual instructions from
  merge to rebase (git rebase --continue / --force-with-lease)
- claude-code-reusable.yml: add claude-rebase job triggered by the
  <!-- auto-rebase-conflict --> sentinel; Claude checks out the branch,
  rebases onto the base branch, resolves conflicts using best-effort
  judgment (prefer main's side for superseded pins, keep PR's side for
  novel changes), pushes, and posts a summary; aborts cleanly if
  application-code conflicts require human judgment

Closes #279

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@don-petry don-petry requested a review from a team as a code owner May 13, 2026 17:29
Copilot AI review requested due to automatic review settings May 13, 2026 17:29
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Note

Gemini is unable to generate a review for this pull request due to the file types involved not being currently supported.

@coderabbitai

coderabbitai Bot commented May 13, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

This PR implements an agentic conflict resolution system for auto-rebasing pull requests. It adds a helper script with idempotent handlers for permission and merge-conflict errors, introduces a Claude-powered rebase job triggered by repository dispatch events, delivers comprehensive shell test infrastructure with gh CLI stubs, and wires everything together via workflow updates and a new CI harness.

Changes

Agentic auto-rebase conflict resolution

Layer / File(s) Summary
Auto-rebase handler script
scripts/auto-rebase.sh
Adds handle_permissions_block() to post idempotent permission-missing manual rebase instructions, and handle_conflict() to compute SHA-keyed conflict sentinels, dispatch a claude-rebase repository event, and post conflict-resolution instructions only after successful dispatch.
Test infrastructure and gh stubs
test/workflows/auto-rebase/helpers/setup.bash
Exports repo paths and script location; manages temp directories; installs single-response and multi-response gh CLI stubs driven by AR_GH_RESPONSES array; logs all gh invocations; provides assertion helpers to verify or deny gh calls by substring pattern.
Handler function test suite
test/workflows/auto-rebase/auto-rebase.bats
Bats tests validate idempotent behavior: handle_permissions_block covers posting/skipping blocked comments and verifying instruction text; handle_conflict covers SHA-keyed sentinel construction, conditional dispatch-only-when-absent, payload fields, multi-response stub coordination, comment content, and idempotency across runs with different base SHAs.
Reusable workflow refactoring and integration
.github/workflows/auto-rebase-reusable.yml
Removes inline error-handling logic, adds contents: write permission, checks out .github repo, sources scripts/auto-rebase.sh, and delegates permission and conflict errors to helper functions. Updates conflict documentation to describe SHA-keyed sentinels and repository_dispatch-based Claude rebase triggering.
Claude rebase automation job
.github/workflows/claude-code-reusable.yml
Introduces new claude-rebase job triggered by repository_dispatch events with action: claude-rebase. Checks out repo with full history, runs Claude Code action with a detailed rebase prompt covering conflict resolution strategy (prefer main for pins, merge configs carefully, best-effort for app code), force-push on success, or abort with conflict summary.
Test runner workflow
.github/workflows/auto-rebase-tests.yml
New CI workflow runs on PR and main push with path filters, installs bats and shellcheck, runs static checks on scripts/auto-rebase.sh, and executes bats test suite under test/workflows/auto-rebase/.

Sequence Diagram(s)

sequenceDiagram
  participant PR as Pull Request
  participant AutoRebase as auto-rebase-reusable
  participant Script as scripts/auto-rebase.sh
  participant GitHubAPI as GitHub API
  participant ClaudeJob as claude-rebase job
  participant Claude as Claude Code

  PR->>AutoRebase: Run auto-rebase workflow
  AutoRebase->>Script: Source and call handlers
  Script->>GitHubAPI: git merge (merge strategy)
  alt Merge conflict
    GitHubAPI-->>Script: HTTP 422 error
    Script->>GitHubAPI: GET PR comments (check sentinel)
    alt Sentinel absent
      Script->>GitHubAPI: repository_dispatch (claude-rebase)
      GitHubAPI-->>ClaudeJob: Trigger on dispatch event
      Script->>GitHubAPI: POST conflict comment (with sentinel)
      ClaudeJob->>Claude: Invoke with rebase prompt
      Claude->>GitHubAPI: git rebase, resolve conflicts
      Claude->>GitHubAPI: git push --force-with-lease
      Claude->>GitHubAPI: POST result comment
    else Sentinel present
      Script-->>Script: Skip (already dispatched)
    end
  else Merge succeeds
    GitHubAPI-->>AutoRebase: Success
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • petry-projects/.github#77: Introduces the claude-code-reusable.yml workflow file that is extended here with the new claude-rebase job.
  • petry-projects/.github#281: Modifies the same auto-rebase and claude-rebase integration surface to trigger agentic rebase via an alternative dispatch mechanism.

Suggested labels

needs-human-review

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 60.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat(auto-rebase): trigger Claude agentic rebase on merge conflict' clearly and specifically describes the primary change—adding Claude-based conflict resolution to the auto-rebase workflow.
Linked Issues check ✅ Passed All objectives from issue #279 are met: claude-rebase job added to claude-code-reusable.yml, conflict sentinel with SHA-keyed idempotency implemented, conflict resolution heuristics applied, safe failure modes with git rebase --abort, and comprehensive test coverage added.
Out of Scope Changes check ✅ Passed All changes are tightly scoped to implementing the agentic rebase feature: workflow updates (auto-rebase and claude-code), helper scripts for conflict handling, and a comprehensive test suite with CI integration—no unrelated modifications.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/auto-rebase-claude-agentic
⚔️ Resolve merge conflicts
  • Resolve merge conflict in branch feat/auto-rebase-claude-agentic

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 1ee5f5b6c7

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/auto-rebase-reusable.yml Outdated
Comment thread .github/workflows/claude-code-reusable.yml Outdated
Comment thread .github/workflows/auto-rebase-reusable.yml Outdated

Copilot AI 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.

Pull request overview

This PR adds an agentic fallback for auto-rebase conflicts: when the merge-based branch update hits a conflict, the workflow posts a sentinel comment intended to trigger Claude to attempt a rebase and conflict resolution.

Changes:

  • Updates the auto-rebase conflict comment to mention Claude’s automatic rebase attempt and rebase-based manual fallback.
  • Adds a claude-rebase job to the reusable Claude workflow for sentinel-triggered conflict resolution.
  • Provides Claude with instructions for checkout, rebase, conflict handling, force-with-lease push, and summary posting.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.

File Description
.github/workflows/auto-rebase-reusable.yml Updates conflict handling comments and sentinel-trigger messaging.
.github/workflows/claude-code-reusable.yml Adds the new Claude rebase automation job and prompt.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread .github/workflows/auto-rebase-reusable.yml Outdated
Comment thread .github/workflows/claude-code-reusable.yml Outdated
…ncy, git identity, tests

Addresses all issues raised by Codex and Copilot on PR #280:

P1 — GITHUB_TOKEN events don't trigger issue_comment workflows:
  Switch from comment-based trigger to repository_dispatch (one of only
  two event types GITHUB_TOKEN IS permitted to trigger workflow runs for).
  auto-rebase-reusable.yml fires `gh api .../dispatches` with event_type
  claude-rebase; claude.yml adds `repository_dispatch: types: [claude-rebase]`;
  claude-code-reusable.yml claude-rebase job triggers on repository_dispatch.

P2 — Idempotency sentinel too broad (one-shot per PR):
  Replace `<!-- auto-rebase-conflict -->` with a SHA-keyed sentinel
  `<!-- auto-rebase-conflict:{base_sha} -->` where base_sha is the first
  8 chars of the base branch HEAD. A new merge to the base branch changes
  the SHA, resetting the gate and giving Claude another attempt.

P2 — Missing git identity before rebase --continue:
  Add `git config user.name/user.email` to the claude-rebase prompt before
  any rebase operations.

Copilot — git rebase --continue called per-file instead of per-commit:
  Clarify in the prompt that all conflicted files for the current commit
  must be staged first, then `git rebase --continue` run once per commit.

Testability:
  Extract conflict-handling logic from inline YAML to scripts/auto-rebase.sh.
  Add 12-test BATS suite covering both handle_permissions_block and
  handle_conflict (sentinel presence, SHA-keyed idempotency, dispatch
  payload fields, comment body content, fallback instructions).
  Add .github/workflows/auto-rebase-tests.yml to run ShellCheck + bats
  on every PR touching the auto-rebase files.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 13, 2026
@don-petry

Copy link
Copy Markdown
Contributor Author

Review feedback addressed (commit 75afe83)

All 5 review threads have been resolved:

Issue Fix
P1 (Codex + Copilot)GITHUB_TOKEN comments don't trigger issue_comment workflows Switched to repository_dispatch (one of only two event types GITHUB_TOKEN can trigger workflows for). auto-rebase fires gh api .../dispatches; claude.yml adds repository_dispatch: types: [claude-rebase]; claude-rebase job triggers on repository_dispatch.
P2 (Codex) — Idempotency sentinel is one-shot per PR lifetime Replaced <!-- auto-rebase-conflict --> with a SHA-keyed sentinel <!-- auto-rebase-conflict:{base_sha} -->. Each new merge to the base branch advances the SHA, resetting the gate and allowing Claude another attempt.
P2 (Codex) — Missing git identity before rebase --continue Added git config user.name/user.email to the claude-rebase prompt before any rebase operations.
Copilotgit rebase --continue called per-file instead of per-commit Clarified in the prompt: stage all files for the current commit first, then run git rebase --continue once.
Test coverage Extracted conflict-handling logic to scripts/auto-rebase.sh. Added 12-test BATS suite + ShellCheck + auto-rebase-tests.yml CI gate. All 12 tests pass locally.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 75afe833d1

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .github/workflows/auto-rebase-reusable.yml
Comment thread scripts/auto-rebase.sh
@don-petry

Copy link
Copy Markdown
Contributor Author

@don-petry assigned me as reviewer — starting a fresh review now. Results will appear in a few minutes.

@don-petry

Copy link
Copy Markdown
Contributor Author

@donpetry-bot please review

@don-petry

Copy link
Copy Markdown
Contributor Author

@don-petry I'm on it — starting a fresh review now. Results will appear in a few minutes.

donpetry-bot
donpetry-bot previously approved these changes May 13, 2026

@donpetry-bot donpetry-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.

Automated review — APPROVED ✓

Risk: MEDIUM
Reviewed commit: de97a136428c17833f4374de399f41dd297fbc02
Review mode: triage-approved (single reviewer)

Summary

Adds an agentic auto-rebase fallback: when the merge strategy hits a conflict, auto-rebase-reusable.yml fires a repository_dispatch event (event_type: claude-rebase) which triggers a new claude-rebase job in claude-code-reusable.yml. Claude checks out the branch, rebases onto the base branch, resolves conflicts with bounded judgment, and pushes with --force-with-lease.

The second commit (75afe83) addressed all prior AI-reviewer feedback (Codex P1/P2, Copilot) — see below. Triage's low-risk classification is correct; the implementation has appropriate safeguards.

Linked issue analysis

Closes #279 (feat(auto-rebase): assign conflicting PRs to Claude for agentic rebase). All acceptance criteria are addressed:

  • ✅ Conflict comment now notes Claude will attempt the rebase
  • ✅ New claude-rebase job dispatched via repository_dispatch (the GITHUB_TOKEN-triggerable path)
  • ✅ Clear abort + summary comment path for unresolvable conflicts
  • ✅ Idempotency preserved via SHA-keyed sentinel (<!-- auto-rebase-conflict:{base_sha} -->)

Findings

Prior review feedback resolved (commit 75afe83):

  • Codex P1issue_comment events from GITHUB_TOKEN don't trigger workflows. Fixed by switching to repository_dispatch, which is one of only two event types GITHUB_TOKEN is permitted to trigger.
  • Codex P2 — Sentinel was one-shot per PR lifetime. Fixed by SHA-keying the sentinel to the base-branch HEAD; each new base merge resets the gate.
  • Codex P2 — Missing git identity before rebase --continue. Added git config user.name/user.email to the Claude prompt.
  • Copilotgit rebase --continue per-file instead of per-commit. Clarified in the prompt: stage all files for the commit, then --continue once.
  • Test gap — Extracted conflict-handling logic to scripts/auto-rebase.sh; added 12-test BATS suite + ShellCheck gate (.github/workflows/auto-rebase-tests.yml).

Security posture (the reason this stays MEDIUM, not HIGH):

  • All third-party actions are pinned to commit SHA (actions/checkout@de0fac2e…, anthropics/claude-code-action@476e359e…).
  • claude-rebase job uses a restricted --allowedTools allowlist (Bash(git*:*), Bash(gh pr ...), Bash(gh api:*), Edit, Write) rather than unrestricted tool use.
  • Permissions on the new job are scoped (contents: write, pull-requests: write, id-token: write, issues: write, plus read-only actions/checks).
  • Concurrency group claude-rebase-${pr_number} with cancel-in-progress: true prevents stacking.
  • 30-minute timeout caps blast radius.
  • Push uses --force-with-lease, not raw --force.
  • Rebase strategy explicitly aborts on complex application-code conflicts and falls back to a human-readable comment.
  • repository_dispatch payload is constructed from internal PR metadata (PR number, head ref, base branch), not from untrusted user input.

Minor observations (non-blocking):

  • The --allowedTools pattern Bash(git*:*) is broad — it matches any subcommand of git with any arguments. Given the scoped checkout and --force-with-lease push, the realistic blast radius is bounded to the PR branch, but tightening to specific git subcommands (git rebase:*, git push:*, git checkout:*, git add:*, git config:*, git fetch:*) would be a defense-in-depth win for a future PR.
  • secrets.GH_PAT_WORKFLOWS || github.token fallback for checkout/push: when the PAT is absent, force-pushing to a PR branch that touches .github/workflows/ will fail with the same workflows permission error the original workflow already handles upstream. That's the right failure mode (loud, not silent), and the manual-rebase comment path is preserved.

CI status

All checks green:

  • ✅ CodeQL — Analyze (actions)
  • ✅ CodeQL (aggregate)
  • ✅ CodeRabbit (status + approving review on this SHA)
  • ✅ SonarQube Quality Gate (0 new issues, 0 hotspots)
  • ✅ pr-review-mention / handle-mention

No unresolved review threads from human reviewers. Codex left automated suggestions on the prior SHA that have been addressed.


Reviewed automatically by the PR-review agent (single-reviewer mode: opus 4.7). Reply if you need a human review.

@donpetry-bot donpetry-bot enabled auto-merge (squash) May 13, 2026 22:08
P1 — script not found when reusable is called from other repos:
  The checkout in auto-rebase-reusable.yml checked out the CALLER's
  repository, so scripts/auto-rebase.sh was only present when the
  .github repo called itself. Fix: always checkout petry-projects/.github
  (the canonical home of the scripts) regardless of which repo invokes
  the reusable.

P2 — sentinel posted before dispatch, blocking retries on dispatch failure:
  Reorder handle_conflict to fire repository_dispatch first, post the
  SHA-keyed sentinel comment only after dispatch succeeds. If dispatch
  fails the comment is never written, so the next auto-rebase run for
  the same base SHA can retry cleanly.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@don-petry don-petry dismissed stale reviews from donpetry-bot and coderabbitai[bot] via a8b49e9 May 13, 2026 22:13
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 13, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a8b49e94fa

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/auto-rebase.sh
Comment on lines +67 to +72
gh api "repos/$REPO/dispatches" \
-X POST \
-f event_type=claude-rebase \
-F "client_payload[pr_number]=$pr_number" \
-F "client_payload[head_ref]=$head_ref" \
-F "client_payload[base_branch]=$base_branch"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Verify the Claude listener before marking dispatch handled

For downstream repos that pick up the updated auto-rebase-reusable.yml@v1 but have not yet copied the updated local claude.yml stub with on.repository_dispatch, this API call can succeed while no Claude workflow is actually listening on the repo’s default branch; GitHub documents repository_dispatch runs only when the workflow file exists on the default branch. Because the sentinel comment is posted immediately after this and future runs skip the same base SHA, those conflicted PRs are left with “Claude has been dispatched” but no rebase attempt. Add a compatibility check/fallback or avoid writing the sentinel until a run is confirmed.

Useful? React with 👍 / 👎.

Comment on lines +46 to +50
- name: Checkout petry-projects/.github (for scripts)
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
repository: petry-projects/.github
fetch-depth: 1

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Pin the helper checkout to the reusable ref

When a downstream repo invokes auto-rebase-reusable.yml@v1, this checkout does not specify ref, so the helper script is loaded from petry-projects/.github’s default branch rather than the same version as the reusable. I checked actions/checkout’s README: for a different repository, omitted ref “uses the default branch.” That bypasses the standards guarantee that @v1 insulates adopters from changes on main, so any future incompatible edit to scripts/auto-rebase.sh can break all pinned callers immediately; checkout the same tag/SHA as the reusable or vendor the script within the versioned workflow.

Useful? React with 👍 / 👎.

donpetry-bot
donpetry-bot previously approved these changes May 14, 2026

@donpetry-bot donpetry-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.

Automated review — APPROVED ✓

Risk: MEDIUM
Reviewed commit: 55877e1f580426cfd3a3857c5ea444c407f50912
Review mode: triage-approved (single reviewer, confirmation pass)

Summary

Confirmation review on a triage-approved PR. The prior bot review approved de97a13; two commits since address feedback from a second Codex review and a merge brings in orthogonal compliance changes from PR #277. The fixes are surgical, the security posture is unchanged (and arguably tightened), and CodeRabbit explicitly approved this exact SHA. Approving.

Linked issue analysis

Closes #279 (feat(auto-rebase): assign conflicting PRs to Claude for agentic rebase). All acceptance criteria remain addressed; the new commits don't alter the user-visible contract — they just fix two correctness/operability bugs uncovered by Codex on the prior SHA.

Findings — what changed since the prior approval (de97a13)

1. auto-rebase-reusable.yml — checkout the canonical scripts repo (commit a8b49e9)
The checkout step previously used the default (caller's) repository, so scripts/auto-rebase.sh was only present when .github called itself. Fixed by setting repository: petry-projects/.github on actions/checkout. This is correct: the script's interactions with the caller's PR go through gh CLI against $REPO (= github.repository, the caller), so the caller's working tree isn't needed in this job.

2. scripts/auto-rebase.sh — dispatch before sentinel (commit a8b49e9)
handle_conflict() now fires repository_dispatch first and posts the SHA-keyed sentinel comment only after dispatch succeeds. Previously, a failed dispatch would still leave the sentinel in place, permanently blocking retries for the current base SHA. The new order trades that failure mode for the much rarer case of a successful dispatch followed by a failed comment post — which would result in (at most) one duplicate Claude run on the next auto-rebase, bounded by the existing claude-rebase-${pr_number} concurrency group with cancel-in-progress: true. Net win.

3. Merge from main (commit 55877e1)
Merges PR #277 (gitleaks secret-scan job using SHA-pinned binary install with checksum verification, dtolnay SHA pin, root .gitleaks.toml). Orthogonal to this PR's scope; no interaction with the auto-rebase logic.

Security posture (still MEDIUM, not HIGH):

  • All third-party actions SHA-pinned (unchanged).
  • claude-rebase job retains its restricted --allowedTools allowlist (unchanged).
  • Scoped job permissions, --force-with-lease push, 30-min timeout, SHA-keyed sentinel idempotency, explicit abort-on-complex-conflict path — all unchanged.
  • The new explicit repository: petry-projects/.github checkout pins the script source to a trusted location, which is a small defense-in-depth improvement over relying on caller-controlled checkout content.

Carry-forward observation (non-blocking, same as prior review):
The Bash(git*:*) allowlist pattern is still broad. Tightening to specific git subcommands would be a future-PR defense-in-depth win, but the blast radius is bounded by the scoped checkout and force-with-lease, so this stays non-blocking.

CI status

All checks green on 55877e1:

  • ✅ CodeQL — Analyze (actions)
  • ✅ CodeQL (aggregate)
  • ✅ CodeRabbit (status + APPROVED review on this SHA)
  • ✅ SonarQube Quality Gate (0 new issues, 0 hotspots)

No unresolved human-reviewer threads. Codex's automated suggestions on prior SHAs have been addressed in a8b49e9.


Reviewed automatically by the PR-review agent (single-reviewer mode: opus 4.7). Reply if you need a human review.

@sonarqubecloud

Copy link
Copy Markdown

@don-petry

Copy link
Copy Markdown
Contributor Author

@donpetry-bot please review and approve — all CI checks are passing

@don-petry

Copy link
Copy Markdown
Contributor Author

@don-petry I'm on it — starting a fresh review now. Results will appear in a few minutes.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a1db44f317

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/auto-rebase.sh
Comment on lines +67 to +68
gh api "repos/$REPO/dispatches" \
-X POST \

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Continue after a failed Claude dispatch

If the repository_dispatch request fails for one conflicted PR due to a transient API/token problem, this unguarded gh api runs under the sourced script's set -e, so the entire auto-rebase step exits instead of moving on to the remaining PRs. That regresses the workflow's per-PR graceful handling: a single dispatch failure can leave later behind branches unprocessed until another push or manual run.

Useful? React with 👍 / 👎.

Comment on lines +361 to +363
if: >-
github.event_name == 'repository_dispatch' &&
github.event.action == 'claude-rebase'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Validate dispatch payload before running privileged rebase

This privileged job now trusts any repository_dispatch payload with action claude-rebase, but it never re-checks that the referenced PR is the same-repo, non-Dependabot PR that auto-rebase is supposed to handle. If another automation or a maintainer token dispatches this event with a fork PR number, the job still gets write permissions and inherited secrets and then instructs Claude to gh pr checkout and rebase that PR; add the same head-repo/bot gate used by the auto-rebase producer before invoking Claude.

Useful? React with 👍 / 👎.

@don-petry

Copy link
Copy Markdown
Contributor Author

Auto-rebase failed — merge conflict — this branch has conflicts with main that must be resolved.

Claude will attempt to resolve this automatically. If it cannot, a follow-up comment will explain what needs manual attention.

To resolve manually instead:

git fetch origin
git merge origin/main
# resolve conflicts, then:
git add .
git commit
git push

@don-petry

Copy link
Copy Markdown
Contributor Author

Auto-rebase failed — merge conflict — this branch has conflicts with main that must be resolved.

Claude will attempt to resolve this automatically. If it cannot, a follow-up comment will explain what needs manual attention.

To resolve manually instead:

git fetch origin
git merge origin/main
# resolve conflicts, then:
git add .
git commit
git push

@don-petry

Copy link
Copy Markdown
Contributor Author

Auto-rebase: Manual Resolution Required

The agentic rebase could not be completed automatically. Here's what was found:

Conflicting files

The PR branch diverges from main (commit 761dd4a) in the following workflow files:

File Conflict type
.github/workflows/auto-rebase-reusable.yml Application logic — PR refactors to repository_dispatch trigger + scripts/auto-rebase.sh extraction; main has older inline implementation
.github/workflows/claude-code-reusable.yml Application logic — PR changes claude-rebase job trigger from issue_comment to repository_dispatch; main has the previous trigger
.github/workflows/claude.yml Changed in main (761dd4a)
standards/ci-standards.md Changed in main (761dd4a)
standards/github-settings.md Changed in main (761dd4a)
standards/workflows/claude.yml Changed in main (761dd4a)

Why automatic resolution was skipped

These are application-logic conflicts, not simple action-pin version bumps. The PR and main have divergent implementations of the same feature (auto-rebase conflict handling), and choosing one side over the other would silently drop either the PR's refactored logic or main's current state. This requires human judgment.

Manual resolution steps

git fetch origin
git rebase origin/main
# Resolve conflicts in each file listed above.
# For each file: keep the PR's newer logic (repository_dispatch trigger,
# scripts/auto-rebase.sh sourcing) and incorporate any relevant changes
# from main's 761dd4a commit.
git add .github/workflows/auto-rebase-reusable.yml
git add .github/workflows/claude-code-reusable.yml
git add .github/workflows/claude.yml
git add standards/ci-standards.md
git add standards/github-settings.md
git add standards/workflows/claude.yml
git rebase --continue
git push --force-with-lease

Tip: The PR branch version of auto-rebase-reusable.yml and claude-code-reusable.yml contains the intended design. Review 761dd4a to check if any of its changes to those files should be forward-ported.

The claude.yml trigger change (adding repository_dispatch: [claude-rebase])
causes the expected OIDC validation failure on any PR that modifies
claude.yml — the Anthropic token endpoint requires the file to be
byte-for-byte identical to the default branch.

The claude-code-reusable.yml job (claude-rebase) receives the event
correctly as long as the CALLING repo's claude.yml declares the trigger.
That update to each repo's thin stub is a follow-up compliance sweep,
not a requirement for the reusable to work from .github itself.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@don-petry don-petry dismissed stale reviews from coderabbitai[bot] and donpetry-bot via 836f546 May 14, 2026 20:33

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 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/auto-rebase-tests.yml:
- Around line 32-33: The concurrency group currently uses the commit SHA (group:
auto-rebase-tests-${{ github.ref }}-${{ github.sha }}), which makes each run
unique and prevents cancel-in-progress from working; update the group key to be
stable per branch/PR by removing `${{ github.sha }}` and using a ref/PR-scoped
value instead (for example use `${{ github.ref }}` or for pull requests `${{
github.event.pull_request.number }}`/`${{ github.head_ref }}`) so that
cancel-in-progress: true will actually cancel previous runs for the same
branch/PR.

In `@test/workflows/auto-rebase/helpers/setup.bash`:
- Around line 25-26: The gh-call stub ar_install_gh_stub currently logs args
space-separated though the comment says argv should be tab-separated; update the
stub so it writes arguments to $AR_GH_LOG separated by tabs (use a tab delimiter
when joining "$@") and make the same change for the other gh-call stubs in this
file (the ones around the earlier 42-43 and later 67-68 blocks) so all argv
logging uses tab separation to preserve argument boundaries.
- Line 84: The ar_gh_call_count helper uses grep -c "$pattern" which treats
pattern as a regex; change it to fixed-string matching so special chars in
$pattern don't get interpreted. Update the invocation that sets count (the line
using count=$(grep -c "$pattern" "${AR_GH_LOG:-/dev/null}" 2>/dev/null) ||
count=0) to use grep --fixed-strings (or -F) and -- to end options, keeping the
same redirection and fallback so it still assigns count and handles missing
AR_GH_LOG correctly.
🪄 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: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 43ed7723-f550-4b58-b1b1-d5314adeed23

📥 Commits

Reviewing files that changed from the base of the PR and between 6f46503 and 836f546.

📒 Files selected for processing (6)
  • .github/workflows/auto-rebase-reusable.yml
  • .github/workflows/auto-rebase-tests.yml
  • .github/workflows/claude-code-reusable.yml
  • scripts/auto-rebase.sh
  • test/workflows/auto-rebase/auto-rebase.bats
  • test/workflows/auto-rebase/helpers/setup.bash

Comment on lines +32 to +33
group: auto-rebase-tests-${{ github.ref }}-${{ github.sha }}
cancel-in-progress: true

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Make concurrency key branch/PR-scoped (not SHA-scoped).

Using ${{ github.sha }} in the group makes each run unique, so cancel-in-progress: true won’t cancel older runs after new commits. Use a stable key per ref/PR instead.

Proposed fix
 concurrency:
-  group: auto-rebase-tests-${{ github.ref }}-${{ github.sha }}
+  group: auto-rebase-tests-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
   cancel-in-progress: true
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
group: auto-rebase-tests-${{ github.ref }}-${{ github.sha }}
cancel-in-progress: true
concurrency:
group: auto-rebase-tests-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
🤖 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/auto-rebase-tests.yml around lines 32 - 33, The
concurrency group currently uses the commit SHA (group: auto-rebase-tests-${{
github.ref }}-${{ github.sha }}), which makes each run unique and prevents
cancel-in-progress from working; update the group key to be stable per branch/PR
by removing `${{ github.sha }}` and using a ref/PR-scoped value instead (for
example use `${{ github.ref }}` or for pull requests `${{
github.event.pull_request.number }}`/`${{ github.head_ref }}`) so that
cancel-in-progress: true will actually cancel previous runs for the same
branch/PR.

Comment on lines +25 to +26
# The stub logs each invocation to $AR_GH_LOG (one line per call, argv tab-separated).
ar_install_gh_stub() {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Align gh-call log format with the documented contract.

The comment says argv is tab-separated, but the stub writes space-separated args. This can blur argument boundaries and weaken assertions for arguments containing spaces.

Proposed fix
-# The stub logs each invocation to $AR_GH_LOG (one line per call, argv tab-separated).
+# The stub logs each invocation to $AR_GH_LOG (one line per call, argv tab-separated).

-printf '%s ' "\$@" >> "${AR_TMP}/gh.log"
+printf '%s\t' "\$@" >> "${AR_TMP}/gh.log"
 printf '\n'   >> "${AR_TMP}/gh.log"

-printf '%s ' "\$@" >> "${AR_TMP}/gh.log"
+printf '%s\t' "\$@" >> "${AR_TMP}/gh.log"
 printf '\n'   >> "${AR_TMP}/gh.log"

Also applies to: 42-43, 67-68

🤖 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 `@test/workflows/auto-rebase/helpers/setup.bash` around lines 25 - 26, The
gh-call stub ar_install_gh_stub currently logs args space-separated though the
comment says argv should be tab-separated; update the stub so it writes
arguments to $AR_GH_LOG separated by tabs (use a tab delimiter when joining
"$@") and make the same change for the other gh-call stubs in this file (the
ones around the earlier 42-43 and later 67-68 blocks) so all argv logging uses
tab separation to preserve argument boundaries.

local pattern="$1"
local count
# grep -c prints 0 even on no match; exit code 1 means no match (not error).
count=$(grep -c "$pattern" "${AR_GH_LOG:-/dev/null}" 2>/dev/null) || count=0

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use fixed-string matching for call assertions.

ar_gh_call_count says “substring match,” but grep -c "$pattern" treats the pattern as regex. Patterns containing []()|* can miscount or fail unexpectedly.

Proposed fix
-  count=$(grep -c "$pattern" "${AR_GH_LOG:-/dev/null}" 2>/dev/null) || count=0
+  count=$(grep -F -c -- "$pattern" "${AR_GH_LOG:-/dev/null}" 2>/dev/null) || count=0
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
count=$(grep -c "$pattern" "${AR_GH_LOG:-/dev/null}" 2>/dev/null) || count=0
count=$(grep -F -c -- "$pattern" "${AR_GH_LOG:-/dev/null}" 2>/dev/null) || count=0
🤖 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 `@test/workflows/auto-rebase/helpers/setup.bash` at line 84, The
ar_gh_call_count helper uses grep -c "$pattern" which treats pattern as a regex;
change it to fixed-string matching so special chars in $pattern don't get
interpreted. Update the invocation that sets count (the line using count=$(grep
-c "$pattern" "${AR_GH_LOG:-/dev/null}" 2>/dev/null) || count=0) to use grep
--fixed-strings (or -F) and -- to end options, keeping the same redirection and
fallback so it still assigns count and handles missing AR_GH_LOG correctly.

@don-petry

Copy link
Copy Markdown
Contributor Author

Closing — the core feature (agentic Claude rebase fallback) was delivered via #281, which merged a more complete implementation (PAT-based sentinel, SHA-keyed delete-and-repost idempotency, semver version comparison in the prompt).

PR #280's unique contribution was the test suite (test/workflows/auto-rebase/) and the extracted scripts/auto-rebase.sh helper. However, those tests exercise handle_conflict / handle_permissions_block functions that no longer exist — #281 inlined the logic back into the workflow YAML with a different approach.

Follow-up: open a new PR that extracts #281's inline conflict-handling logic into scripts/auto-rebase.sh and writes BATS tests against that implementation. The test harness from this PR (helpers/setup.bash, stubs, auto-rebase-tests.yml) can be reused.

@don-petry don-petry closed this May 14, 2026
auto-merge was automatically disabled May 14, 2026 20:46

Pull request was closed

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.

feat(auto-rebase): assign conflicting PRs to Claude for agentic rebase

3 participants