Skip to content

ci: adopt the inline pr-agent lane — a public repo cannot call a private reusable workflow - #59

Merged
yakimoto merged 3 commits into
mainfrom
ci/adopt-inline-pr-agent
Aug 24, 2026
Merged

ci: adopt the inline pr-agent lane — a public repo cannot call a private reusable workflow#59
yakimoto merged 3 commits into
mainfrom
ci/adopt-inline-pr-agent

Conversation

@yakimoto

@yakimoto yakimoto commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

User description

User description

User description

Part of the fan-out tracked in wave-pen#388, proven first on wave-certify#44 where pr_agent returned success.

The defect

pr-agent.yml here calls wave-av/wave-foundation/.github/workflows/reusable-pr-agent.yml@main, and wave-foundation is private. GitHub does not permit a public repository to call a reusable workflow from a private one, so the uses: never resolves: the run dies before any job is created — conclusion: failure, total_count: 0, no log, and no check run on the head sha at all.

That is worse than a normal failure. There is nothing to click through to. Every PR on this repo has been carrying a red check that reports nothing, and external contributors see it.

Measured on this repo today — the last 5 pr-agent runs:

failure, failure, failure, failure, failure

Measured across the org on 2026-08-22: 7 public repos / 176 runs / 100% failure; 9 private repos / zero failures. A clean 16/16 split on visibility alone. Three competing hypotheses were each tested and refuted — missing OPENAI_KEY (present in both populations), a dead pinned ref (150ffae2 resolves, file exists at it), and @main vs a pinned sha (wave-realtime-edge pins @main and fails, wave-pen pins @main and works).

The fix already existed and was never adopted

wave-foundation-public/.github/workflows/pr-agent.yml is an inline copy of the same lane with no reference to the private repo. Its own header says it was written for exactly this. This PR adopts it verbatim.

So this is an adoption gap, not a design gap.

Why now, and not when #388 was filed

#388 named two blockers, and both are cleared as of wave-foundation-public#71:

  1. The shared concurrency key. The template carried pr-agent-${{ github.event.pull_request.number || … }}, shared between pull_request and issue_comment, so any bot comment cancelled a live review ~10s in (wave-pen#386). It now keys on github.event_name.
  2. Missing step-level timeouts. The template now carries 6.

Fanning out before those landed would have traded a red-with-no-log lane for a cancelled-on-every-comment lane — a different failure, not a fix.

Verified before opening this

  • The template is genuinely self-contained. Its only two wave-foundation/ mentions are in comments, not in a uses:. Checked rather than assumed, since that is the whole property this depends on.
  • The job id stays pr_agent. A job's id is its check-run context and branch protection matches on (context, app_id), so nothing needs touching on the protection side.
  • The workflow parses, and the source was read from a fresh clone of wave-foundation-public's default branch — not from a local checkout that might be parked on another branch.

The receipt is this PR, not the diff

A red lane and a working lane are indistinguishable until one actually runs — that is the whole reason 176 failures went unexamined. So the proof is pr-agent going green on this PR. If it does, the remaining 27 repos get the same change with evidence behind it. If it does not, we learn that here, on one low-traffic repo, instead of across the org's entire public surface.

Proven before fanning out. wave-certify#44 took this exact change first and its pr_agent run returned success on the pull_request event — a job with a real log, where the broken form produced no job at all. The other repos were not changed on hope.

Refs wave-pen#388


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is disabled.


Note

Medium Risk
CI-only, but it posts on PRs with GITHUB_TOKEN/OPENAI_KEY and changes how an advisory check succeeds or stays green. Misclassification could hide real failures or still flake checks.

Overview
Stops calling the private wave-foundation reusable workflow (which GitHub never resolves from a public repo) and inlines the pr-agent job so reviews actually start and produce logs.

Concurrency now includes github.event_name, so slash-command comments no longer cancel in-flight push reviews. The job skips bots, drafts, forks, and untrusted comments.

Runs pinned The-PR-Agent/pr-agent v0.42.0 twice (6-minute step budget, 45s backoff, continue-on-error). A verdict step classifies success, cancel, hang vs rate-limit and exits 0 on advisory flakes so a 429 cannot block the PR.

Reviewed by Cursor Bugbot for commit bf8a3b7. Bugbot is set up for automated code reviews on this repo. Configure here.

Review in cubic

Summary by Sourcery

Adopt the self-contained public pr-agent workflow so advisory reviews run reliably and safely on this repository.

Bug Fixes:

  • Replace the unusable private reusable workflow reference so public repositories can run pr-agent and receive a real check result.
  • Prevent fork-originated comment reviews from using the advisory lane's credentials, failing closed when fork status cannot be determined.

Enhancements:

  • Improve pr-agent reliability with event-specific concurrency, bounded retries, step timeouts, and non-blocking verdict classification for reviewer failures and rate limits.

CI:

  • Inline the public pr-agent workflow configuration while preserving the existing pr_agent check context and supporting pull request and trusted slash-command review events.

PR Type

Bug fix


Description

  • Replaced private workflow reference with inline public version

  • Added concurrency controls for event-specific grouping

  • Implemented fork detection gate for security

  • Added retry logic with timeout management

  • Enhanced verdict classification for failure analysis


Diagram Walkthrough

flowchart TD
  A["Previous workflow"] --> B["Failure: private repo access"]
  B --> C["Adopt inline public workflow"]
  C --> D["Concurrency group fix"]
  D --> E["Fork detection added"]
  E --> F["Retry logic with timeout"]
  F --> G["Enhanced failure classification"]
Loading

File Walkthrough

Relevant files
Bug fix
pr-agent.yml
Migrated to inline pr-agent workflow with enhanced reliability

.github/workflows/pr-agent.yml

  • Replaced private workflow reference with inline public version
  • Added concurrency controls for event-specific grouping
  • Implemented fork detection gate for security
  • Added retry logic with timeout management
  • Enhanced verdict classification for failure analysis
+301/-7 

@codeant-ai

codeant-ai Bot commented Aug 23, 2026

Copy link
Copy Markdown

🤖 CodeAnt AI — Review Status

Status Commit Started (UTC) Finished (UTC)
✅ Incremental review completed bf8a3b7 Aug 24, 2026 · 13:36 13:36
✅ Reviewed your PR 889c2a6 Aug 23, 2026 · 22:36 22:37

@cursor

cursor Bot commented Aug 23, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_e79b57be-3720-4adb-b95f-c802d07e28d6)

@sourcery-ai

sourcery-ai Bot commented Aug 23, 2026

Copy link
Copy Markdown

Reviewer's Guide

This PR replaces the broken reusable GitHub Actions workflow invocation for pr-agent in a public repo with an inline, self-contained workflow that mirrors the private reusable lane, adds concurrency-key and timeout fixes, and introduces explicit retry and verdict logic so pr-agent is advisory and resilient to failures and rate limits.

Sequence diagram for the inline PR-Agent review with retry and verdict

sequenceDiagram
    participant GitHub
    participant Workflow
    participant Qodo as PR-Agent Qodo Merge
    participant Router as LLM Router
    participant Verdict

    GitHub->>Workflow: Trigger pull_request or trusted /review comment
    Workflow->>Workflow: Evaluate pr_agent condition
    Workflow->>Qodo: Run PR-Agent attempt 1
    Qodo->>Router: Request review
    alt Attempt 1 succeeds
        Router-->>Qodo: Review result
        Qodo-->>Workflow: success
    else Attempt 1 fails
        Router-->>Qodo: Error or timeout
        Qodo-->>Workflow: failure
        Workflow->>Workflow: backoff before retry
        Workflow->>Qodo: Run PR-Agent retry attempt 2
        Qodo->>Router: Request review
        Router-->>Qodo: Review result or failure
        Qodo-->>Workflow: Retry outcome
    end
    Workflow->>Verdict: Run verdict
    Verdict-->>GitHub: Advisory check result
Loading

File-Level Changes

Change Details Files
Replace the reusable pr-agent workflow call with an inline, self-contained workflow that is safe for public repositories and mirrors the private reusable lane.
  • Remove the uses: wave-av/wave-foundation/.github/workflows/reusable-pr-agent.yml@main job invocation relying on a private repo.
  • Introduce a full inline pr_agent job definition including runner, steps, and environment configuration for The-PR-Agent.
  • Configure pr-agent to use the org’s OpenAI-backed dispatch endpoint and specific models, tokens, timeout, and suggestion settings via environment variables.
.github/workflows/pr-agent.yml
Fix concurrency behavior to avoid issue_comment runs cancelling in-flight pull_request reviews and to keep slash-command reviews in their own lane.
  • Update the concurrency group key to include github.event_name along with PR/issue number/ref.
  • Retain cancel-in-progress: true so newer runs still supersede older runs for the same event type.
  • Document measured behavior and rationale for the new concurrency key in comments for future maintainers.
.github/workflows/pr-agent.yml
Add step-level timeouts, retry/backoff, and explicit verdict classification so pr-agent behaves as a non-blocking advisory reviewer and differentiates failure modes.
  • Set a 15-minute job-level timeout and 6-minute step-level timeouts for both pr-agent attempts to keep retries within the job budget.
  • Enable continue-on-error: true on pr-agent steps and add a 45-second backoff plus a second attempt when the first attempt fails.
  • Introduce a start-time stamping step and a final verdict step that classifies outcomes into success, never-ran, cancelled, timed-out, or failed-with-error; renders advisory failures as neutral or warnings; and ensures only workflow faults block the check.
.github/workflows/pr-agent.yml
Clarify and expand documentation comments in the workflow to capture the public/private reusable-workflow constraint, drift risks, and operational observations.
  • Rewrite the workflow header to explain why an inline copy is required for public repos and summarize the prior failure pattern across org repos.
  • Add detailed comments about concurrency behavior, cancellation patterns, timing measurements, and slash-command handling.
  • Add comments explaining the lack of YAML anchors for duplicated env blocks and the rationale for verdict branching over multiple failure modes, including rate limits and timeouts.
.github/workflows/pr-agent.yml

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Aug 23, 2026

Copy link
Copy Markdown

Warning

Review limit reached

Next included review available in 57 minutes.

View limit details

Limit details: You’ve used the included review currently available. Your 91 included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab.

Learn how review limits work.

Review configuration:

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: bb9f1097-f640-4fcc-b391-76f13152f09a

📥 Commits

Reviewing files that changed from the base of the PR and between ab521e0 and 6328033.

📒 Files selected for processing (1)
  • .github/workflows/pr-agent.yml

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

@codeant-ai codeant-ai Bot added the size:L This PR changes 100-499 lines, ignoring generated files label Aug 23, 2026
@macroscopeapp

macroscopeapp Bot commented Aug 23, 2026

Copy link
Copy Markdown

Approvability

Verdict: Not approved

Macroscope's review found this PR not approvable — This PR turns a previously non-running reference into a secret-bearing, write-enabled inline workflow with new retry, timeout, and slash-command behavior. Its issue-comment path does not exclude fork pull requests, leaving a concrete risk that trusted commands could run the external action against untrusted content with repository secrets.

Not approved because:

  • Credit balance exhausted. Approvability relies on correctness review in order to determine eligibility

Review your spending limits in Billing settings. You can add or adjust custom eligibility rules. Learn more.

@github-actions

github-actions Bot commented Aug 23, 2026

Copy link
Copy Markdown

PR Reviewer Guide 🔍

(Review updated until commit 98632f7)

Here are some key observations to aid the review process:

⏱️ Estimated effort to review: 3 🔵🔵🔵⚪⚪
🧪 No relevant tests
🔒 No security concerns identified
⚡ Recommended focus areas for review

Misclassified Verdict

AGENT_START is stamped once before attempt 1, so ELAPSED covers both attempts plus the 45s
backoff, yet it is compared against STEP_BUDGET_S which is the per-attempt budget (360s).
Concrete case: attempt 1 errors at 200s, sleep 45s, attempt 2 errors at 200s → ELAPSED=445 ≥ 360,
and the run reports "TIMED OUT ... a hang, NOT a rate limit" even though neither attempt hit its
step timeout. That is exactly the "confidently wrong cause" the comment above the step warns
against. Either stamp a fresh start before each attempt (and evaluate per attempt), or compare
against 2 * STEP_BUDGET_S + 45.

ELAPSED=$(( $(date +%s) - ${AGENT_START:-$(date +%s)} ))
if [ "$ELAPSED" -ge "$STEP_BUDGET_S" ]; then
  echo "::warning::pr-agent TIMED OUT — ${ELAPSED}s against a ${STEP_BUDGET_S}s per-attempt budget, so an attempt was killed by its step timeout rather than returning an error. A hang, NOT a rate limit. Rendering NEUTRAL: an advisory reviewer must not block the PR (#3128)."
  exit 0
fi
echo "::warning::pr-agent failed after 2 attempts (45s backoff, ${ELAPSED}s total — well inside the ${STEP_BUDGET_S}s budget, so it returned an error rather than hanging) — most commonly an upstream 429/rate-limit from the LLM router. Rendering NEUTRAL: an advisory reviewer must not block the PR (#3128)."
Duplicate Comments

The ret

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

CI: inline pr-agent workflow for public repos (avoid private reusable call)

🐞 Bug fix ⚙️ Configuration changes 🕐 20-40 Minutes

Grey Divider

AI Description

• Inline the pr-agent job to avoid calling a private reusable workflow from a public repo.
• Fix concurrency grouping so issue_comment runs don’t cancel in-flight pull_request reviews.
• Add retries, step budgets, and a verdict step so advisory failures don’t block PRs.
Diagram

graph TD
  A["PR / Comment event"] --> B["Workflow: pr-agent.yml"] --> C["Concurrency group"] --> D["Job: pr_agent"] --> E["PR-Agent action (Qodo Merge)"] --> F[("Wave LLM router")]
  D --> G["Verdict step (neutralize advisory failures)"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Public reusable workflow (wave-foundation-public)
  • ➕ Single source of truth shared across public repos
  • ➕ Avoids copy/paste drift while remaining callable from public repos
  • ➖ Requires ongoing governance/versioning in the public workflow repo
  • ➖ Still needs a migration plan for existing inline copies and pinning strategy
2. Composite action wrapper for PR-Agent configuration
  • ➕ Centralizes env/config and verdict logic in a versioned action
  • ➕ Can be reused across repos without workflow duplication
  • ➖ Adds packaging/release overhead for the composite action
  • ➖ Harder to debug than an inline workflow for some teams
3. Keep the inline workflow (current PR)
  • ➕ Immediately fixes the “no job created / no logs” failure mode
  • ➕ Self-contained and debuggable within the repo
  • ➕ Allows repo-specific tuning of concurrency, timeouts, and verdict behavior
  • ➖ Risk of drift vs the upstream template over time
  • ➖ Future improvements must be fanned out manually

Recommendation: The inline workflow adoption is the right immediate fix because it restores observable runs (jobs/logs/checks) and removes the forbidden dependency on a private reusable workflow. For longer-term maintainability, consider converging public repos on a public reusable workflow (or a composite action) with explicit version pinning to reduce mirror drift, but that’s a follow-up rather than a prerequisite for correctness here.

Files changed (1) +166 / -7

Other (1) +166 / -7
pr-agent.ymlInline PR-Agent lane with corrected concurrency, retries, and verdict handling +166/-7

Inline PR-Agent lane with corrected concurrency, retries, and verdict handling

• Replaces the reusable-workflow 'uses:' call (which cannot resolve from a public repo to a private repo) with a fully inlined 'pr_agent' job. Updates concurrency grouping to include 'github.event_name' to prevent issue_comment runs from cancelling pull_request reviews, and adds step-level timeouts, a backoff+retry, and a final verdict step that keeps this advisory check from blocking PRs on upstream flakes/timeouts.

.github/workflows/pr-agent.yml

@sourcery-ai sourcery-ai 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.

Hey - I've reviewed your changes and they look great!

Sourcery assessment

Needs a human reviewer. If the workflow or pinned action is wrong, it can send pull-request contents to the configured external API and use the repository token to add comments or commits, with potential API cost and changes that outlive a revert. Those effects are bounded and can generally be removed or corrected, but any information disclosure or unwanted external request cannot be undone by reverting this workflow.


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@gitar-bot

gitar-bot Bot commented Aug 23, 2026

Copy link
Copy Markdown

Note

Automatic reviews are paused because your team has used its included automatic processing for this billing period (headroom scales with your seat count). You can still comment "Gitar review" to run one anytime, and automatic reviews resume on their own by September 1. Add seats for more headroom.
Learn more

Code Review ✅ Approved

Adopts the self-contained inline PR-Agent workflow to resolve private reusable workflow failures in public repositories. No issues found.

Options

Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Compact
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

…ate reusable workflow

This repo's pr-agent.yml calls
`wave-av/wave-foundation/.github/workflows/reusable-pr-agent.yml`, and
wave-foundation is PRIVATE. GitHub does not permit a PUBLIC repository to call
a reusable workflow from a private one, so the `uses:` never resolves: the run
dies before any job is created — conclusion: failure, total_count: 0, no log,
and no check run on the head sha to read. Every PR here has carried a red check
that reports nothing, and external contributors see it.

Measured across the org 2026-08-22: 7 public repos / 176 runs / 100% failure;
9 private repos / zero failures — a clean 16/16 split on visibility alone.
Three competing hypotheses (missing OPENAI_KEY, dead pinned ref, @main vs a
pinned sha) were each tested and refuted.

THE FIX already existed and was never adopted:
wave-foundation-public/.github/workflows/pr-agent.yml is an INLINE copy of the
same lane with no reference to the private repo. This adopts it verbatim.

PROVEN BEFORE FANNING OUT. wave-certify#44 took this exact change first and its
pr_agent run returned SUCCESS on the pull_request event — a job with a real log,
where the broken form produced no job at all. 27 repos were not changed on hope.

Two prerequisites named in wave-pen#388 are cleared as of
wave-foundation-public#71: the shared concurrency key that let any bot comment
cancel a live review ~10s in (wave-pen#386) now keys on github.event_name, and
the lane carries step-level timeouts.

The job id stays `pr_agent`, so the check-run context is unchanged and no
branch protection rule needs touching.

Refs wave-pen#388

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@qodo-code-review

qodo-code-review Bot commented Aug 23, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Remediation recommended

1. Wrong timeout classification ✓ Resolved 🐞 Bug ≡ Correctness
Description
The verdict step compares total elapsed time since the job start stamp (including the 45s backoff
and retry runtime) against a per-attempt timeout budget, so a slow-but-not-timed-out second attempt
can be misreported as “TIMED OUT”. This produces confidently wrong diagnostics and makes real
failure modes harder to debug.
Code

.github/workflows/pr-agent.yml[R177-180]

+          ELAPSED=$(( $(date +%s) - ${AGENT_START:-$(date +%s)} ))
+          if [ "$ELAPSED" -ge "$STEP_BUDGET_S" ]; then
+            echo "::warning::pr-agent TIMED OUT — ${ELAPSED}s against a ${STEP_BUDGET_S}s per-attempt budget, so an attempt was killed by its step timeout rather than returning an error. A hang, NOT a rate limit. Rendering NEUTRAL: an advisory reviewer must not block the PR (#3128)."
+            exit 0
Relevance

●●● Strong

This is a deterministic timeout-classification bug; accepted CI findings prioritize accurate
failure-mode reporting.

PR-#49

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The workflow only records one start timestamp, then later treats the computed elapsed time as a
per-attempt timeout discriminator, even though it also includes the explicit 45-second backoff and
time spent in attempt 2.

.github/workflows/pr-agent.yml[75-77]
.github/workflows/pr-agent.yml[117-120]
.github/workflows/pr-agent.yml[158-183]

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 stamps `AGENT_START` once, then uses `ELAPSED` in the verdict step to decide whether an attempt hit the **per-attempt** 6-minute timeout. But `ELAPSED` includes time spent sleeping for backoff and running the retry attempt, so it can exceed 360 seconds even when neither attempt actually hit its step timeout.

### Issue Context
This leads to incorrect verdict messaging ("TIMED OUT") when the action merely failed after a long retry path.

### Fix Focus Areas
- .github/workflows/pr-agent.yml[75-77]
- .github/workflows/pr-agent.yml[117-120]
- .github/workflows/pr-agent.yml[158-183]

### Suggested fix
- Stamp attempt start time **before each attempt** (e.g., `AGENT1_START`, `AGENT2_START`) and compute elapsed per attempt.
- Alternatively, avoid time-based inference and key off a more direct signal (e.g., capture the step conclusion/outcome for timeout specifically, if available), but keep the classification accurate for the retry path.

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


2. Secrets usable on fork PRs ✓ Resolved 🐞 Bug ⛨ Security
Description
The issue_comment (/slash-command) entry condition does not restrict the target PR to non-forks,
yet the job passes OPENAI_KEY from repo secrets into the action. This contradicts the workflow’s
own “Forks skipped” comment and creates a footgun where maintainers can run the lane (with secrets)
against untrusted fork PR content.
Code

.github/workflows/pr-agent.yml[R61-64]

+        (github.event_name == 'issue_comment'
+            && github.event.issue.pull_request
+            && startsWith(github.event.comment.body, '/')
+            && contains(fromJSON('["MEMBER","OWNER","COLLABORATOR"]'), github.event.comment.author_association))
Relevance

●●● Strong

Security hardening for secret-bearing workflows is consistent with accepted CI supply-chain risk
findings.

PR-#7
PR-#49

ⓘ Recommendations generated based on similar findings in past PRs

Evidence
The issue_comment branch of the job if: checks author association and slash prefix, but has no
fork restriction, while both attempts of PR-Agent are configured with OPENAI_KEY from secrets,
meaning the workflow can run with secrets on the slash-command path.

.github/workflows/pr-agent.yml[58-69]
.github/workflows/pr-agent.yml[95-104]
.github/workflows/pr-agent.yml[130-140]

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 job-level `if:` for `issue_comment` allows `/...` commands on PRs without checking whether the PR head repo is a fork, while the action receives `OPENAI_KEY` from secrets. In a public repo this makes it easy to accidentally run a secret-bearing workflow against fork PRs.

### Issue Context
The `pull_request` path correctly checks `github.event.pull_request.head.repo.fork == false`, but the `issue_comment` path cannot use that same field because issue_comment payloads don’t include full PR data.

### Fix Focus Areas
- .github/workflows/pr-agent.yml[58-69]
- .github/workflows/pr-agent.yml[95-112]
- .github/workflows/pr-agent.yml[130-147]

### Suggested fix
Implement an explicit fork check for the slash-command path before invoking PR-Agent:
- Add a step that uses the GitHub API to fetch the PR (`issues` event provides the PR URL) and determine whether `head.repo.fork` is true.
- Gate the PR-Agent steps on that result (and emit a clear warning + exit 0 when it’s a fork).
- Update the comment to match the actual behavior once enforced.

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


Grey Divider

Context sources
✅ Compliance rules (platform): 1 rule
✅ REVIEW.md
Review mode: ⚖️ Balanced: This changes a security- and reliability-sensitive GitHub Actions workflow with retries, permissions, concurrency, timeouts, secret/API configuration, and verdict logic; despite one file, it has substantial behavioral risk but not enough independent paths to warrant extended review.

Grey Divider

Tip of the day
💡 Did you know, you can switch off images and animations for a plain-text comment

More tips ↗ | Customize Qodo ↗ | Qodo docs ↗

Grey Divider

Qodo Logo

Comment thread .github/workflows/pr-agent.yml Outdated
Comment thread .github/workflows/pr-agent.yml
@github-actions

Copy link
Copy Markdown

PR Code Suggestions ✨

No code suggestions found for the PR.

@yakimoto
yakimoto force-pushed the ci/adopt-inline-pr-agent branch from 889c2a6 to 98632f7 Compare August 23, 2026 22:39
@cursor

cursor Bot commented Aug 23, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_b7048554-675c-4387-a035-79a81b73c93c)

@github-actions

Copy link
Copy Markdown

Persistent review updated to latest commit 98632f7

@qodo-code-review

Copy link
Copy Markdown

Qodo Fixer

✅ Merged (0) · ☑ Fixed (0)

Process

  • No fixes were applied (no_fixes_applied)

…t classification

Picks up wave-foundation-public#72, which landed after this PR was opened.

The template this PR originally copied classified timeouts on TOTAL job time
(attempt 1 + 45s backoff + attempt 2) against STEP_BUDGET_S=360, a PER-ATTEMPT
budget. Two healthy-but-slow attempts (~180s each) were therefore reported as
"TIMED OUT ... A hang, NOT a rate limit", and the else-branch claimed the run
was "well inside the budget" from the same misused total. Found by qodo review
on wave-monitor#48 and confirmed against the file.

Now stamps each attempt separately and classifies on the LONGEST attempt, with
if: always() end stamps so an attempt killed BY its step timeout still records
one. Verified by dry-running both cases before the template landed.

Updated in place rather than as a follow-up PR because this has not merged yet
— cheaper, and it keeps the repo from ever carrying the defective version.

Refs wave-av/wave-pen#417, wave-av/wave-pen#388
@cursor

cursor Bot commented Aug 24, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_232e8cc9-6487-4e73-8820-c76cc6d24394)

@codeant-ai codeant-ai Bot added size:L This PR changes 100-499 lines, ignoring generated files and removed size:L This PR changes 100-499 lines, ignoring generated files labels Aug 24, 2026
…s step cap

Re-syncs this PR to the hardened template before it merges, so it cannot land
carrying the two defects it was opened with (wave-pen#418, wave-foundation-public#73).

1. Fork status is now RESOLVED, not assumed. The job-level `if:` refuses forks
   on the `pull_request` arm; it structurally cannot on `issue_comment`, because
   fork status is absent from that payload — measured, with a positive control:
   `issues/<n>.pull_request` carries exactly [diff_url, html_url, merged_at,
   patch_url, url], while `pulls/<n>.head.repo.fork` answers. A `fork gate` step
   asks the pulls endpoint and FAILS CLOSED: only a literal `false` proceeds; a
   404, a revoked token, a rate limit and `.head.repo = null` all skip.

   Scope: this lane runs no `actions/checkout`, so fork code is never fetched or
   executed and no exfiltration path existed. The durable defect was the comment
   claiming "Forks skipped (no secrets there)" — true of one arm, false of the
   other, and exactly what would mislead whoever adds a checkout step later.

2. CONFIG__AI_TIMEOUT 600 -> 300, in both env blocks. 600s inside a 360s step is
   unreachable: the runner killed the step first, so pr-agent never reached its
   own timeout and never fell back to CONFIG__FALLBACK_MODELS.

3. A latent classifier bug the gate exposed: `stamp attempt 2 end` runs under
   `if: always()`, so when attempt 2 never ran the arithmetic subtracted from
   zero and reported a 1787580408-second attempt as a confident TIMED OUT. Fixed
   at the arithmetic; the verdict also gains an explicit `skipped` branch.

The job id stays `pr_agent`, so the check-run context is unchanged and no branch
protection rule needs touching.

Refs wave-pen#418, wave-pen#417, wave-pen#388

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@cursor

cursor Bot commented Aug 24, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_88f9a8c1-4d4f-4daa-847b-e813ebf85256)

@yakimoto
yakimoto merged commit 31cf5de into main Aug 24, 2026
19 checks passed
@yakimoto
yakimoto deleted the ci/adopt-inline-pr-agent branch August 24, 2026 14:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Review effort 3/5 size:L This PR changes 100-499 lines, ignoring generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant