Skip to content
Merged
Show file tree
Hide file tree
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
32 changes: 18 additions & 14 deletions .github/agents/dependabot-pr-reviewer.agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,17 +93,19 @@ Render the review body as markdown in this order:

## Validation Signal

The agent runs AFTER the `PR Validation` orchestrator finishes (`workflow_run`
trigger). Use the deterministic CI conclusion as the canonical validation
signal. Do not invoke `uv`, `pytest`, `npm ci`, `terraform`, or `go` from the
bash tool — those binaries live on the host runner and are not visible
inside the AWF firewall sandbox.
The agent runs via `pull_request_target` and may execute BEFORE the
`PR Validation` orchestrator has completed. Treat the deterministic CI
conclusion as the canonical validation signal when it is available, and as
`pending` otherwise. Do not invoke `uv`, `pytest`, `npm ci`, `terraform`,
or `go` from the bash tool — those binaries live on the host runner and
are not visible inside the AWF firewall sandbox.

The orchestrator's overall conclusion is injected into the prompt as
`PR_VALIDATION_CONCLUSION` (one of `success`, `failure`, `cancelled`,
`neutral`, `skipped`, `timed_out`, `action_required`). Map the touched
surfaces to the per-job check runs below and read each conclusion via the
`github` MCP `pull_requests` toolset (or `GET /repos/{owner}/{repo}/commits/{sha}/check-runs`).
`PR_VALIDATION_CONCLUSION` (one of `pending`, `in_progress:<status>`,
`success`, `failure`, `cancelled`, `neutral`, `skipped`, `timed_out`,
`action_required`, or `unknown`). Map the touched surfaces to the
per-job check runs below and read each conclusion via the `github` MCP
`pull_requests` toolset (or `GET /repos/{owner}/{repo}/commits/{sha}/check-runs`).

### Surface to Check Run Map

Expand Down Expand Up @@ -165,9 +167,10 @@ review body with three parts:
violation, peer-dep conflict, breaking-changelog quote), prepend
`⚠️ Maintainer review recommended` to the top of the review body once.

If the orchestrator conclusion is unavailable (workflow not yet completed,
PR resolution failed, or check-runs API returns empty), state:
`⚠️ Deterministic CI conclusion unavailable; verdict is advisory only.`
If the orchestrator conclusion is unavailable or still in progress
(`pending`, `in_progress:*`, or `unknown`; PR resolution failed; or the
check-runs API returns empty), state:
`⚠️ Deterministic CI conclusion not yet available; verdict is advisory only.`
and keep the verdict at `COMMENT`.

### Verdict Adjustment
Expand All @@ -181,8 +184,9 @@ and keep the verdict at `COMMENT`.
check name plus its `html_url`. Do NOT skip enrichment — maintainers rely
on the advisory output to triage which package in a grouped PR caused
the failure.
* `PR_VALIDATION_CONCLUSION` is `neutral`, `skipped`, or `action_required`
→ verdict stays at `COMMENT`; body explains the inconclusive state.
* `PR_VALIDATION_CONCLUSION` is `neutral`, `skipped`, `action_required`,
`pending`, `in_progress:*`, or `unknown` → verdict stays at `COMMENT`;
body explains the inconclusive or pending state.
* The Isaac Sim ABI guard is sticky: a `numpy` 2.x bump keeps the verdict
at `COMMENT` and forces the high-risk banner regardless of CI conclusion.

Expand Down
68 changes: 39 additions & 29 deletions .github/workflows/aw-dependabot-pr-review.lock.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"9c5977b664a092da5bda82443950d104c747b4835e843f0a79d086a5a5dc8926","compiler_version":"v0.68.3","strict":true,"agent_id":"copilot"}
# gh-aw-metadata: {"schema_version":"v3","frontmatter_hash":"46234d20433a81ce7491f5c6933eb4c75977de922d188a0253fa2392eff22580","compiler_version":"v0.68.3","strict":true,"agent_id":"copilot"}
# gh-aw-manifest: {"version":1,"secrets":["COPILOT_GITHUB_TOKEN","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN"],"actions":[{"repo":"actions/checkout","sha":"de0fac2e4500dabe0009e67214ff5f5447ce83dd","version":"v6.0.2"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"373c709c69115d41ff229c7e5df9f8788daa9553","version":"v9"},{"repo":"actions/setup-go","sha":"4a3601121dd01d1626a1e23e37211e3254c1c06c","version":"v6.4.0"},{"repo":"actions/setup-node","sha":"53b83947a5a98c8d113130e565377fae1a50d02f","version":"v6.3.0"},{"repo":"actions/setup-python","sha":"a309ff8b426b58ec0e2a45f0f869d46889d02405","version":"v6.2.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"astral-sh/setup-uv","sha":"cec208311dfd045dd5311c1add060b2062131d57","version":"v8.0.0"},{"repo":"github/gh-aw-actions/setup","sha":"ba90f2186d7ad780ec640f364005fa24e797b360","version":"v0.68.3"},{"repo":"hashicorp/setup-terraform","sha":"5e8dbf3c6d9deaf4193ca7a8fb23f2ac83bb6c85","version":"5e8dbf3c6d9deaf4193ca7a8fb23f2ac83bb6c85"},{"repo":"terraform-linters/setup-tflint","sha":"b480b8fcdaa6f2c577f8e4fa799e89e756bb7c93","version":"b480b8fcdaa6f2c577f8e4fa799e89e756bb7c93"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.25.20"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.25.20"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.25.20"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.2.19"},{"image":"ghcr.io/github/github-mcp-server:v0.32.0"},{"image":"node:lts-alpine"}]}
# ___ _ _
# / _ \ | | (_)
Expand Down Expand Up @@ -59,46 +59,47 @@ name: "AW Dependabot PR Review"
"on":
# bots: # Bots processed as bot check in pre-activation job
# - dependabot[bot] # Bots processed as bot check in pre-activation job
pull_request_target:
branches:
- main
types:
- opened
- synchronize
- reopened
# roles: # Roles processed as role check in pre-activation job
# - admin # Roles processed as role check in pre-activation job
# - maintainer # Roles processed as role check in pre-activation job
# - write # Roles processed as role check in pre-activation job
workflow_run:
# zizmor: ignore[dangerous-triggers] - workflow_run trigger is secured with role and fork validation
branches:
- dependabot/**
types:
- completed
workflows:
- PR Validation

permissions: {}

concurrency:
group: "gh-aw-${{ github.workflow }}"
group: "gh-aw-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref || github.run_id }}"
cancel-in-progress: true

run-name: "AW Dependabot PR Review"

jobs:
activation:
needs: pre_activation
# zizmor: ignore[dangerous-triggers] - workflow_run trigger is secured with role and fork validation
if: >
(needs.pre_activation.outputs.activated == 'true' && (github.event.workflow_run.event == 'pull_request' &&
github.event.workflow_run.conclusion != null)) && (github.event_name != 'workflow_run' || github.event.workflow_run.repository.id == github.repository_id &&
(!(github.event.workflow_run.repository.fork)))
needs.pre_activation.outputs.activated == 'true' && (github.event.pull_request != null && startsWith(github.event.pull_request.head.ref, 'dependabot/') &&
github.event.pull_request.user.login == 'dependabot[bot]' && !github.event.pull_request.draft)
runs-on: ubuntu-slim
permissions:
actions: read
contents: read
outputs:
body: ${{ steps.sanitized.outputs.body }}
comment_id: ""
comment_repo: ""
lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }}
model: ${{ steps.generate_aw_info.outputs.model }}
secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }}
setup-trace-id: ${{ steps.setup.outputs.trace-id }}
stale_lock_file_failed: ${{ steps.check-lock-file.outputs.stale_lock_file_failed == 'true' }}
text: ${{ steps.sanitized.outputs.text }}
title: ${{ steps.sanitized.outputs.title }}
steps:
- name: Setup Scripts
id: setup
Expand Down Expand Up @@ -169,6 +170,17 @@ jobs:
setupGlobals(core, github, context, exec, io, getOctokit);
const { main } = require('${{ runner.temp }}/gh-aw/actions/check_version_updates.cjs');
await main();
- name: Compute current body text
id: sanitized
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
env:
GH_AW_ALLOWED_BOTS: "dependabot[bot]"
with:
script: |
const { setupGlobals } = require('${{ runner.temp }}/gh-aw/actions/setup_globals.cjs');
setupGlobals(core, github, context, exec, io, getOctokit);
const { main } = require('${{ runner.temp }}/gh-aw/actions/compute_text.cjs');
await main();
- name: Create prompt with built-in context
env:
GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt
Expand All @@ -185,14 +197,14 @@ jobs:
run: |
bash "${RUNNER_TEMP}/gh-aw/actions/create_prompt_first.sh"
{
cat << 'GH_AW_PROMPT_2a2f11d60a10f74e_EOF'
cat << 'GH_AW_PROMPT_5734b58a8c868ede_EOF'
<system>
GH_AW_PROMPT_2a2f11d60a10f74e_EOF
GH_AW_PROMPT_5734b58a8c868ede_EOF
cat "${RUNNER_TEMP}/gh-aw/prompts/xpia.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/temp_folder_prompt.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/markdown.md"
cat "${RUNNER_TEMP}/gh-aw/prompts/safe_outputs_prompt.md"
cat << 'GH_AW_PROMPT_2a2f11d60a10f74e_EOF'
cat << 'GH_AW_PROMPT_5734b58a8c868ede_EOF'
<safe-output-tools>
Tools: add_comment(max:2), create_pull_request_review_comment(max:5), submit_pull_request_review, missing_tool, missing_data, noop
</safe-output-tools>
Expand Down Expand Up @@ -224,13 +236,13 @@ jobs:
{{/if}}
</github-context>

GH_AW_PROMPT_2a2f11d60a10f74e_EOF
GH_AW_PROMPT_5734b58a8c868ede_EOF
cat "${RUNNER_TEMP}/gh-aw/prompts/github_mcp_tools_with_safeoutputs_prompt.md"
cat << 'GH_AW_PROMPT_2a2f11d60a10f74e_EOF'
cat << 'GH_AW_PROMPT_5734b58a8c868ede_EOF'
</system>
{{#runtime-import .github/agents/dependabot-pr-reviewer.agent.md}}
{{#runtime-import .github/workflows/aw-dependabot-pr-review.md}}
GH_AW_PROMPT_2a2f11d60a10f74e_EOF
GH_AW_PROMPT_5734b58a8c868ede_EOF
} > "$GH_AW_PROMPT"
- name: Interpolate variables and render templates
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
Expand Down Expand Up @@ -306,8 +318,6 @@ jobs:
actions: read
contents: read
pull-requests: read
concurrency:
group: "gh-aw-copilot-${{ github.workflow }}"
env:
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
GH_AW_ASSETS_ALLOWED_EXTS: ""
Expand Down Expand Up @@ -401,10 +411,10 @@ jobs:
with:
tflint_version: latest
- id: resolve-pr
name: Resolve Dependabot PR context from triggering workflow_run
name: Resolve Dependabot PR context and fetch PR Validation status
uses: actions/github-script@373c709c69115d41ff229c7e5df9f8788daa9553 # v9
with:
script: "const wr = context.payload.workflow_run;\nif (!wr) {\n core.setFailed('workflow_run payload missing');\n return;\n}\ncore.exportVariable('PR_VALIDATION_CONCLUSION', wr.conclusion || 'unknown');\ncore.exportVariable('PR_VALIDATION_RUN_URL', wr.html_url || '');\ncore.exportVariable('PR_HEAD_SHA', wr.head_sha || '');\n\nconst prs = wr.pull_requests || [];\nlet prNumber = prs.length ? prs[0].number : null;\nif (!prNumber && wr.head_branch) {\n // workflow_run may not populate pull_requests for forks; resolve via search.\n const { data: search } = await github.rest.search.issuesAndPullRequests({\n q: `repo:${context.repo.owner}/${context.repo.repo} is:pr head:${wr.head_branch} state:open`,\n per_page: 1,\n });\n if (search.items.length) prNumber = search.items[0].number;\n}\nif (!prNumber) {\n core.warning('Could not resolve a PR for this workflow_run; emitting noop.');\n core.exportVariable('PR_DEPENDABOT_SKIP_REASON', 'no-pr-resolved');\n return;\n}\nconst { data: pr } = await github.rest.pulls.get({\n owner: context.repo.owner,\n repo: context.repo.repo,\n pull_number: prNumber,\n});\nif (pr.user.login !== 'dependabot[bot]') {\n core.exportVariable('PR_DEPENDABOT_SKIP_REASON', 'not-dependabot');\n return;\n}\nif (pr.draft) {\n core.exportVariable('PR_DEPENDABOT_SKIP_REASON', 'draft');\n return;\n}\ncore.exportVariable('PR_NUMBER', String(pr.number));\ncore.exportVariable('PR_TITLE', pr.title);\ncore.exportVariable('PR_HEAD_REF', pr.head.ref);\ncore.exportVariable('PR_BASE_REF', pr.base.ref);\ncore.exportVariable('PR_AUTHOR', pr.user.login);\ncore.info(`Resolved PR #${pr.number} (${pr.title}); PR Validation conclusion: ${wr.conclusion}`);\n"
script: "const pr = context.payload.pull_request;\nif (!pr) {\n core.setFailed('pull_request payload missing');\n return;\n}\nif (pr.user.login !== 'dependabot[bot]') {\n core.exportVariable('PR_DEPENDABOT_SKIP_REASON', 'not-dependabot');\n return;\n}\nif (pr.draft) {\n core.exportVariable('PR_DEPENDABOT_SKIP_REASON', 'draft');\n return;\n}\ncore.exportVariable('PR_NUMBER', String(pr.number));\ncore.exportVariable('PR_TITLE', pr.title);\ncore.exportVariable('PR_HEAD_REF', pr.head.ref);\ncore.exportVariable('PR_BASE_REF', pr.base.ref);\ncore.exportVariable('PR_AUTHOR', pr.user.login);\ncore.exportVariable('PR_HEAD_SHA', pr.head.sha);\n\n// Look up the most recent PR Validation workflow run for this head SHA.\n// It may still be in progress when pull_request_target fires.\nlet conclusion = 'pending';\nlet runUrl = '';\ntry {\n const { data } = await github.rest.actions.listWorkflowRunsForRepo({\n owner: context.repo.owner,\n repo: context.repo.repo,\n head_sha: pr.head.sha,\n event: 'pull_request',\n per_page: 30,\n });\n const validation = (data.workflow_runs || []).find(r => r.name === 'PR Validation');\n if (validation) {\n runUrl = validation.html_url || '';\n conclusion = validation.status === 'completed'\n ? (validation.conclusion || 'unknown')\n : `in_progress:${validation.status}`;\n }\n} catch (err) {\n core.warning(`Failed to look up PR Validation run: ${err.message}`);\n}\ncore.exportVariable('PR_VALIDATION_CONCLUSION', conclusion);\ncore.exportVariable('PR_VALIDATION_RUN_URL', runUrl);\ncore.info(`Resolved PR #${pr.number} (${pr.title}); PR Validation conclusion: ${conclusion}`);\n"

- name: Configure Git credentials
env:
Expand Down Expand Up @@ -456,9 +466,9 @@ jobs:
mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs"
mkdir -p /tmp/gh-aw/safeoutputs
mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs
cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_dca91df37c117583_EOF'
cat > "${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" << 'GH_AW_SAFE_OUTPUTS_CONFIG_a6000a4bbc0dff64_EOF'
{"add_comment":{"max":2,"target":"triggering"},"create_pull_request_review_comment":{"max":5,"side":"RIGHT"},"create_report_incomplete_issue":{},"missing_data":{},"missing_tool":{},"noop":{"max":1,"report-as-issue":"true"},"report_incomplete":{},"submit_pull_request_review":{"max":1}}
GH_AW_SAFE_OUTPUTS_CONFIG_dca91df37c117583_EOF
GH_AW_SAFE_OUTPUTS_CONFIG_a6000a4bbc0dff64_EOF
- name: Write Safe Outputs Tools
env:
GH_AW_TOOLS_META_JSON: |
Expand Down Expand Up @@ -699,7 +709,7 @@ jobs:
export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network host -v /var/run/docker.sock:/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_API_KEY -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DEBUG -e MCP_GATEWAY_LOG_DIR -e GH_AW_MCP_LOG_DIR -e GH_AW_SAFE_OUTPUTS -e GH_AW_SAFE_OUTPUTS_CONFIG_PATH -e GH_AW_SAFE_OUTPUTS_TOOLS_PATH -e GH_AW_ASSETS_BRANCH -e GH_AW_ASSETS_MAX_SIZE_KB -e GH_AW_ASSETS_ALLOWED_EXTS -e DEFAULT_BRANCH -e GITHUB_MCP_SERVER_TOKEN -e GITHUB_MCP_GUARD_MIN_INTEGRITY -e GITHUB_MCP_GUARD_REPOS -e GITHUB_REPOSITORY -e GITHUB_SERVER_URL -e GITHUB_SHA -e GITHUB_WORKSPACE -e GITHUB_TOKEN -e GITHUB_RUN_ID -e GITHUB_RUN_NUMBER -e GITHUB_RUN_ATTEMPT -e GITHUB_JOB -e GITHUB_ACTION -e GITHUB_EVENT_NAME -e GITHUB_EVENT_PATH -e GITHUB_ACTOR -e GITHUB_ACTOR_ID -e GITHUB_TRIGGERING_ACTOR -e GITHUB_WORKFLOW -e GITHUB_WORKFLOW_REF -e GITHUB_WORKFLOW_SHA -e GITHUB_REF -e GITHUB_REF_NAME -e GITHUB_REF_TYPE -e GITHUB_HEAD_REF -e GITHUB_BASE_REF -e GH_AW_SAFE_OUTPUTS_PORT -e GH_AW_SAFE_OUTPUTS_API_KEY -v /tmp/gh-aw/mcp-payloads:/tmp/gh-aw/mcp-payloads:rw -v /opt:/opt:ro -v /tmp:/tmp:rw -v '"${GITHUB_WORKSPACE}"':'"${GITHUB_WORKSPACE}"':rw ghcr.io/github/gh-aw-mcpg:v0.2.19'

mkdir -p /home/runner/.copilot
cat << GH_AW_MCP_CONFIG_9807ed4ec462af68_EOF | bash "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh"
cat << GH_AW_MCP_CONFIG_658c528aa9fae3bb_EOF | bash "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.sh"
{
"mcpServers": {
"github": {
Expand Down Expand Up @@ -740,7 +750,7 @@ jobs:
"payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}"
}
}
GH_AW_MCP_CONFIG_9807ed4ec462af68_EOF
GH_AW_MCP_CONFIG_658c528aa9fae3bb_EOF
- name: Download activation artifact
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
Expand Down Expand Up @@ -1248,7 +1258,7 @@ jobs:

pre_activation:
if: >
github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion != null
github.event.pull_request != null && startsWith(github.event.pull_request.head.ref, 'dependabot/') && github.event.pull_request.user.login == 'dependabot[bot]' && !github.event.pull_request.draft
runs-on: ubuntu-slim
outputs:
activated: ${{ steps.check_membership.outputs.is_team_member == 'true' }}
Expand Down
Loading
Loading