Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
137 changes: 137 additions & 0 deletions .github/workflows/auto-merge.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
# Auto-merge workflow for trusted PRs
#
# Tiers:
# 1a. Dependabot PRs: Auto-approve + auto-merge for patch/minor
# 1b. Renovate PRs: Auto-approve + auto-merge
# 2. AI Agent fix PRs (copilot/, jules/, claude/): Auto-merge when CI passes
# 3. CodeRabbit approved PRs: Auto-merge when CI passes
Comment on lines +6 to +7

Copilot AI Jan 15, 2026

Copy link

Choose a reason for hiding this comment

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

The comments claim "Auto-merge when CI passes" for tiers 2 and 3, but the workflow does not actually wait for or verify that CI checks have passed before enabling auto-merge. The workflow should either include logic to verify CI status or update the comments to accurately reflect the actual behavior (immediate auto-merge without CI verification).

Suggested change
# 2. AI Agent fix PRs (copilot/, jules/, claude/): Auto-merge when CI passes
# 3. CodeRabbit approved PRs: Auto-merge when CI passes
# 2. AI Agent fix PRs (copilot/, jules/, claude/): Auto-merge
# 3. CodeRabbit approved PRs: Auto-merge

Copilot uses AI. Check for mistakes.

name: Auto-merge

on:
pull_request_target:
types: [opened, synchronize, reopened, ready_for_review]
Comment on lines +12 to +13

Copilot AI Jan 15, 2026

Copy link

Choose a reason for hiding this comment

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

Using pull_request_target with automatic approval and merging poses a security risk. The pull_request_target event runs with write permissions in the context of the base repository, even for PRs from forks. While the current implementation restricts execution to specific actors (dependabot, renovate, specific branch prefixes), a compromised bot account or malicious actor could potentially exploit this. Consider adding additional safety checks such as verifying that the PR is from the same repository (not a fork) or requiring CI checks to pass before auto-merging.

Copilot uses AI. Check for mistakes.
pull_request_review:
types: [submitted]

permissions:
contents: write

Copilot AI Jan 15, 2026

Copy link

Choose a reason for hiding this comment

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

The workflow has broad permissions (contents: write, pull-requests: write) that apply to all jobs. Following the principle of least privilege, jobs should only have the permissions they actually need. For example, the CodeRabbit job only needs to enable auto-merge (pull-requests: write) but not contents: write. Consider setting permissions at the job level instead of the workflow level to minimize the security surface area.

Suggested change
contents: write
contents: read

Copilot uses AI. Check for mistakes.
pull-requests: write

jobs:
dependabot-auto-merge:
name: Dependabot auto-merge
runs-on: ubuntu-latest
if: github.actor == 'dependabot[bot]'

steps:
- name: Fetch Dependabot metadata
id: metadata
uses: dependabot/fetch-metadata@v2
with:
github-token: ${{ secrets.GITHUB_TOKEN }}

- name: Auto-approve patch and minor updates
if: steps.metadata.outputs.update-type != 'version-update:semver-major'
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh pr review --approve "$PR_URL"

- name: Enable auto-merge for patch and minor
if: steps.metadata.outputs.update-type != 'version-update:semver-major'
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh pr merge --auto --squash "$PR_URL"
Comment on lines +22 to +46

Copilot AI Jan 15, 2026

Copy link

Choose a reason for hiding this comment

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

The Dependabot auto-merge job will run on every event type listed in the trigger (opened, synchronize, reopened, ready_for_review, pull_request_review submitted, and check_suite completed), even though it only needs to run when the PR is first opened or updated. This could lead to unnecessary workflow executions. Consider adding event type filtering to the job's if condition to only run on relevant events, such as checking that github.event_name is 'pull_request_target'.

Copilot uses AI. Check for mistakes.

- name: Comment on major updates
if: steps.metadata.outputs.update-type == 'version-update:semver-major'
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
DEP_NAMES: ${{ steps.metadata.outputs.dependency-names }}
PREV_VERSION: ${{ steps.metadata.outputs.previous-version }}
NEW_VERSION: ${{ steps.metadata.outputs.new-version }}
run: |
gh pr comment "$PR_URL" --body "## ⚠️ Major Version Update

This is a **major version update** that may contain breaking changes.

**Manual review required.**

Dependency: \`$DEP_NAMES\`
Update: \`$PREV_VERSION\` → \`$NEW_VERSION\`"
Comment on lines +57 to +64

Copilot AI Jan 15, 2026

Copy link

Choose a reason for hiding this comment

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

The multi-line comment body contains indented text that will be included in the comment as-is, potentially with unwanted leading whitespace on each line. This could result in poorly formatted GitHub comments. Consider using a heredoc or adjusting the indentation to ensure the comment text starts at column 0 after the opening quote.

Suggested change
gh pr comment "$PR_URL" --body "## ⚠️ Major Version Update
This is a **major version update** that may contain breaking changes.
**Manual review required.**
Dependency: \`$DEP_NAMES\`
Update: \`$PREV_VERSION\` → \`$NEW_VERSION\`"
gh pr comment "$PR_URL" --body-file - <<EOF
## ⚠️ Major Version Update
This is a **major version update** that may contain breaking changes.
**Manual review required.**
Dependency: \`$DEP_NAMES\`
Update: \`$PREV_VERSION\` → \`$NEW_VERSION\`
EOF

Copilot uses AI. Check for mistakes.

renovate-auto-merge:
name: Renovate auto-merge
runs-on: ubuntu-latest
if: github.actor == 'renovate[bot]'

steps:
- name: Auto-approve Renovate PRs
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh pr review --approve "$PR_URL"

- name: Enable auto-merge for Renovate
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh pr merge --auto --squash "$PR_URL"
Comment on lines +66 to +82

Copilot AI Jan 15, 2026

Copy link

Choose a reason for hiding this comment

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

The Renovate and AI agent auto-merge jobs do not check if the pull request is in draft state before enabling auto-merge. This could result in draft PRs being automatically merged, which is likely unintended. Consider adding a condition to check that the PR is not a draft, similar to checking if the PR event type is 'ready_for_review' or by adding a condition like 'github.event.pull_request.draft == false'.

Copilot uses AI. Check for mistakes.

Comment on lines +72 to +83

Copilot AI Jan 15, 2026

Copy link

Choose a reason for hiding this comment

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

The Renovate auto-merge job approves and merges all Renovate PRs without checking for major version updates, unlike the Dependabot job which has special handling for major updates (lines 50-66). This inconsistency means major breaking changes from Renovate could be auto-merged without manual review. Consider adding similar major version protection for Renovate PRs or documenting why this difference in behavior is intentional.

Suggested change
- name: Auto-approve Renovate PRs
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh pr review --approve "$PR_URL"
- name: Enable auto-merge for Renovate
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh pr merge --auto --squash "$PR_URL"
- name: Detect Renovate major updates
id: renovate_metadata
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Detect if this Renovate PR represents a major version update.
# Renovate typically labels such PRs with "major" or "renovate/major".
LABELS_JSON=$(gh pr view "$PR_URL" --json labels)
if echo "$LABELS_JSON" | grep -qi '"name":"major"'; then
echo "update-type=version-update:semver-major" >> "$GITHUB_OUTPUT"
elif echo "$LABELS_JSON" | grep -qi '"name":"renovate/major"'; then
echo "update-type=version-update:semver-major" >> "$GITHUB_OUTPUT"
else
echo "update-type=version-update:semver-non-major" >> "$GITHUB_OUTPUT"
fi
- name: Auto-approve Renovate PRs
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh pr review --approve "$PR_URL"
- name: Enable auto-merge for Renovate (non-major)
if: steps.renovate_metadata.outputs.update-type != 'version-update:semver-major'
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh pr merge --auto --squash "$PR_URL"
- name: Comment on Renovate major updates
if: steps.renovate_metadata.outputs.update-type == 'version-update:semver-major'
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh pr comment "$PR_URL" --body "## ⚠️ Renovate Major Version Update
This is a **major version update** created by Renovate and may contain breaking changes.
**Auto-merge has been disabled. Manual review and merge are required.**"

Copilot uses AI. Check for mistakes.
ai-agent-auto-merge:
name: AI Agent auto-merge
runs-on: ubuntu-latest
if: |
(github.actor == 'copilot[bot]' || github.actor == 'jules[bot]' || github.actor == 'claude-code[bot]') &&
(
startsWith(github.event.pull_request.head.ref, 'copilot/') ||
startsWith(github.event.pull_request.head.ref, 'jules/') ||
startsWith(github.event.pull_request.head.ref, 'claude/')
)

steps:
- name: Identify AI agent
id: agent
env:
BRANCH: ${{ github.event.pull_request.head.ref }}
run: |
if [[ "$BRANCH" == copilot/* ]]; then
echo "agent=Copilot" >> "$GITHUB_OUTPUT"
elif [[ "$BRANCH" == jules/* ]]; then
echo "agent=Jules" >> "$GITHUB_OUTPUT"
elif [[ "$BRANCH" == claude/* ]]; then
echo "agent=Claude" >> "$GITHUB_OUTPUT"
fi

- name: Auto-approve AI agent PRs
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
AGENT: ${{ steps.agent.outputs.agent }}
run: |
echo "Auto-approving $AGENT PR"
gh pr review --approve "$PR_URL" --body "✅ Auto-approved: $AGENT autonomous fix PR"

- name: Enable auto-merge for AI agent PRs
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh pr merge --auto --squash "$PR_URL"

coderabbit-auto-merge:
name: CodeRabbit auto-merge
runs-on: ubuntu-latest
if: |
github.event_name == 'pull_request_review' &&
github.event.review.state == 'approved' &&
github.event.review.user.login == 'coderabbitai[bot]'

steps:
- name: Enable auto-merge for CodeRabbit approved PRs
env:
PR_URL: ${{ github.event.pull_request.html_url }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: gh pr merge --auto --squash "$PR_URL"
Comment on lines +124 to +137

Copilot AI Jan 15, 2026

Copy link

Choose a reason for hiding this comment

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

The CodeRabbit auto-merge job does not check if the pull request is in draft state before enabling auto-merge. This could result in draft PRs being automatically merged after CodeRabbit approval, which is likely unintended. Consider adding a condition to check that the PR is not a draft by adding 'github.event.pull_request.draft == false' to the job's if condition.

Copilot uses AI. Check for mistakes.

Copilot AI Jan 15, 2026

Copy link

Choose a reason for hiding this comment

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

The gh CLI commands do not have error handling or continue-on-error configured. If a command fails (e.g., due to permissions issues, API rate limits, or network problems), the workflow will fail silently without providing useful feedback. Consider adding error handling or at least ensuring that failures are visible and don't leave PRs in an inconsistent state where they might be partially approved but not merged.

Suggested change
run: gh pr merge --auto --squash "$PR_URL"
run: gh pr merge --auto --squash "$PR_URL" || { echo "Failed to auto-merge CodeRabbit-approved PR $PR_URL"; exit 1; }

Copilot uses AI. Check for mistakes.