refactor(agents): migrate dependabot AW review to workflow_run trigger#612
Conversation
- Switch trigger from pull_request_target to workflow_run gated on PR Validation completion on main - Filter on workflow_run.actor.login == 'dependabot[bot]' (replacing pull_request_target bots:/roles: allowlists) - Hydrate PR_VALIDATION_CONCLUSION from workflow_run payload and PR_VALIDATION_FAILING_CHECKS via checks.listForRef - Tighten persona verdict rubric so non-success conclusions map to COMMENT with caution banner - Replace persona check-run API walk with resolver-supplied env vars - Regenerate aw-dependabot-pr-review.lock.yml 🤖 - Generated by Copilot Co-authored-by: Copilot <copilot@github.com>
…dabot branches - change workflow_run branches from main to dependabot/** - clarify workflow execution context for Dependabot PRs 🔧 - Generated by Copilot
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Snapshot WarningsEnsure that dependencies are being submitted on PR branches and consider enabling retry-on-snapshot-warnings. See the documentation for more information and troubleshooting advice. Scanned FilesNone |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #612 +/- ##
=======================================
Coverage 88.63% 88.63%
=======================================
Files 252 252
Lines 18018 18019 +1
Branches 2492 2492
=======================================
+ Hits 15971 15972 +1
Misses 1579 1579
Partials 468 468
*This pull request uses carry forward flags. Click here to find out more.
🚀 New features to boost your workflow:
|
# Conflicts: # .github/workflows/aw-dependabot-pr-review.lock.yml
- Merge main to resolve lock file conflict - Upgrade gh-aw from v0.71.1 to v0.71.5 - Recompile aw-dependabot-pr-review workflow 🤖 - Generated by Copilot
5d10a1c to
eec026b
Compare
# Conflicts: # .github/workflows/aw-dependabot-pr-review.lock.yml
WilliamBerryiii
left a comment
There was a problem hiding this comment.
Thanks @katriendg — really nice migration. Pulling the trigger, resolver, and dispatch logic into a clean workflow_run shape makes the Dependabot review path feel a lot more durable, and the explicit no-checks.listForRef-in-resolver guard is a great touch.
A couple of thoughts that aren't blocking:
- Concurrency group scope (
.lock.yml) —gh-aw-copilot-${{ github.workflow }}serializes every Dependabot review, so a batch of ~10 PRs would stack end-to-end (~10× wall time). Scoping per-PR (e.g.,gh-aw-copilot-${{ github.workflow }}-${{ github.event.workflow_run.pull_requests[0].number || github.event.workflow_run.head_sha }}) would let independent reviews run in parallel while still serializing within a single PR. - Dead "Checkout PR branch" step (
.lock.yml) — underworkflow_run, neithergithub.event.pull_requestnorgithub.event.issue.pull_requestis set, so that step is permanently skipped. That's intentional (the resolver pulls everything from REST), but a one-line note in the source.md"Trigger Posture" section — something like "The agent runs without a working tree — all PR context comes from REST APIs in the resolver. Do not add a checkout step." — would save the next reader from trying to "fix" the missing checkout.
A few other items we looked at and don't think need action: the XPIA prompt-injection guidance reads correctly under the new trigger; the surface-to-check-run name mapping in the resolver matches the matrix names we could verify; and the > [!CAUTION] callout is the project's preferred alert syntax.
Thanks again for moving this forward!
- Disambiguate fork-PR search fallback by filtering to open Dependabot PRs with matching SHA; fail loudly on ambiguity - Paginate checks.listForRef to avoid silently missing check-runs when the CI matrix grows beyond a single page 🤖 - Generated by Copilot
…exclusions - Remove || 'unknown' fallback on run.conclusion since workflow_run types: [completed] guarantees conclusion is set - Consolidate lock file exclusions in Invoke-YamlLint.ps1 to a single post-filter; drop redundant inline exclusions 🤖 - Generated by Copilot
- Add concurrency.job-discriminator keyed on workflow_run.head_sha so independent Dependabot PR reviews run in parallel instead of serializing end-to-end through a single concurrency group 🤖 - Generated by Copilot
- Clarify that the agent runs without a working tree and the compiler-generated checkout step is permanently skipped under workflow_run 🤖 - Generated by Copilot
Thanks for your review @WilliamBerryiii - I believe I have addressed all comments, and by digging more into the docs, the For the second comment, added a note to the MD file. Ready for a second pass review. Thanks. |
Description
The
aw-dependabot-pr-reviewagentic workflow used to fire onpull_request_target, which meant the resolver step captured a snapshot ofPR Validationwhile it was stillpendingorin_progress:*, and the advisory review was posted before the orchestrator ever finished. PR #608 was the canonical example: the review correctly applied the Isaac Sim numpy 2.x ABI guard, but its CI banner quoted a stalein_progress:in_progressconclusion.This PR migrates the workflow to
workflow_runkeyed onPR Validationcompleted, reads the orchestrator's terminal conclusion straight fromcontext.payload.workflow_run.conclusion, and pre-resolves failing per-surface check-runs once in the resolver step. The persona rubric is rewritten to consume those env vars and to map every terminal conclusion explicitly -pendingandin_progress:*branches are gone because they are now unreachable.Related to #579.
Type of Change
Component(s) Affected
infrastructure/terraform/prerequisites/- Azure subscription setupinfrastructure/terraform/- Terraform infrastructureinfrastructure/setup/- OSMO control plane / Helmworkflows/- Training and evaluation workflowstraining/- Training pipelines and scriptsdocs/- DocumentationChanges
Workflow trigger and resolver
pull_request_targetwithworkflow_runonworkflows: ["PR Validation"],types: [completed],branches: ["dependabot/**"]. Thebranches:filter onworkflow_runmatches the triggering run'shead_branch(not the base), sodependabot/**is the only value that fires for Dependabot PRs — usingmainhere was the #583 regression fixed in #584. The workflow-levelif:filters onworkflow_run.event == 'pull_request',workflow_run.actor.login == 'dependabot[bot]', and a whitelist of seven terminal conclusions.on.bots: ["dependabot[bot]"]andon.roles: [admin, maintainer, write]at the top level — gh-aw'spre_activationguard checks the triggering actor againston.bots/on.rolesindependently of the workflowif:, so dropping these would resurrect the #585 / #586User permission 'none'activation block.checks: readtopermissions:for server-side check-run enumeration; existingcontents,pull-requests, andactionsscopes are unchanged.context.payload.workflow_run, prefersworkflow_run.pull_requests[0], and falls back tosearch.issuesAndPullRequestskeyed onhead_shafor the fork case. Both paths re-hydrate viapulls.getsobodyanddraftare reliable.listWorkflowRunsForRepolookup.PR_VALIDATION_CONCLUSIONnow reads directly fromrun.conclusion, which undertypes: [completed]is always one ofsuccess,failure,cancelled,timed_out,neutral,skipped, oraction_required.PR_VALIDATION_FAILING_CHECKS— JSON array of{name, html_url, conclusion}fromchecks.listForRef(ref=pr.head.sha)filtered to completed non-success/non-neutral/non-skipped runs.PR_BODY— PR body hydrated server-side so the agent does not depend on the integrity-filtered MCP read of the PR.PR_DEPENDABOT_SKIP_REASON:not-a-pr-runandpr-resolution-failed, alongside the existingnot-dependabot/draft.safe-outputs:submit-pull-request-review.target→${{ env.PR_NUMBER }}add-comment.target→${{ env.PR_NUMBER }}(wastriggering, which is undefined underworkflow_run)create-pull-request-review-comment.target→"*"Persona verdict rubric
.github/agents/dependabot-pr-reviewer.agent.md. The persona is told the workflow runs afterPR Validationreaches a terminal conclusion, and is explicitly forbidden from callingchecks.listForReforcommits/{sha}/check-runs— it readsPR_VALIDATION_FAILING_CHECKSfrom the environment instead.success+ no static concern + no sticky high-risk trigger →APPROVE-eligible, citing the orchestrator conclusion plus an emptyPR_VALIDATION_FAILING_CHECKS.failure | cancelled | timed_out | action_required→COMMENT; body MUST quote every entry fromPR_VALIDATION_FAILING_CHECKS(nameplushtml_url).neutral | skipped | unknownorPR_DEPENDABOT_SKIP_REASON == 'pr-resolution-failed'→COMMENTwith a> [!CAUTION]banner: Deterministic CI signal unavailable ({conclusion}); review is advisory only.numpy2.x bump still keeps the verdict atCOMMENTand forces the⚠️ Maintainer review recommendedbanner regardless of CI conclusion.Workflow documentation and lock files
aw-dependabot-pr-review.mdto describe theworkflow_runexecution model, the gh-aw compiler's auto-injected fork-PR exclusion andrepository.idguard, and the new env-var contract.github/gh-aw-actions/setupv0.68.3→v0.71.1in.github/aw/actions-lock.json(SHAba90f21…→239aec4…), picked up by recompilation..github/workflows/aw-dependabot-pr-review.lock.ymlvia the gh-aw compiler — diff reflects the trigger swap, the new env vars, and the setup-action SHA bump. No hand edits.Testing Performed
planreviewed (no unexpected changes)applytested in dev environmentsmoke_test_azure.py)Documentation Impact
Bug Fix Checklist
Not a bug fix — this is a refactor of an agentic-workflow trigger surface.
Checklist
Related Issues
Related to #579
Notes
min-integritytounapprovedwas rejected on prompt-injection grounds; the resolver-side hydration is the chosen mitigation.workflow_runruns in default-branch context, which means changes to the AW workflow itself cannot be exercised by a Dependabot PR — this is the secure-by-design tradeoff documented in the GitHub Security Lab "preventing pwn requests" guide and aligns with the gh-awworkflow_runrecommendation.Follow-up Tasks
PR Validationruns against the same head SHA — confirm that only the latest completed run drives the advisory review.safe-outputs.submit-pull-request-reviewandadd-commentpost successfully underworkflow_run— thetarget: ${{ env.PR_NUMBER }}overrides are the #588 / #589 mitigation; a Not in pull request context skip insafe_outputswould mean the env var did not resolve.