Skip to content

Harden auto-merge workflow collaborator check - #7

Merged
robnester-rh merged 1 commit into
conforma:mainfrom
robnester-rh:EC-2055
Aug 25, 2026
Merged

Harden auto-merge workflow collaborator check#7
robnester-rh merged 1 commit into
conforma:mainfrom
robnester-rh:EC-2055

Conversation

@robnester-rh

Copy link
Copy Markdown
Contributor

What

The reusable auto-merge workflow expanded GitHub context expressions
(repository name, sender login, PR number) directly into its inline run:
script. This change passes them through env: and GraphQL variables and
matches the approving collaborator in the shell instead.

Why

The workflow runs with contents: write and is reused across many
repositories. Keeping event-provided data out of the interpreted command
is defense-in-depth against context-expression injection in a shared,
write-capable component.

Also included

While rewriting the collaborator lookup, made it more robust:

  • Pagination — the collaborators connection is now paginated, so an
    approver beyond the first page is still recognized.
  • Fail closed on error — an API failure now exits non-zero instead of
    being silently treated as "not a collaborator".

Behavior

Auto-merge is still enabled only for approved bot pull requests whose
approver is a repository collaborator.

Validation

  • actionlint + shellcheck clean
  • No ${{ }} expansions remain in the run: body (only env: and the
    job-level if:)

Ref: EC-2055

Pass the repository name, sender login, and pull request number to the
reusable auto-merge workflow's run step through env: variables and
GraphQL variables, and match the approving collaborator in the shell,
instead of expanding GitHub context expressions directly into the inline
script. This keeps event data out of the interpreted command as
defense-in-depth for a reusable workflow that runs with contents: write
across many repositories.

While rewriting the collaborator lookup, also make it more robust:
paginate the collaborators connection so an approver beyond the first
page is still recognized, and fail closed (exit non-zero) on an API
error rather than treating the failure as "not a collaborator".

Auto-merge is still enabled only for approved bot pull requests whose
approver is a repository collaborator.

Co-Authored-By: Claude <noreply@anthropic.com>
Ref: EC-2055
@coderabbitai

coderabbitai Bot commented Aug 20, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: 8bbb554b-9124-4568-bf6b-ac9ae6d072f4

📥 Commits

Reviewing files that changed from the base of the PR and between e049ae9 and d007c5c.

📒 Files selected for processing (1)
  • .github/workflows/auto-merge.yaml

Included review availability: Your plan provides up to 12 included reviews per hour; 11 remain after this review.


📝 Walkthrough

Walkthrough

The auto-merge workflow now uses environment variables, retrieves collaborators through paginated GraphQL requests, handles API failures, and enables auto-merge only when the sender is a collaborator.

Changes

Auto-merge collaborator validation

Layer / File(s) Summary
Collaborator lookup and auto-merge gate
.github/workflows/auto-merge.yaml
The workflow passes repository, sender, pull-request, and token values through environment variables. It retrieves paginated collaborators, exits on API errors, compares the sender login, and enables auto-merge only for matching collaborators.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: ⚪ Minimal · up to d007c

The workflow hardens handling of event-provided values while preserving auto-merge behavior; no actionable merge-blocking risk remains.

Sequence Diagram(s)

sequenceDiagram
  participant AutoMergeWorkflow
  participant GitHubGraphQLAPI
  participant PullRequest
  AutoMergeWorkflow->>GitHubGraphQLAPI: Retrieve paginated collaborators
  GitHubGraphQLAPI-->>AutoMergeWorkflow: Return collaborator data or API error
  AutoMergeWorkflow->>PullRequest: Compare SENDER_LOGIN and enable auto-merge when matched
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: hardening the auto-merge workflow's collaborator check.
Description check ✅ Passed The description accurately explains the workflow hardening, pagination, fail-closed behavior, and validation results.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0 files. (1 skipped: 1 unsupported.)
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

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

@qodo-for-conforma

Copy link
Copy Markdown

PR Summary by Qodo

Harden auto-merge workflow collaborator check against context injection

✨ Enhancement 🐞 Bug fix ⚙️ Configuration changes 🕐 10-20 Minutes

Grey Divider

AI Description

• Move GitHub context values into env/GraphQL variables to avoid inline script interpolation.
• Paginate collaborator lookup and match approver in shell for correctness.
• Fail closed on API errors to avoid silently skipping valid collaborator approvals.
Diagram

graph TD
  A(["PR review event"]) --> B["auto-merge job"] --> C["gh api graphql (paginate)"] --> D{"sender is collaborator?"}
  D -->|"yes"| E["gh pr merge --auto"]
  D -->|"no"| F["notice + stop"]
  C -->|"API error"| G["error + exit 1"]

  subgraph Legend
    direction LR
    _evt(["Event"]) ~~~ _step["Step"] ~~~ _dec{"Decision"}
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Use REST collaborator check endpoint
  • ➕ Simpler: a single request like GET /repos/{owner}/{repo}/collaborators/{username}
  • ➕ No pagination or list processing required
  • ➖ May require specific permissions to reliably determine collaboration status across repos
  • ➖ Less flexible if future logic needs additional collaborator metadata
2. Use actions/github-script (Octokit) instead of shell + gh
  • ➕ Avoids shell parsing/matching and reduces injection surface further
  • ➕ Structured API calls and errors are easier to handle consistently
  • ➖ Adds action/runtime dependency and a different execution environment
  • ➖ More verbose than the current gh-based approach for a small workflow

Recommendation: The current approach (env + GraphQL variables, shell-side matching, pagination, and fail-closed error handling) is a strong defense-in-depth improvement for a reusable write-capable workflow. Consider the REST single-user collaborator check only if permissions are known to be sufficient across all consuming repos; otherwise, the paginated GraphQL list remains the most portable and explicit option.

Files changed (1) +41 / -6

Other (1) +41 / -6
auto-merge.yamlAvoid inline context interpolation and harden collaborator verification +41/-6

Avoid inline context interpolation and harden collaborator verification

• Stops expanding GitHub context expressions directly inside the inline shell script by passing repo/login/PR number via env and GraphQL variables. Adds paginated collaborator retrieval, matches the sender login in the shell, and fails the job on API errors rather than silently treating them as non-collaborators.

.github/workflows/auto-merge.yaml

@qodo-for-conforma

qodo-for-conforma Bot commented Aug 20, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📎 Requirement gaps (0) 🎨 UX issues (0) 🔗 Cross-repo conflicts (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Unbounded collaborator pagination ✗ Dismissed 🐞 Bug ➹ Performance
Description
The workflow paginates and downloads the full collaborators list before checking whether
SENDER_LOGIN is present, making the step’s runtime/API usage proportional to collaborator count.
On repos with many collaborators, this can significantly slow the job and increase the chance of
GitHub API rate-limit/time-budget failures.
Code

.github/workflows/auto-merge.yaml[R46-49]

+          if ! collaborators="$(gh api graphql --paginate \
+            -f owner="$ORG" -f name="$REPO" \
+            -f query='query($owner: String!, $name: String!, $endCursor: String) {
+              repository(owner: $owner, name: $name) {
Evidence
The script explicitly uses --paginate to enumerate collaborator pages into collaborators, then
iterates the entire output to find a single matching login, which requires downloading all pages
before the loop even begins.

.github/workflows/auto-merge.yaml[46-67]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

### Issue description
The workflow currently uses `gh api graphql --paginate` to fetch *all* collaborators (all pages) and then scans the full list to see if it contains the approving user. This is O(N) in number of collaborators and can become slow and API-expensive in large repositories.

### Issue Context
This step only needs to answer: “Is `$SENDER_LOGIN` a collaborator?” — it does not need the entire collaborators list.

### Fix Focus Areas
- .github/workflows/auto-merge.yaml[46-67]

### Suggested fix
Replace the full-list pagination with a targeted membership check for the single login, e.g. using a REST endpoint that returns 204/404 for collaborator membership, or a GraphQL query that filters by login (if available). Ensure failures still "fail closed" (non-zero exit) and keep all event-provided values passed via `env:`/variables (no direct `${{ }}` expansion in `run:`).

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Tip of the day
💡 Did you know, you can hide the parts of a finding you never read, like the evidence or the agent prompt

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread .github/workflows/auto-merge.yaml
@robnester-rh
robnester-rh merged commit db8c967 into conforma:main Aug 25, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants