Codex PR Review #375
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Copyright (c) 2026, Oracle and/or its affiliates. | ||
|
Check warning on line 1 in .github/workflows/codex-pr-review.lock.yml
|
||
| # gh-aw-metadata: {"schema_version":"v4","frontmatter_hash":"0b31ee68566190840503a73c13394d2499704a5db20f7989d71e5849c135806f","body_hash":"f0a340a350fe0af340f68eb7fdaa5aec60991d08a0001183762b6a9c530e57cb","compiler_version":"v0.89.20","strict":true,"agent_id":"codex","agent_model":"gpt-6-astra","engine_versions":{"codex":"0.154.0"}} | ||
| # gh-aw-manifest: {"version":1,"secrets":["CODEX_API_KEY","COPILOT_GITHUB_TOKEN","GH_AW_DEFAULT_OTLP_ENDPOINT","GH_AW_DEFAULT_OTLP_HEADERS","GH_AW_GITHUB_MCP_SERVER_TOKEN","GH_AW_GITHUB_TOKEN","GITHUB_TOKEN","OPENAI_API_KEY"],"actions":[{"repo":"actions/checkout","sha":"3d3c42e5aac5ba805825da76410c181273ba90b1","version":"v7.0.1"},{"repo":"actions/download-artifact","sha":"3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c","version":"v8.0.1"},{"repo":"actions/github-script","sha":"3a2844b7e9c422d3c10d287c895573f7108da1b3","version":"v9.0.0"},{"repo":"actions/setup-node","sha":"820762786026740c76f36085b0efc47a31fe5020","version":"v7.0.0"},{"repo":"actions/upload-artifact","sha":"043fb46d1a93c77aae656e7c1c64a875d1fc6a0a","version":"v7.0.1"},{"repo":"github/gh-aw-actions/setup","sha":"925900cb40de9cb7652268d0cd14e00f9b7d2189","version":"v0.89.20"}],"containers":[{"image":"ghcr.io/github/gh-aw-firewall/agent:0.28.23","digest":"sha256:2c78aaba1c108e130e2d6d01e4f2cca334ea04c53e6f258913ac34173fe7e3b2","pinned_image":"ghcr.io/github/gh-aw-firewall/agent:0.28.23@sha256:2c78aaba1c108e130e2d6d01e4f2cca334ea04c53e6f258913ac34173fe7e3b2"},{"image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.28.23","digest":"sha256:c15c3d1208df10c5b588a3657be53742aa982ae0909d1eb1812525268794ca64","pinned_image":"ghcr.io/github/gh-aw-firewall/api-proxy:0.28.23@sha256:c15c3d1208df10c5b588a3657be53742aa982ae0909d1eb1812525268794ca64"},{"image":"ghcr.io/github/gh-aw-firewall/squid:0.28.23","digest":"sha256:02ffc56dd40158223064ef03a78c2d9717473c93723b4e403d455ea6f0b09ae0","pinned_image":"ghcr.io/github/gh-aw-firewall/squid:0.28.23@sha256:02ffc56dd40158223064ef03a78c2d9717473c93723b4e403d455ea6f0b09ae0"},{"image":"ghcr.io/github/gh-aw-mcpg:v0.4.25","digest":"sha256:9be0a86220e807a0ecc89e53d7453468f7a53fbc6b3d1efd2299025ffe01d086","pinned_image":"ghcr.io/github/gh-aw-mcpg:v0.4.25@sha256:9be0a86220e807a0ecc89e53d7453468f7a53fbc6b3d1efd2299025ffe01d086"},{"image":"ghcr.io/github/gh-aw-node","digest":"sha256:11c2c544876cdbaffefe0f7f1283b74838c209654b4934a78e23ed11f750490f","pinned_image":"ghcr.io/github/gh-aw-node@sha256:11c2c544876cdbaffefe0f7f1283b74838c209654b4934a78e23ed11f750490f"},{"image":"ghcr.io/github/github-mcp-server:v1.12.2","digest":"sha256:508a0857ec762b1ab1cece29193345b501fab1dd9d1228a7b617062954cecac6","pinned_image":"ghcr.io/github/github-mcp-server:v1.12.2@sha256:508a0857ec762b1ab1cece29193345b501fab1dd9d1228a7b617062954cecac6"}],"has_pull_request_target":true,"mcp_servers":[{"name":"github","tools":["get_commit","get_file_contents","get_latest_release","get_me","get_pull_request","get_pull_request_comments","get_pull_request_diff","get_pull_request_files","get_pull_request_review_comments","get_pull_request_reviews","get_pull_request_status","get_release_by_tag","get_tag","issue_read","list_branches","list_commits","list_issue_types","list_issues","list_pull_requests","list_releases","list_starred_repositories","list_tags","pull_request_read","search_code","search_issues","search_pull_requests","search_repositories"]},{"name":"safeoutputs","tools":["add_comment","create_pull_request_review_comment","missing_data","missing_tool","noop","submit_pull_request_review"]}]} | ||
| # This file was automatically generated by gh-aw (v0.89.20). DO NOT EDIT. To debug this workflow, load the skill at https://github.com/github/gh-aw/blob/main/debug.md | ||
| # | ||
| # ___ _ _ | ||
| # / _ \ | | (_) | ||
| # | |_| | __ _ ___ _ __ | |_ _ ___ | ||
| # | _ |/ _` |/ _ \ '_ \| __| |/ __| | ||
| # | | | | (_| | __/ | | | |_| | (__ | ||
| # \_| |_/\__, |\___|_| |_|\__|_|\___| | ||
| # __/ | | ||
| # _ _ |___/ | ||
| # | | | | / _| | | ||
| # | | | | ___ _ __ _ __| |_| | _____ ____ | ||
| # | |/\| |/ _ \ '__| |/ /| _| |/ _ \ \ /\ / / ___| | ||
| # \ /\ / (_) | | | | ( | | | | (_) \ V V /\__ \ | ||
| # \/ \/ \___/|_| |_|\_\|_| |_|\___/ \_/\_/ |___/ | ||
| # | ||
| # | ||
| # To update this file, edit the corresponding .md file and run: | ||
| # gh aw compile | ||
| # Not all edits will cause changes to this file. | ||
| # | ||
| # For more information: https://github.github.com/gh-aw/introduction/overview/ | ||
| # | ||
| # | ||
| # Secrets used: | ||
| # - CODEX_API_KEY | ||
| # - COPILOT_GITHUB_TOKEN | ||
| # - GH_AW_DEFAULT_OTLP_ENDPOINT | ||
| # - GH_AW_DEFAULT_OTLP_HEADERS | ||
| # - GH_AW_GITHUB_MCP_SERVER_TOKEN | ||
| # - GH_AW_GITHUB_TOKEN | ||
| # - GITHUB_TOKEN | ||
| # - OPENAI_API_KEY | ||
| # | ||
| # Custom actions used: | ||
| # - actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||
| # - actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | ||
| # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| # - actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9) | ||
| # - actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | ||
| # - actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | ||
| # - github/gh-aw-actions/setup@925900cb40de9cb7652268d0cd14e00f9b7d2189 # v0.89.20 | ||
| # | ||
| # Container images used: | ||
| # - ghcr.io/github/gh-aw-firewall/agent:0.28.23@sha256:2c78aaba1c108e130e2d6d01e4f2cca334ea04c53e6f258913ac34173fe7e3b2 | ||
| # - ghcr.io/github/gh-aw-firewall/api-proxy:0.28.23@sha256:c15c3d1208df10c5b588a3657be53742aa982ae0909d1eb1812525268794ca64 | ||
| # - ghcr.io/github/gh-aw-firewall/squid:0.28.23@sha256:02ffc56dd40158223064ef03a78c2d9717473c93723b4e403d455ea6f0b09ae0 | ||
| # - ghcr.io/github/gh-aw-mcpg:v0.4.25@sha256:9be0a86220e807a0ecc89e53d7453468f7a53fbc6b3d1efd2299025ffe01d086 | ||
| # - ghcr.io/github/gh-aw-node@sha256:11c2c544876cdbaffefe0f7f1283b74838c209654b4934a78e23ed11f750490f | ||
| # - ghcr.io/github/github-mcp-server:v1.12.2@sha256:508a0857ec762b1ab1cece29193345b501fab1dd9d1228a7b617062954cecac6 | ||
| name: "Codex PR Review" | ||
| on: | ||
| issue_comment: | ||
| types: | ||
| - created | ||
| - edited | ||
| # permissions: # Permissions applied to pre-activation job | ||
| # actions: read | ||
| # pull-requests: read | ||
| pull_request_target: | ||
| types: | ||
| - synchronize | ||
| - reopened | ||
| - ready_for_review | ||
| - labeled | ||
| # roles: all # Roles processed as role check in pre-activation job | ||
| # steps: # Steps injected into pre-activation job | ||
| # - id: oca_verification | ||
| # if: |- | ||
| # steps.check_command_position.outputs.command_position_ok == 'true' && (github.event_name != 'pull_request_target' || | ||
| # (github.event.pull_request.draft == false && | ||
| # (github.event.action != 'labeled' || github.event.label.name == 'OCA Verified'))) | ||
| # name: Check OCA verification | ||
| # uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 | ||
| # with: | ||
| # script: "core.setOutput('verified', 'false');\nconst pull_number = context.payload.pull_request?.number ??\n (context.payload.issue?.pull_request ? context.payload.issue.number : undefined);\nif (!pull_number) return;\n// Read current labels for both automatic and requested reviews.\nconst { data: pull } = await github.rest.pulls.get({\n ...context.repo,\n pull_number,\n});\ncore.setOutput('verified', pull.labels.some(label => label.name === 'OCA Verified'));\n" | ||
| # - env: | ||
| # GH_AW_RATE_LIMIT_EVENTS: pull_request_target,issue_comment | ||
| # GH_AW_RATE_LIMIT_IGNORED_ROLES: admin,maintain,write | ||
| # GH_AW_RATE_LIMIT_MAX: "3" | ||
| # GH_AW_RATE_LIMIT_WINDOW: "20" | ||
| # id: review_rate_limit | ||
| # if: steps.oca_verification.outputs.verified == 'true' | ||
| # name: Check review rate limit | ||
| # uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 | ||
| # with: | ||
| # github-token: ${{ secrets.GITHUB_TOKEN }} # GitHub token used for reactions and status comments in activation | ||
| # script: | | ||
| # const path = require('path'); | ||
| # const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| # const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| # setupGlobals(core, github, context, exec, io, getOctokit); | ||
| # const { main } = require(path.join(actionsDir, 'check_rate_limit.cjs')); | ||
| # await main(); | ||
| permissions: {} | ||
| concurrency: | ||
| cancel-in-progress: false | ||
| group: codex-pr-review-run-${{ github.run_id }} | ||
| run-name: "Codex PR Review" | ||
| env: | ||
| OTEL_EXPORTER_OTLP_ENDPOINT: ${{ secrets.GH_AW_DEFAULT_OTLP_ENDPOINT || vars.GH_AW_DEFAULT_OTLP_ENDPOINT }} | ||
| OTEL_SERVICE_NAME: gh-aw.codex-pr-review | ||
| OTEL_RESOURCE_ATTRIBUTES: 'gh-aw.workflow.name=Codex%20PR%20Review,gh-aw.repository=${{ github.repository }},gh-aw.run.id=${{ github.run_id }},github.run_id=${{ github.run_id }},gh-aw.engine.id=codex' | ||
| OTEL_EXPORTER_OTLP_HEADERS: ${{ secrets.GH_AW_DEFAULT_OTLP_HEADERS }} | ||
| GH_AW_OTLP_ENDPOINTS: '[{"url":"${{ secrets.GH_AW_DEFAULT_OTLP_ENDPOINT || vars.GH_AW_DEFAULT_OTLP_ENDPOINT }}","headers":"${{ secrets.GH_AW_DEFAULT_OTLP_HEADERS }}"}]' | ||
| GH_AW_OTLP_IF_MISSING: ignore | ||
| jobs: | ||
| activation: | ||
| needs: pre_activation | ||
| if: "needs.pre_activation.outputs.activated == 'true' && (((github.event_name != 'pull_request_target' || github.event.pull_request.draft == false) && needs.pre_activation.outputs.oca_verified == 'true' && needs.pre_activation.outputs.review_rate_limit_ok == 'true') && ((github.event_name == 'issue_comment') && (github.event_name == 'issue_comment' && (startsWith(github.event.comment.body, '/codex ') || startsWith(github.event.comment.body, '/codex\n') || startsWith(github.event.comment.body, '/codex\r') || github.event.comment.body == '/codex') && github.event.issue.pull_request != null) || !(github.event_name == 'issue_comment')))" | ||
| runs-on: ubuntu-slim | ||
| permissions: | ||
| actions: read | ||
| contents: read | ||
| issues: write | ||
| pull-requests: write | ||
| env: | ||
| GH_AW_MAX_DAILY_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_DAILY_AI_CREDITS || '5000' }} | ||
| GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }} | ||
| outputs: | ||
| body: ${{ steps.sanitized.outputs.body }} | ||
| comment_id: ${{ steps.add-comment.outputs.comment-id }} | ||
| comment_repo: ${{ steps.add-comment.outputs.comment-repo }} | ||
| comment_url: ${{ steps.add-comment.outputs.comment-url }} | ||
| daily_ai_credits_exceeded: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_exceeded == 'true' }} | ||
| daily_ai_credits_guardrail_error: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_guardrail_error || '' }} | ||
| daily_ai_credits_guardrail_status: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_guardrail_status || '' }} | ||
| daily_ai_credits_threshold: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_threshold || '' }} | ||
| daily_ai_credits_total: ${{ steps.daily-ai-credits-workflow-guardrail.outputs.daily_ai_credits_total || '' }} | ||
| engine_id: ${{ steps.generate_aw_info.outputs.engine_id }} | ||
| lockdown_check_failed: ${{ steps.generate_aw_info.outputs.lockdown_check_failed == 'true' }} | ||
| model: ${{ steps.generate_aw_info.outputs.model }} | ||
| oauth_token_check_failed: ${{ steps.check-oauth-tokens.outputs.oauth_token_check_failed == 'true' }} | ||
| secret_verification_result: ${{ steps.validate-secret.outputs.verification_result }} | ||
| setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }} | ||
| setup-span-id: ${{ steps.setup.outputs.span-id }} | ||
| setup-trace-id: ${{ steps.setup.outputs.trace-id }} | ||
| slash_command: ${{ needs.pre_activation.outputs.matched_command }} | ||
| 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 | ||
| uses: github/gh-aw-actions/setup@925900cb40de9cb7652268d0cd14e00f9b7d2189 # v0.89.20 | ||
| with: | ||
| destination: ${{ runner.temp }}/gh-aw/actions | ||
| job-name: ${{ github.job }} | ||
| trace-id: ${{ needs.pre_activation.outputs.setup-trace-id }} | ||
| parent-span-id: ${{ needs.pre_activation.outputs.setup-parent-span-id || needs.pre_activation.outputs.setup-span-id }} | ||
| safe-output-artifact-client: ${{ env.GH_AW_MAX_DAILY_AI_CREDITS != '' }} | ||
| env: | ||
| GH_AW_SETUP_WORKFLOW_NAME: "Codex PR Review" | ||
| GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/codex-pr-review.lock.yml@${{ github.ref }} | ||
| GH_AW_INFO_VERSION: "0.154.0" | ||
| GH_AW_INFO_AWF_VERSION: "v0.28.23" | ||
| GH_AW_INFO_ENGINE_ID: "codex" | ||
| - name: Mask OTLP telemetry headers | ||
| run: bash "${RUNNER_TEMP}/gh-aw/actions/mask_otlp_headers.sh" | ||
| - name: Generate agentic run info | ||
| id: generate_aw_info | ||
| env: | ||
| GH_AW_INFO_ENGINE_ID: "codex" | ||
| GH_AW_INFO_ENGINE_NAME: "Codex" | ||
| GH_AW_INFO_MODEL: "gpt-6-astra" | ||
| GH_AW_INFO_VERSION: "0.154.0" | ||
| GH_AW_INFO_AGENT_VERSION: "0.154.0" | ||
| GH_AW_INFO_CLI_VERSION: "v0.89.20" | ||
| GH_AW_INFO_WORKFLOW_NAME: "Codex PR Review" | ||
| GH_AW_INFO_EXPERIMENTAL: "false" | ||
| GH_AW_INFO_SUPPORTS_TOOLS_ALLOWLIST: "true" | ||
| GH_AW_INFO_STAGED: "false" | ||
| GH_AW_INFO_ALLOWED_DOMAINS: '["defaults"]' | ||
| GH_AW_INFO_FIREWALL_ENABLED: "true" | ||
| GH_AW_INFO_AWF_VERSION: "v0.28.23" | ||
| GH_AW_INFO_AWMG_VERSION: "" | ||
| GH_AW_INFO_FIREWALL_TYPE: "squid" | ||
| GH_AW_INFO_AGENT_RUNTIME: "" | ||
| GH_AW_COMPILED_STRICT: "true" | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| with: | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'generate_aw_info.cjs')); | ||
| await main(core, context); | ||
| - name: Restore daily AIC scan observations | ||
| id: restore-daily-aic-cache-fallback | ||
| if: ${{ env.GH_AW_MAX_DAILY_AI_CREDITS != '' }} | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| env: | ||
| GH_AW_HAS_SLASH_COMMAND: "true" | ||
| GH_AW_HAS_LABEL_COMMAND: "false" | ||
| with: | ||
| github-token: ${{ secrets.GITHUB_TOKEN }} | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'restore_aic_scan_cache.cjs')); | ||
| await main(); | ||
| - name: Check daily workflow token guardrail | ||
| id: daily-ai-credits-workflow-guardrail | ||
| if: ${{ env.GH_AW_MAX_DAILY_AI_CREDITS != '' }} | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| env: | ||
| GH_AW_WORKFLOW_NAME: "Codex PR Review" | ||
| GH_AW_WORKFLOW_ID: "codex-pr-review" | ||
| GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | ||
| GH_AW_WORKFLOW_DISPATCH_AW_CONTEXT: ${{ github.event.inputs.aw_context || '' }} | ||
| GH_AW_HAS_SLASH_COMMAND: "true" | ||
| GH_AW_HAS_LABEL_COMMAND: "false" | ||
| GH_AW_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| GH_AW_MAX_DAILY_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_DAILY_AI_CREDITS || '5000' }} | ||
| GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }} | ||
| with: | ||
| github-token: ${{ secrets.GITHUB_TOKEN }} | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'check_daily_aic_workflow_guardrail.cjs')); | ||
| await main(); | ||
| - name: Publish daily AIC scan observations | ||
| if: always() && env.GH_AW_MAX_DAILY_AI_CREDITS != '' | ||
| continue-on-error: true | ||
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | ||
| with: | ||
| name: aic-usage-scan-v2 | ||
| path: /tmp/gh-aw/agentic-workflow-usage-scan-v2.jsonl | ||
| overwrite: true | ||
| if-no-files-found: ignore | ||
| retention-days: 3 | ||
| - name: Add eyes reaction for immediate feedback | ||
| id: react | ||
| if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || github.event_name == 'pull_request' && github.event.pull_request.head.repo.id == github.repository_id | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| env: | ||
| GH_AW_REACTION: "eyes" | ||
| with: | ||
| github-token: ${{ secrets.GITHUB_TOKEN }} | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'add_reaction.cjs')); | ||
| await main(); | ||
| - name: Validate CODEX_API_KEY or OPENAI_API_KEY secret | ||
| id: validate-secret | ||
| run: bash "${RUNNER_TEMP}/gh-aw/actions/validate_multi_secret.sh" CODEX_API_KEY OPENAI_API_KEY Codex https://github.github.com/gh-aw/reference/engines/#openai-codex | ||
| env: | ||
| CODEX_API_KEY: ${{ secrets.CODEX_API_KEY }} | ||
| OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} | ||
| - name: Check for OAuth tokens | ||
| id: check-oauth-tokens | ||
| run: bash "${RUNNER_TEMP}/gh-aw/actions/check_oauth_tokens.sh" | ||
| env: | ||
| COPILOT_GITHUB_TOKEN: ${{ secrets.COPILOT_GITHUB_TOKEN }} | ||
| GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} | ||
| GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} | ||
| - name: Checkout .github and .agents folders | ||
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||
| with: | ||
| persist-credentials: false | ||
| sparse-checkout: | | ||
| .github | ||
| .agents | ||
| .claude | ||
| .codex | ||
| .gemini | ||
| .pi | ||
| sparse-checkout-cone-mode: true | ||
| fetch-depth: 1 | ||
| - name: Save agent config folders for base branch restoration | ||
| env: | ||
| GH_AW_AGENT_FOLDERS: ".agents .codex .github" | ||
| GH_AW_AGENT_FILES: "AGENTS.md" | ||
| run: | | ||
| bash "${RUNNER_TEMP}/gh-aw/actions/save_base_github_folders.sh" | ||
| - name: Check workflow lock file | ||
| id: check-lock-file | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| env: | ||
| GH_AW_WORKFLOW_FILE: "codex-pr-review.lock.yml" | ||
| GH_AW_CONTEXT_WORKFLOW_REF: "${{ github.workflow_ref }}" | ||
| with: | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'check_workflow_timestamp_api.cjs')); | ||
| await main(); | ||
| - name: Check compile-agentic version | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| env: | ||
| GH_AW_COMPILED_VERSION: "v0.89.20" | ||
| GH_AW_BLOCKED_VERSION_REPORT_AS_ISSUE: "true" | ||
| GH_AW_WORKFLOW_NAME: "Codex PR Review" | ||
| with: | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'check_version_updates.cjs')); | ||
| await main(); | ||
| - name: Compute current body text | ||
| id: sanitized | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| env: | ||
| GH_AW_ALLOWED_DOMAINS: "api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,s.symcb.com,s.symcd.com,security.ubuntu.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" | ||
| with: | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'compute_text.cjs')); | ||
| await main(); | ||
| - name: Add comment with workflow run link | ||
| id: add-comment | ||
| if: github.event_name == 'issues' || github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment' || github.event_name == 'discussion' || github.event_name == 'discussion_comment' || github.event_name == 'pull_request' && github.event.pull_request.head.repo.id == github.repository_id | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| env: | ||
| GH_AW_WORKFLOW_NAME: "Codex PR Review" | ||
| with: | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'add_workflow_run_comment.cjs')); | ||
| await main(); | ||
| - name: Log runtime features | ||
| if: ${{ contains(toJSON(vars), '"GH_AW_RUNTIME_FEATURES":') }} | ||
| run: bash "${RUNNER_TEMP}/gh-aw/actions/log_runtime_features_summary.sh" | ||
| - name: Create prompt with built-in context | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| env: | ||
| GH_AW_ACTIONS_DIR: ${{ runner.temp }}/gh-aw/actions | ||
| GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt | ||
| GH_AW_SAFE_OUTPUTS: ${{ runner.temp }}/gh-aw/safeoutputs/outputs.jsonl | ||
| GH_AW_PROMPT_CONFIG: "{\"items\":[{\"content_env\":\"GH_AW_PROMPT_CONTENT_0000\"},{\"file\":\"xpia.md\"},{\"file\":\"temp_folder_prompt.md\"},{\"file\":\"markdown.md\"},{\"file\":\"safe_outputs_prompt.md\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0001\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0002\"},{\"file\":\"mcp_cli_tools_with_safeoutputs_prompt.md\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0003\"},{\"file\":\"github_mcp_tools_with_safeoutputs_prompt.md\"},{\"file\":\"pr_context_prompt.md\",\"condition_env\":\"GH_AW_INCLUDE_PR_CONTEXT\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0004\"},{\"content_env\":\"GH_AW_PROMPT_CONTENT_0005\"}]}" | ||
| GH_AW_EXPR_1A3A194A: ${{ github.event.discussion.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'discussion' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} | ||
| GH_AW_EXPR_463A214A: ${{ github.event.pull_request.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'pull_request' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} | ||
| GH_AW_EXPR_802A9F6A: ${{ github.event.issue.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'issue' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} | ||
| GH_AW_EXPR_FF1D34CE: ${{ github.event.comment.id || fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').comment_id }} | ||
| GH_AW_GITHUB_ACTOR: ${{ github.actor }} | ||
| GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} | ||
| GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} | ||
| GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} | ||
| GH_AW_INCLUDE_PR_CONTEXT: ${{ (github.event_name == 'issue_comment' && github.event.issue.pull_request != null) || github.event_name == 'pull_request_review_comment' || github.event_name == 'pull_request_review' }} | ||
| GH_AW_PROMPT_CONTENT_0000: "<system>\n" | ||
| GH_AW_PROMPT_CONTENT_0001: "<safe-output-tools>\nTools: add_comment, create_pull_request_review_comment(max:50), submit_pull_request_review, missing_tool, missing_data, noop\n" | ||
| GH_AW_PROMPT_CONTENT_0002: "</safe-output-tools>\n" | ||
| GH_AW_PROMPT_CONTENT_0003: "<github-context>\nThe following GitHub context information is available for this workflow:\n{{#if github.actor}}\n- **actor**: __GH_AW_GITHUB_ACTOR__\n{{/if}}\n{{#if github.repository}}\n- **repository**: __GH_AW_GITHUB_REPOSITORY__\n{{/if}}\n{{#if github.workspace}}\n- **workspace**: __GH_AW_GITHUB_WORKSPACE__\n{{/if}}\n{{#if github.event.issue.number || (github.aw.context.item_type == 'issue' && github.aw.context.item_number)}}\n- **issue-number**: #__GH_AW_EXPR_802A9F6A__\n{{/if}}\n{{#if github.event.discussion.number || (github.aw.context.item_type == 'discussion' && github.aw.context.item_number)}}\n- **discussion-number**: #__GH_AW_EXPR_1A3A194A__\n{{/if}}\n{{#if github.event.pull_request.number || (github.aw.context.item_type == 'pull_request' && github.aw.context.item_number)}}\n- **pull-request-number**: #__GH_AW_EXPR_463A214A__\n{{/if}}\n{{#if github.event.comment.id || github.aw.context.comment_id}}\n- **comment-id**: __GH_AW_EXPR_FF1D34CE__\n{{/if}}\n{{#if github.run_id}}\n- **workflow-run-id**: __GH_AW_GITHUB_RUN_ID__\n{{/if}}\n- **checkouts**: The following repositories have been checked out and are available in the workspace:\n - repo `__GH_AW_GITHUB_REPOSITORY__` → `__GH_AW_GITHUB_WORKSPACE__` (cwd) [shallow clone, fetch-depth=1 (default)]\n - **Note**: The workspace path reported above may contain a separate shallow, credential-free checkout of the host repository. Use the exact checkout path shown for the repository you need. Before concluding that a branch is unavailable, confirm your working directory matches that path and inspect refs there. If the branch is not present in that checkout and is not listed as an additional fetched ref, it has NOT been checked out. For private repositories you cannot fetch it. If the branch is required and not available, exit with an error and ask the user to add it to the `fetch:` option of the `checkout:` configuration (e.g., `fetch: [\"refs/pulls/open/*\"]` for all open PR refs, or `fetch: [\"main\", \"feature/my-branch\"]` for specific branches).\n - **Warning: No git credentials are available to the agent.** Credentials are\n intentionally removed after the checkout step for security. This means any git\n operation that needs to authenticate to the remote will fail. In private repositories, that includes:\n - `git fetch`, `git pull`, `git clone`, and `git push` (direct push, not via safe-output tools)\n - Checking out or switching to a remote branch that is not already fetched\n - Deepening a shallow clone (`git fetch --unshallow`)\n - On-demand blob fetches in partial/blobless clones (operations on files not in the initial checkout)\n Do NOT attempt to configure credentials, run `git credential fill`, or modify `.gitconfig` —\n authentication will not succeed. If you encounter credential prompts or authentication errors,\n stop immediately and report the limitation rather than spending turns trying to work around it.\n</github-context>\n\n" | ||
| GH_AW_PROMPT_CONTENT_0004: "</system>\n" | ||
| GH_AW_PROMPT_CONTENT_0005: "{{#runtime-import .github/workflows/codex-pr-review.md}}\n" | ||
| with: | ||
| script: | | ||
| const { setupGlobals } = require(process.env.GH_AW_ACTIONS_DIR + '/setup_globals.cjs'); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(process.env.GH_AW_ACTIONS_DIR + '/create_prompt.cjs'); | ||
| await main(core); | ||
| - name: Interpolate variables and render templates | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| env: | ||
| GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt | ||
| GH_AW_ENGINE_ID: "codex" | ||
| with: | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'interpolate_prompt.cjs')); | ||
| await main(); | ||
| - name: Substitute placeholders | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| env: | ||
| GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt | ||
| GH_AW_EXPR_1A3A194A: ${{ github.event.discussion.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'discussion' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} | ||
| GH_AW_EXPR_463A214A: ${{ github.event.pull_request.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'pull_request' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} | ||
| GH_AW_EXPR_802A9F6A: ${{ github.event.issue.number || (fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_type == 'issue' && fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').item_number) }} | ||
| GH_AW_EXPR_FF1D34CE: ${{ github.event.comment.id || fromJSON(github.event.inputs.aw_context || github.event.client_payload.aw_context || '{}').comment_id }} | ||
| GH_AW_GITHUB_ACTOR: ${{ github.actor }} | ||
| GH_AW_GITHUB_REPOSITORY: ${{ github.repository }} | ||
| GH_AW_GITHUB_RUN_ID: ${{ github.run_id }} | ||
| GH_AW_GITHUB_WORKSPACE: ${{ github.workspace }} | ||
| GH_AW_INCLUDE_PR_CONTEXT: ${{ (github.event_name == 'issue_comment' && github.event.issue.pull_request != null) || github.event_name == 'pull_request_review_comment' || github.event_name == 'pull_request_review' }} | ||
| GH_AW_MCP_CLI_SERVERS_LIST: '- `safeoutputs` — run `safeoutputs --help` to see available tools' | ||
| GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: ${{ needs.pre_activation.outputs.activated }} | ||
| GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_MATCHED_COMMAND: ${{ needs.pre_activation.outputs.matched_command }} | ||
| with: | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const substitutePlaceholders = require(path.join(actionsDir, 'substitute_placeholders.cjs')); | ||
| // Call the substitution function | ||
| return await substitutePlaceholders({ | ||
| file: process.env.GH_AW_PROMPT, | ||
| substitutions: { | ||
| GH_AW_EXPR_1A3A194A: process.env.GH_AW_EXPR_1A3A194A, | ||
| GH_AW_EXPR_463A214A: process.env.GH_AW_EXPR_463A214A, | ||
| GH_AW_EXPR_802A9F6A: process.env.GH_AW_EXPR_802A9F6A, | ||
| GH_AW_EXPR_FF1D34CE: process.env.GH_AW_EXPR_FF1D34CE, | ||
| GH_AW_GITHUB_ACTOR: process.env.GH_AW_GITHUB_ACTOR, | ||
| GH_AW_GITHUB_REPOSITORY: process.env.GH_AW_GITHUB_REPOSITORY, | ||
| GH_AW_GITHUB_RUN_ID: process.env.GH_AW_GITHUB_RUN_ID, | ||
| GH_AW_GITHUB_WORKSPACE: process.env.GH_AW_GITHUB_WORKSPACE, | ||
| GH_AW_INCLUDE_PR_CONTEXT: process.env.GH_AW_INCLUDE_PR_CONTEXT, | ||
| GH_AW_MCP_CLI_SERVERS_LIST: process.env.GH_AW_MCP_CLI_SERVERS_LIST, | ||
| GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_ACTIVATED, | ||
| GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_MATCHED_COMMAND: process.env.GH_AW_NEEDS_PRE_ACTIVATION_OUTPUTS_MATCHED_COMMAND | ||
| } | ||
| }); | ||
| - name: Validate prompt placeholders | ||
| env: | ||
| GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt | ||
| run: | | ||
| bash "${RUNNER_TEMP}/gh-aw/actions/validate_prompt_placeholders.sh" | ||
| - name: Print prompt | ||
| env: | ||
| GH_AW_PROMPT: ${{ runner.temp }}/gh-aw/aw-prompts/prompt.txt | ||
| run: | | ||
| bash "${RUNNER_TEMP}/gh-aw/actions/print_prompt_summary.sh" | ||
| - name: Upload info artifact | ||
| if: success() || failure() | ||
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | ||
| with: | ||
| name: info | ||
| path: /tmp/gh-aw/aw_info.json | ||
| if-no-files-found: ignore | ||
| - name: Stage prompt files for artifact upload | ||
| run: | | ||
| mkdir -p /tmp/gh-aw/aw-prompts | ||
| cp -a "${RUNNER_TEMP}/gh-aw/aw-prompts/." /tmp/gh-aw/aw-prompts/ | ||
| - name: Upload activation artifact | ||
| if: success() || failure() | ||
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | ||
| with: | ||
| name: activation | ||
| include-hidden-files: true | ||
| path: | | ||
| /tmp/gh-aw/aw_info.json | ||
| /tmp/gh-aw/models.json | ||
| /tmp/gh-aw/aw-prompts/prompt.txt | ||
| /tmp/gh-aw/aw-prompts/prompt-template.txt | ||
| /tmp/gh-aw/aw-prompts/prompt-import-tree.json | ||
| /tmp/gh-aw/github_rate_limits.jsonl | ||
| /tmp/gh-aw/base | ||
| /tmp/gh-aw/.codex/agents | ||
| /tmp/gh-aw/.codex/skills | ||
| if-no-files-found: ignore | ||
| retention-days: 1 | ||
| agent: | ||
| needs: activation | ||
| if: needs.activation.outputs.daily_ai_credits_exceeded != 'true' | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
| pull-requests: read | ||
| concurrency: | ||
| group: "codex-pr-review-agent-${{ github.event.pull_request.number || github.event.issue.number || github.run_id }}" | ||
| cancel-in-progress: true | ||
| timeout-minutes: 60 | ||
| env: | ||
| DEFAULT_BRANCH: ${{ github.event.repository.default_branch }} | ||
| GH_AW_ASSETS_ALLOWED_EXTS: "" | ||
| GH_AW_ASSETS_BRANCH: "" | ||
| GH_AW_ASSETS_MAX_SIZE_KB: 0 | ||
| GH_AW_ENGINE_VERSION: "0.154.0" | ||
| GH_AW_MCP_LOG_DIR: /tmp/gh-aw/mcp-logs/safeoutputs | ||
| GH_AW_PR_HEAD_BASE_BRANCH: "" | ||
| GH_AW_PR_HEAD_BASE_PR_NUMBER: "" | ||
| GH_AW_PR_HEAD_BASE_REF: "" | ||
| GH_AW_PR_HEAD_BASE_REPO: "" | ||
| GH_AW_PR_HEAD_BASE_SHA: "" | ||
| GH_AW_PR_HEAD_REPO: "" | ||
| GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }} | ||
| GH_AW_WORKFLOW_ID_SANITIZED: codexprreview | ||
| outputs: | ||
| agentic_engine_timeout: ${{ steps.detect-agent-errors.outputs.agentic_engine_timeout || 'false' }} | ||
| ai_credits_rate_limit_error: ${{ steps.parse-mcp-gateway.outputs.ai_credits_rate_limit_error || 'false' }} | ||
| aic: ${{ steps.parse-token-usage.outputs.aic }} | ||
| ambient_context: ${{ steps.parse-token-usage.outputs.ambient_context }} | ||
| has_patch: ${{ steps.collect_output.outputs.has_patch }} | ||
| http_400_response_error: ${{ steps.detect-agent-errors.outputs.http_400_response_error || 'false' }} | ||
| inference_access_error: ${{ steps.detect-agent-errors.outputs.inference_access_error || 'false' }} | ||
| invocation_cap_exceeded: ${{ steps.detect-agent-errors.outputs.invocation_cap_exceeded || 'false' }} | ||
| max_cache_misses_exceeded: ${{ steps.detect-agent-errors.outputs.max_cache_misses_exceeded || 'false' }} | ||
| mcp_policy_error: ${{ steps.detect-agent-errors.outputs.mcp_policy_error || 'false' }} | ||
| missing_model_pricing_error: ${{ steps.detect-agent-errors.outputs.missing_model_pricing_error || 'false' }} | ||
| missing_model_pricing_model_name: ${{ steps.detect-agent-errors.outputs.missing_model_pricing_model_name || '' }} | ||
| model: ${{ needs.activation.outputs.model }} | ||
| model_not_supported_error: ${{ steps.detect-agent-errors.outputs.model_not_supported_error || 'false' }} | ||
| output: ${{ steps.collect_output.outputs.output }} | ||
| output_types: ${{ steps.collect_output.outputs.output_types }} | ||
| setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }} | ||
| setup-span-id: ${{ steps.setup.outputs.span-id }} | ||
| setup-trace-id: ${{ steps.setup.outputs.trace-id }} | ||
| shell_expansion_guard_rejected: ${{ steps.detect-agent-errors.outputs.shell_expansion_guard_rejected || 'false' }} | ||
| unknown_model_ai_credits: ${{ steps.parse-mcp-gateway.outputs.unknown_model_ai_credits || 'false' }} | ||
| steps: | ||
| - name: Setup Scripts | ||
| id: setup | ||
| uses: github/gh-aw-actions/setup@925900cb40de9cb7652268d0cd14e00f9b7d2189 # v0.89.20 | ||
| with: | ||
| destination: ${{ runner.temp }}/gh-aw/actions | ||
| job-name: ${{ github.job }} | ||
| trace-id: ${{ needs.activation.outputs.setup-trace-id }} | ||
| parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} | ||
| env: | ||
| GH_AW_SETUP_WORKFLOW_NAME: "Codex PR Review" | ||
| GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/codex-pr-review.lock.yml@${{ github.ref }} | ||
| GH_AW_INFO_VERSION: "0.154.0" | ||
| GH_AW_INFO_AWF_VERSION: "v0.28.23" | ||
| GH_AW_INFO_ENGINE_ID: "codex" | ||
| - name: Set runtime paths | ||
| id: set-runtime-paths | ||
| env: | ||
| GH_AW_RUNNER_TOOL_CACHE: ${{ runner.tool_cache }} | ||
| run: | # zizmor: ignore[github-env] - runner.tool_cache is set by GitHub Actions, not user input. | ||
| if [ -z "${RUNNER_TOOL_CACHE:-}" ]; then | ||
| echo "RUNNER_TOOL_CACHE=${GH_AW_RUNNER_TOOL_CACHE}" >> "$GITHUB_ENV" | ||
| fi | ||
| { | ||
| echo "GH_AW_SAFE_OUTPUTS=${RUNNER_TEMP}/gh-aw/safeoutputs/outputs.jsonl" | ||
| echo "GH_AW_SAFE_OUTPUTS_CONFIG_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/config.json" | ||
| echo "GH_AW_SAFE_OUTPUTS_TOOLS_PATH=${RUNNER_TEMP}/gh-aw/safeoutputs/tools.json" | ||
| } >> "$GITHUB_OUTPUT" | ||
| - name: Mask OTLP telemetry headers | ||
| run: bash "${RUNNER_TEMP}/gh-aw/actions/mask_otlp_headers.sh" | ||
| - name: Check OTLP telemetry configuration | ||
| run: bash "${RUNNER_TEMP}/gh-aw/actions/check_otlp_default_credentials.sh" | ||
| - name: Checkout repository | ||
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||
| with: | ||
| persist-credentials: false | ||
| ref: ${{ github.event.pull_request.base.sha }} | ||
| - name: Initialize agent execution evidence | ||
| run: | | ||
| mkdir -p "/tmp/gh-aw" | ||
| evidence_tmp="/tmp/gh-aw/agent_execution.json.tmp" | ||
| printf '{"version":1,"component":"agent","run_id":%s,"run_attempt":%s,"state":"not_started"}\n' "$GITHUB_RUN_ID" "$GITHUB_RUN_ATTEMPT" > "$evidence_tmp" | ||
| mv "$evidence_tmp" "/tmp/gh-aw/agent_execution.json" | ||
| - name: Create gh-aw temp directory | ||
| run: bash "${RUNNER_TEMP}/gh-aw/actions/create_gh_aw_tmp_dir.sh" | ||
| - name: Configure gh CLI for GitHub Enterprise | ||
| run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_gh_for_ghe.sh" | ||
| env: | ||
| GH_TOKEN: ${{ github.token }} | ||
| - name: Start DIFC Proxy | ||
| env: | ||
| GH_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | ||
| GITHUB_SERVER_URL: ${{ github.server_url }} | ||
| GITHUB_API_URL: ${{ github.api_url }} | ||
| GH_HOST: ${{ env.GH_HOST }} | ||
| GITHUB_HOST: ${{ env.GITHUB_HOST }} | ||
| GITHUB_ENTERPRISE_HOST: ${{ env.GITHUB_ENTERPRISE_HOST }} | ||
| GITHUB_GRAPHQL_URL: ${{ env.GITHUB_GRAPHQL_URL }} | ||
| GITHUB_COPILOT_BASE_URL: ${{ env.GITHUB_COPILOT_BASE_URL }} | ||
| GH_AW_NETWORK_ISOLATION: 'true' | ||
| DIFC_PROXY_POLICY: '{"allow-only":{"min-integrity":"approved","repos":"all"}}' | ||
| DIFC_PROXY_IMAGE: 'ghcr.io/github/gh-aw-mcpg:v0.4.25' | ||
| run: | | ||
| bash "${RUNNER_TEMP}/gh-aw/actions/start_difc_proxy.sh" | ||
| - name: Download activation artifact | ||
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | ||
| with: | ||
| name: activation | ||
| path: /tmp/gh-aw | ||
| - name: Fetch and verify PR source | ||
| run: |- | ||
| [[ "$PR_NUMBER" =~ ^[0-9]+$ ]] || exit 1 | ||
| header="AUTHORIZATION: basic $(printf 'x-access-token:%s' "$GH_TOKEN" | base64 | tr -d '\n')" | ||
| echo "::add-mask::$header" | ||
| export GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=http.extraheader GIT_CONFIG_VALUE_0="$header" | ||
| git fetch --no-tags --depth=1 origin "+refs/pull/${PR_NUMBER}/head:refs/review/head" | ||
| remote_head=$(git ls-remote origin "refs/pull/${PR_NUMBER}/head" | cut -f1) | ||
| if [[ "$(git rev-parse refs/review/head)" != "$remote_head" ]]; then | ||
| echo "::error::PR head changed during setup; rerun the review." | ||
| exit 1 | ||
| fi | ||
| env: | ||
| GH_HOST: ${{ env.GH_HOST || 'github.com' }} | ||
| GH_REPO: ${{ github.repository }} | ||
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| GITHUB_API_URL: https://localhost:18443/api/v3 | ||
| GITHUB_GRAPHQL_URL: https://localhost:18443/api/graphql | ||
| NODE_EXTRA_CA_CERTS: /tmp/gh-aw/proxy-logs/proxy-tls/ca.crt | ||
| PR_NUMBER: ${{ github.event.pull_request.number || github.event.issue.number }} | ||
| - name: Configure Git credentials | ||
| env: | ||
| GITHUB_REPOSITORY: ${{ github.repository }} | ||
| GITHUB_SERVER_URL: ${{ github.server_url }} | ||
| GITHUB_TOKEN: ${{ github.token }} | ||
| run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_git_credentials.sh" | ||
| - name: Setup Node.js | ||
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | ||
| with: | ||
| node-version: '24' | ||
| package-manager-cache: false | ||
| - name: Install Codex CLI | ||
| run: npm install --ignore-scripts -g @openai/codex@0.154.0 | ||
| - name: Install AWF binary | ||
| run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.28.23 --rootless | ||
| - name: Determine automatic lockdown mode for GitHub MCP Server | ||
| id: determine-automatic-lockdown | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 (source v9) | ||
| env: | ||
| GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} | ||
| GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} | ||
| GH_AW_GITHUB_MIN_INTEGRITY: 'approved' | ||
| with: | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const determineAutomaticLockdown = require(path.join(actionsDir, 'determine_automatic_lockdown.cjs')); | ||
| await determineAutomaticLockdown(github, context, core); | ||
| - name: Parse integrity filter lists | ||
| id: parse-guard-vars | ||
| env: | ||
| GH_AW_BLOCKED_USERS_VAR: ${{ vars.GH_AW_GITHUB_BLOCKED_USERS || '' }} | ||
| GH_AW_TRUSTED_USERS_VAR: ${{ vars.GH_AW_GITHUB_TRUSTED_USERS || '' }} | ||
| GH_AW_APPROVAL_LABELS_EXTRA: OCA Verified | ||
| GH_AW_APPROVAL_LABELS_VAR: ${{ vars.GH_AW_GITHUB_APPROVAL_LABELS || '' }} | ||
| run: bash "${RUNNER_TEMP}/gh-aw/actions/parse_guard_list.sh" | ||
| - name: Stop DIFC Proxy | ||
| if: always() | ||
| continue-on-error: true | ||
| run: bash "${RUNNER_TEMP}/gh-aw/actions/stop_difc_proxy.sh" | ||
| - name: Restore inline sub-agents from activation artifact | ||
| env: | ||
| GH_AW_SUB_AGENT_DIR: ".codex/agents" | ||
| GH_AW_SUB_AGENT_EXT: ".md" | ||
| run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_sub_agents.sh" | ||
| - name: Restore inline skills from activation artifact | ||
| env: | ||
| GH_AW_SKILL_DIR: ".codex/skills" | ||
| run: bash "${RUNNER_TEMP}/gh-aw/actions/restore_inline_skills.sh" | ||
| - name: Download container images | ||
| run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.28.23@sha256:2c78aaba1c108e130e2d6d01e4f2cca334ea04c53e6f258913ac34173fe7e3b2 ghcr.io/github/gh-aw-firewall/api-proxy:0.28.23@sha256:c15c3d1208df10c5b588a3657be53742aa982ae0909d1eb1812525268794ca64 ghcr.io/github/gh-aw-firewall/squid:0.28.23@sha256:02ffc56dd40158223064ef03a78c2d9717473c93723b4e403d455ea6f0b09ae0 ghcr.io/github/gh-aw-mcpg:v0.4.25@sha256:9be0a86220e807a0ecc89e53d7453468f7a53fbc6b3d1efd2299025ffe01d086 ghcr.io/github/gh-aw-node@sha256:11c2c544876cdbaffefe0f7f1283b74838c209654b4934a78e23ed11f750490f ghcr.io/github/github-mcp-server:v1.12.2@sha256:508a0857ec762b1ab1cece29193345b501fab1dd9d1228a7b617062954cecac6 | ||
| - name: Prepare Safe Outputs Directories | ||
| run: | | ||
| mkdir -p "${RUNNER_TEMP}/gh-aw/safeoutputs" | ||
| mkdir -p /tmp/gh-aw/safeoutputs | ||
| mkdir -p /tmp/gh-aw/mcp-logs/safeoutputs | ||
| - name: Generate Safe Outputs Config | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| env: | ||
| GH_AW_FILE_ROOT: "${{ runner.temp }}/gh-aw" | ||
| GH_AW_FILE_CONFIG: "{\"files\":[{\"path\":\"safeoutputs/config.json\",\"content_env\":\"GH_AW_SAFE_OUTPUTS_CONFIG\"}]}" | ||
| GH_AW_SAFE_OUTPUTS_CONFIG: "{\"add_comment\":{\"max\":1},\"create_pull_request_review_comment\":{\"max\":50,\"side\":\"RIGHT\"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"false\"},\"report_incomplete\":{},\"submit_pull_request_review\":{\"allowed_events\":[\"COMMENT\"],\"max\":1}}" | ||
| with: | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'create_files.cjs')); | ||
| await main(); | ||
| - name: Generate Safe Outputs Tools | ||
| env: | ||
| GH_AW_TOOLS_META_JSON: | | ||
| { | ||
| "description_suffixes": { | ||
| "add_comment": " CONSTRAINTS: Maximum 1 comment(s) can be added. Supports reply_to_id for discussion threading.", | ||
| "create_pull_request_review_comment": " CONSTRAINTS: Maximum 50 review comment(s) can be created. Comments will be on the RIGHT side of the diff.", | ||
| "submit_pull_request_review": " CONSTRAINTS: Maximum 1 review(s) can be submitted." | ||
| }, | ||
| "repo_params": {}, | ||
| "dynamic_tools": [], | ||
| "property_injections": { | ||
| "submit_pull_request_review": { | ||
| "event": { | ||
| "description": "Review decision. Restricted by allowed-events configuration to: COMMENT.", | ||
| "enum": [ | ||
| "COMMENT" | ||
| ], | ||
| "type": "string", | ||
| "x-synonyms": [ | ||
| "action" | ||
| ] | ||
| } | ||
| } | ||
| } | ||
| } | ||
| GH_AW_VALIDATION_JSON: | | ||
| { | ||
| "add_comment": { | ||
| "defaultMax": 1, | ||
| "fields": { | ||
| "body": { | ||
| "required": true, | ||
| "type": "string", | ||
| "sanitize": true, | ||
| "maxLength": 65000 | ||
| }, | ||
| "comment_id": { | ||
| "optionalPositiveInteger": true | ||
| }, | ||
| "item_number": { | ||
| "issueOrPRNumber": true | ||
| }, | ||
| "pr": { | ||
| "issueOrPRNumber": true | ||
| }, | ||
| "pr_number": { | ||
| "issueOrPRNumber": true | ||
| }, | ||
| "reply_to_id": { | ||
| "type": "string", | ||
| "maxLength": 256 | ||
| }, | ||
| "repo": { | ||
| "type": "string", | ||
| "maxLength": 256 | ||
| }, | ||
| "target": { | ||
| "type": "string", | ||
| "enum": [ | ||
| "status" | ||
| ] | ||
| }, | ||
| "temporary_id": { | ||
| "type": "string", | ||
| "pattern": "^#?aw_[A-Za-z0-9_]{3,12}$" | ||
| } | ||
| } | ||
| }, | ||
| "create_pull_request_review_comment": { | ||
| "defaultMax": 1, | ||
| "fields": { | ||
| "body": { | ||
| "required": true, | ||
| "type": "string", | ||
| "sanitize": true, | ||
| "maxLength": 65000 | ||
| }, | ||
| "line": { | ||
| "required": true, | ||
| "positiveInteger": true | ||
| }, | ||
| "path": { | ||
| "required": true, | ||
| "type": "string" | ||
| }, | ||
| "pull_request_number": { | ||
| "optionalPositiveInteger": true | ||
| }, | ||
| "repo": { | ||
| "type": "string", | ||
| "maxLength": 256 | ||
| }, | ||
| "side": { | ||
| "type": "string", | ||
| "enum": [ | ||
| "LEFT", | ||
| "RIGHT" | ||
| ] | ||
| }, | ||
| "start_line": { | ||
| "optionalPositiveInteger": true | ||
| } | ||
| }, | ||
| "customValidation": "startLineLessOrEqualLine" | ||
| }, | ||
| "missing_data": { | ||
| "defaultMax": 20, | ||
| "fields": { | ||
| "alternatives": { | ||
| "type": "string", | ||
| "sanitize": true, | ||
| "maxLength": 256 | ||
| }, | ||
| "context": { | ||
| "type": "string", | ||
| "sanitize": true, | ||
| "maxLength": 256 | ||
| }, | ||
| "data_type": { | ||
| "type": "string", | ||
| "sanitize": true, | ||
| "maxLength": 128 | ||
| }, | ||
| "reason": { | ||
| "type": "string", | ||
| "sanitize": true, | ||
| "maxLength": 256 | ||
| } | ||
| } | ||
| }, | ||
| "missing_tool": { | ||
| "defaultMax": 20, | ||
| "fields": { | ||
| "alternatives": { | ||
| "type": "string", | ||
| "sanitize": true, | ||
| "maxLength": 512 | ||
| }, | ||
| "reason": { | ||
| "required": true, | ||
| "type": "string", | ||
| "sanitize": true, | ||
| "maxLength": 256 | ||
| }, | ||
| "tool": { | ||
| "type": "string", | ||
| "sanitize": true, | ||
| "maxLength": 128 | ||
| } | ||
| } | ||
| }, | ||
| "noop": { | ||
| "defaultMax": 1, | ||
| "fields": { | ||
| "message": { | ||
| "required": true, | ||
| "type": "string", | ||
| "sanitize": true, | ||
| "maxLength": 65000 | ||
| } | ||
| } | ||
| }, | ||
| "report_incomplete": { | ||
| "defaultMax": 5, | ||
| "fields": { | ||
| "details": { | ||
| "type": "string", | ||
| "sanitize": true, | ||
| "maxLength": 65000 | ||
| }, | ||
| "reason": { | ||
| "required": true, | ||
| "type": "string", | ||
| "sanitize": true, | ||
| "maxLength": 1024 | ||
| } | ||
| } | ||
| }, | ||
| "submit_pull_request_review": { | ||
| "defaultMax": 1, | ||
| "fields": { | ||
| "body": { | ||
| "type": "string", | ||
| "sanitize": true, | ||
| "maxLength": 65000 | ||
| }, | ||
| "event": { | ||
| "type": "string", | ||
| "enum": [ | ||
| "APPROVE", | ||
| "REQUEST_CHANGES", | ||
| "COMMENT" | ||
| ] | ||
| }, | ||
| "pull_request_number": { | ||
| "issueOrPRNumber": true | ||
| }, | ||
| "repo": { | ||
| "type": "string", | ||
| "maxLength": 256 | ||
| } | ||
| } | ||
| } | ||
| } | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| with: | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'generate_safe_outputs_tools.cjs')); | ||
| await main(); | ||
| - name: Start MCP Gateway | ||
| id: start-mcp-gateway | ||
| env: | ||
| CODEX_HOME: /tmp/gh-aw/mcp-config | ||
| GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST: ${{ vars.GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST || 'true' }} | ||
| GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} | ||
| GH_AW_SAFE_OUTPUTS_CONFIG_PATH: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS_CONFIG_PATH }} | ||
| GH_AW_SAFE_OUTPUTS_TOOLS_PATH: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS_TOOLS_PATH }} | ||
| GH_AW_SINK_VISIBILITY: ${{ steps.determine-automatic-lockdown.outputs.visibility }} | ||
| GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN || secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| set -eo pipefail | ||
| mkdir -p "${RUNNER_TEMP}/gh-aw/mcp-config" | ||
| if [ -n "${GITHUB_EVENT_PATH:-}" ] && [ -r "${GITHUB_EVENT_PATH}" ]; then | ||
| GH_AW_SAFEOUTPUTS_EVENT_PATH="${RUNNER_TEMP}/gh-aw/safeoutputs/github_event.json" | ||
| cp "${GITHUB_EVENT_PATH}" "${GH_AW_SAFEOUTPUTS_EVENT_PATH}" | ||
| export GITHUB_EVENT_PATH="${GH_AW_SAFEOUTPUTS_EVENT_PATH}" | ||
| fi | ||
| # Export gateway environment variables for MCP config and gateway script | ||
| export MCP_GATEWAY_PORT="8080" | ||
| export MCP_GATEWAY_DOMAIN="awmg-mcpg" | ||
| export MCP_GATEWAY_HOST_DOMAIN="localhost" | ||
| MCP_GATEWAY_AGENT_ID=$(openssl rand -base64 45 | tr -d '/+=') | ||
| echo "::add-mask::${MCP_GATEWAY_AGENT_ID}" | ||
| export MCP_GATEWAY_AGENT_ID | ||
| export MCP_GATEWAY_PAYLOAD_DIR="/tmp/gh-aw/mcp-payloads" | ||
| mkdir -p "${MCP_GATEWAY_PAYLOAD_DIR}" | ||
| export MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD="524288" | ||
| export MCP_GATEWAY_ALLOWED_MOUNT_ROOTS="${GITHUB_WORKSPACE}:rw,${RUNNER_TEMP}/gh-aw:ro,${RUNNER_TEMP}/gh-aw/safeoutputs:rw,/opt:ro,/tmp:rw,/usr/bin/gh:ro" | ||
| export GH_AW_PR_HEAD_BASE_BRANCH="${GH_AW_PR_HEAD_BASE_BRANCH:-}" | ||
| export GH_AW_PR_HEAD_BASE_SHA="${GH_AW_PR_HEAD_BASE_SHA:-}" | ||
| export GH_AW_PR_HEAD_BASE_REPO="${GH_AW_PR_HEAD_BASE_REPO:-}" | ||
| export GH_AW_PR_HEAD_BASE_PR_NUMBER="${GH_AW_PR_HEAD_BASE_PR_NUMBER:-}" | ||
| export GH_AW_PR_HEAD_BASE_REF="${GH_AW_PR_HEAD_BASE_REF:-}" | ||
| export GH_AW_PR_HEAD_REPO="${GH_AW_PR_HEAD_REPO:-}" | ||
| export DEBUG="*" | ||
| export GH_AW_ENGINE="codex" | ||
| MCP_GATEWAY_UID=$(id -u 2>/dev/null || echo '0') | ||
| MCP_GATEWAY_GID=$(id -g 2>/dev/null || echo '0') | ||
| source "${RUNNER_TEMP}/gh-aw/actions/resolve_docker_socket_gid.sh" | ||
| export MCP_GATEWAY_DOCKER_COMMAND='docker run -i --rm --network bridge -p 127.0.0.1:'"${MCP_GATEWAY_PORT}"':'"${MCP_GATEWAY_PORT}"' --name awmg-mcpg --add-host host.docker.internal:host-gateway --user '"${MCP_GATEWAY_UID}"':'"${MCP_GATEWAY_GID}"' --group-add '"${DOCKER_SOCK_GID}"' -v '"${DOCKER_SOCK_PATH}"':/var/run/docker.sock -e MCP_GATEWAY_PORT -e MCP_GATEWAY_DOMAIN -e MCP_GATEWAY_AGENT_ID -e MCP_GATEWAY_PAYLOAD_DIR -e MCP_GATEWAY_PAYLOAD_SIZE_THRESHOLD -e DOCKER_HOST=unix:///var/run/docker.sock -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_PR_HEAD_BASE_BRANCH -e GH_AW_PR_HEAD_BASE_SHA -e GH_AW_PR_HEAD_BASE_REPO -e GH_AW_PR_HEAD_BASE_PR_NUMBER -e GH_AW_PR_HEAD_BASE_REF -e GH_AW_PR_HEAD_REPO -e GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST -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 GH_AW_SINK_VISIBILITY -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 RUNNER_TEMP -e RUNNER_TOOL_CACHE -e MCP_GATEWAY_ALLOWED_MOUNT_ROOTS -e GITHUB_AW_OTEL_TRACE_ID -e GITHUB_AW_OTEL_PARENT_SPAN_ID -e OTEL_EXPORTER_OTLP_HEADERS -e CODEX_HOME -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 -v '"${RUNNER_TEMP}"'/gh-aw/safeoutputs:'"${RUNNER_TEMP}"'/gh-aw/safeoutputs:rw ghcr.io/github/gh-aw-mcpg:v0.4.25' | ||
| cat > "${RUNNER_TEMP}/gh-aw/mcp-config/config.toml" << GH_AW_MCP_CONFIG_34624276a1dcb8e9_EOF | ||
| [history] | ||
| persistence = "none" | ||
| [otel] | ||
| metrics_exporter = "none" | ||
| [shell_environment_policy] | ||
| inherit = "core" | ||
| include_only = ["^CODEX_API_KEY$", "^GH_AW_ASSETS_ALLOWED_EXTS$", "^GH_AW_ASSETS_BRANCH$", "^GH_AW_ASSETS_MAX_SIZE_KB$", "^GH_AW_SAFE_OUTPUTS$", "^GITHUB_PERSONAL_ACCESS_TOKEN$", "^GITHUB_REPOSITORY$", "^GITHUB_SERVER_URL$", "^HOME$", "^OPENAI_API_KEY$", "^PATH$"] | ||
| [mcp_servers.github] | ||
| user_agent = "codex-pr-review" | ||
| startup_timeout_sec = 120 | ||
| tool_timeout_sec = 60 | ||
| container = "ghcr.io/github/github-mcp-server:v1.12.2" | ||
| env = { "GITHUB_FEATURES" = "fields_param", "GITHUB_HOST" = "$GITHUB_SERVER_URL", "GITHUB_PERSONAL_ACCESS_TOKEN" = "$GH_AW_GITHUB_TOKEN", "GITHUB_READ_ONLY" = "1", "GITHUB_TOOLSETS" = "context,repos,issues,pull_requests" } | ||
| env_vars = ["GITHUB_FEATURES", "GITHUB_HOST", "GITHUB_PERSONAL_ACCESS_TOKEN", "GITHUB_READ_ONLY", "GITHUB_TOOLSETS"] | ||
| [mcp_servers.safeoutputs] | ||
| container = "ghcr.io/github/gh-aw-node" | ||
| mounts = ["\${GITHUB_WORKSPACE}:\${GITHUB_WORKSPACE}:rw", "${RUNNER_TEMP}/gh-aw/safeoutputs:${RUNNER_TEMP}/gh-aw/safeoutputs:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"] | ||
| args = ["-w", "$GITHUB_WORKSPACE"] | ||
| entrypoint = "sh" | ||
| entrypointArgs = ["-c", "sh ${RUNNER_TEMP}/gh-aw/safeoutputs/start_safe_outputs_mcp.sh"] | ||
| env_vars = ["DEBUG", "DEFAULT_BRANCH", "GH_AW_ASSETS_ALLOWED_EXTS", "GH_AW_ASSETS_BRANCH", "GH_AW_ASSETS_MAX_SIZE_KB", "GH_AW_MCP_LOG_DIR", "GH_AW_SAFE_OUTPUTS", "GH_AW_SAFE_OUTPUTS_CONFIG_PATH", "GH_AW_SAFE_OUTPUTS_TOOLS_PATH", "GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST", "GH_AW_PR_HEAD_BASE_BRANCH", "GH_AW_PR_HEAD_BASE_SHA", "GH_AW_PR_HEAD_BASE_REPO", "GH_AW_PR_HEAD_BASE_PR_NUMBER", "GH_AW_PR_HEAD_BASE_REF", "GH_AW_PR_HEAD_REPO", "GITHUB_EVENT_NAME", "GITHUB_EVENT_PATH", "GITHUB_REPOSITORY", "GITHUB_SHA", "GITHUB_TOKEN", "GITHUB_WORKSPACE", "RUNNER_TEMP"] | ||
| [mcp_servers.safeoutputs."guard-policies"] | ||
| [mcp_servers.safeoutputs."guard-policies".write-sink] | ||
| accept = ["*"] | ||
| sink-visibility = "${GH_AW_SINK_VISIBILITY}" | ||
| GH_AW_MCP_CONFIG_34624276a1dcb8e9_EOF | ||
| # Generate JSON config for MCP gateway | ||
| GH_AW_NODE=$(which node 2>/dev/null || command -v node 2>/dev/null || echo node) | ||
| cat << GH_AW_MCP_CONFIG_3fc8161c8e784f05_EOF | "$GH_AW_NODE" "${RUNNER_TEMP}/gh-aw/actions/start_mcp_gateway.cjs" | ||
| { | ||
| "mcpServers": { | ||
| "github": { | ||
| "container": "ghcr.io/github/github-mcp-server:v1.12.2", | ||
| "env": { | ||
| "GITHUB_FEATURES": "fields_param", | ||
| "GITHUB_HOST": "$GITHUB_SERVER_URL", | ||
| "GITHUB_PERSONAL_ACCESS_TOKEN": "$GITHUB_MCP_SERVER_TOKEN", | ||
| "GITHUB_READ_ONLY": "1", | ||
| "GITHUB_TOOLSETS": "context,repos,issues,pull_requests" | ||
| }, | ||
| "guard-policies": { | ||
| "allow-only": { | ||
| "approval-labels": ${{ steps.parse-guard-vars.outputs.approval_labels }}, | ||
| "blocked-users": ${{ steps.parse-guard-vars.outputs.blocked_users }}, | ||
| "min-integrity": "approved", | ||
| "repos": "all", | ||
| "trusted-users": ${{ steps.parse-guard-vars.outputs.trusted_users }} | ||
| } | ||
| } | ||
| }, | ||
| "safeoutputs": { | ||
| "container": "ghcr.io/github/gh-aw-node", | ||
| "mounts": ["\${GITHUB_WORKSPACE}:\${GITHUB_WORKSPACE}:rw", "${RUNNER_TEMP}/gh-aw/safeoutputs:${RUNNER_TEMP}/gh-aw/safeoutputs:rw", "/tmp/gh-aw:/tmp/gh-aw:rw"], | ||
| "args": ["-w", "\${GITHUB_WORKSPACE}"], | ||
| "entrypoint": "sh", | ||
| "entrypointArgs": ["-c", "sh ${RUNNER_TEMP}/gh-aw/safeoutputs/start_safe_outputs_mcp.sh"], | ||
| "env": { | ||
| "DEBUG": "*", | ||
| "DEFAULT_BRANCH": "\${DEFAULT_BRANCH}", | ||
| "GH_AW_ASSETS_ALLOWED_EXTS": "\${GH_AW_ASSETS_ALLOWED_EXTS}", | ||
| "GH_AW_ASSETS_BRANCH": "\${GH_AW_ASSETS_BRANCH}", | ||
| "GH_AW_ASSETS_MAX_SIZE_KB": "\${GH_AW_ASSETS_MAX_SIZE_KB}", | ||
| "GH_AW_MCP_LOG_DIR": "\${GH_AW_MCP_LOG_DIR}", | ||
| "GH_AW_SAFE_OUTPUTS": "\${GH_AW_SAFE_OUTPUTS}", | ||
| "GH_AW_SAFE_OUTPUTS_CONFIG_PATH": "\${GH_AW_SAFE_OUTPUTS_CONFIG_PATH}", | ||
| "GH_AW_SAFE_OUTPUTS_TOOLS_PATH": "\${GH_AW_SAFE_OUTPUTS_TOOLS_PATH}", | ||
| "GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST": "\${GH_AW_POLICY_ALLOW_CREATE_PULL_REQUEST}", | ||
| "GH_AW_PR_HEAD_BASE_BRANCH": "\${GH_AW_PR_HEAD_BASE_BRANCH}", | ||
| "GH_AW_PR_HEAD_BASE_SHA": "\${GH_AW_PR_HEAD_BASE_SHA}", | ||
| "GH_AW_PR_HEAD_BASE_REPO": "\${GH_AW_PR_HEAD_BASE_REPO}", | ||
| "GH_AW_PR_HEAD_BASE_PR_NUMBER": "\${GH_AW_PR_HEAD_BASE_PR_NUMBER}", | ||
| "GH_AW_PR_HEAD_BASE_REF": "\${GH_AW_PR_HEAD_BASE_REF}", | ||
| "GH_AW_PR_HEAD_REPO": "\${GH_AW_PR_HEAD_REPO}", | ||
| "GITHUB_EVENT_NAME": "\${GITHUB_EVENT_NAME}", | ||
| "GITHUB_EVENT_PATH": "\${GITHUB_EVENT_PATH}", | ||
| "GITHUB_REPOSITORY": "\${GITHUB_REPOSITORY}", | ||
| "GITHUB_SHA": "\${GITHUB_SHA}", | ||
| "GITHUB_TOKEN": "\${GITHUB_TOKEN}", | ||
| "GITHUB_WORKSPACE": "\${GITHUB_WORKSPACE}", | ||
| "RUNNER_TEMP": "\${RUNNER_TEMP}" | ||
| }, | ||
| "guard-policies": { | ||
| "write-sink": { | ||
| "accept": [ | ||
| "*" | ||
| ], | ||
| "sink-visibility": "${GH_AW_SINK_VISIBILITY}" | ||
| } | ||
| } | ||
| } | ||
| }, | ||
| "gateway": { | ||
| "port": $MCP_GATEWAY_PORT, | ||
| "domain": "${MCP_GATEWAY_DOMAIN}", | ||
| "agentId": "${MCP_GATEWAY_AGENT_ID}", | ||
| "payloadDir": "${MCP_GATEWAY_PAYLOAD_DIR}", | ||
| "startupTimeout": 120, | ||
| "opentelemetry": { | ||
| "endpoint": "${OTEL_EXPORTER_OTLP_ENDPOINT}", | ||
| "traceId": "${GITHUB_AW_OTEL_TRACE_ID}", | ||
| "spanId": "${GITHUB_AW_OTEL_PARENT_SPAN_ID}" | ||
| } | ||
| } | ||
| } | ||
| GH_AW_MCP_CONFIG_3fc8161c8e784f05_EOF | ||
| # Sync converter output to writable CODEX_HOME for Codex | ||
| mkdir -p /tmp/gh-aw/mcp-config | ||
| cat > "/tmp/gh-aw/mcp-config/config.toml" << GH_AW_CODEX_SHELL_POLICY_1291c5e46fe06428_EOF | ||
| model_provider = "openai-proxy" | ||
| [model_providers.openai-proxy] | ||
| name = "OpenAI AWF proxy" | ||
| base_url = "http://172.30.0.30:10000" | ||
| env_key = "CODEX_API_KEY" | ||
| wire_api = "responses" | ||
| requires_openai_auth = false | ||
| supports_websockets = false | ||
| [features] | ||
| plugins = false | ||
| [shell_environment_policy] | ||
| inherit = "core" | ||
| include_only = ["^CODEX_API_KEY$", "^GH_AW_ASSETS_ALLOWED_EXTS$", "^GH_AW_ASSETS_BRANCH$", "^GH_AW_ASSETS_MAX_SIZE_KB$", "^GH_AW_SAFE_OUTPUTS$", "^GITHUB_PERSONAL_ACCESS_TOKEN$", "^GITHUB_REPOSITORY$", "^GITHUB_SERVER_URL$", "^HOME$", "^OPENAI_API_KEY$", "^PATH$"] | ||
| GH_AW_CODEX_SHELL_POLICY_1291c5e46fe06428_EOF | ||
| awk ' | ||
| BEGIN { skip_openai_proxy = 0 } | ||
| /^[[:space:]]*model_provider[[:space:]]*=/ { next } | ||
| /^\[model_providers\.openai-proxy\][[:space:]]*$/ { skip_openai_proxy = 1; next } | ||
| /^\[/ { skip_openai_proxy = 0 } | ||
| !skip_openai_proxy { print } | ||
| ' "${RUNNER_TEMP}/gh-aw/mcp-config/config.toml" >> "/tmp/gh-aw/mcp-config/config.toml" | ||
| chmod 600 "/tmp/gh-aw/mcp-config/config.toml" | ||
| mkdir -p "${CODEX_HOME}" | ||
| if [ "/tmp/gh-aw/mcp-config/config.toml" != "${CODEX_HOME}/config.toml" ]; then cp "/tmp/gh-aw/mcp-config/config.toml" "${CODEX_HOME}/config.toml"; fi | ||
| chmod 600 "${CODEX_HOME}/config.toml" | ||
| - name: Mount MCP servers as CLIs | ||
| id: mount-mcp-clis | ||
| continue-on-error: true | ||
| env: | ||
| MCP_GATEWAY_AGENT_ID: ${{ steps.start-mcp-gateway.outputs.gateway-agent-id }} | ||
| MCP_GATEWAY_DOMAIN: ${{ steps.start-mcp-gateway.outputs.gateway-domain }} | ||
| MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }} | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| with: | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io); | ||
| const { main } = require(path.join(actionsDir, 'mount_mcp_as_cli.cjs')); | ||
| await main(); | ||
| - name: Clean credentials | ||
| continue-on-error: true | ||
| run: bash "${RUNNER_TEMP}/gh-aw/actions/clean_git_credentials.sh" | ||
| - name: Audit pre-agent workspace | ||
| id: pre_agent_audit | ||
| continue-on-error: true | ||
| run: bash "${RUNNER_TEMP}/gh-aw/actions/audit_pre_agent_workspace.sh" | ||
| - name: Execute Codex CLI | ||
| id: agentic_execution | ||
| timeout-minutes: 30 | ||
| run: | | ||
| set -o pipefail | ||
| trap 'gh_aw_exit_code=$?; mkdir -p /tmp/gh-aw >/dev/null 2>&1 || true; printf "%s" "$gh_aw_exit_code" > /tmp/gh-aw/agent_execution_exit_code.txt || true; if [ "$gh_aw_exit_code" -ne 0 ]; then echo "::error::Agent execution exited with code $gh_aw_exit_code"; fi' EXIT | ||
| printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt | ||
| mkdir -p "$CODEX_HOME/logs" && touch /tmp/gh-aw/agent-step-summary.md | ||
| (umask 177 && touch /tmp/gh-aw/agent-stdio.log) | ||
| GH_AW_MAX_AI_CREDITS="${GH_AW_MAX_AI_CREDITS:-1000}" | ||
| if [[ ! "$GH_AW_MAX_AI_CREDITS" =~ ^[0-9]+$ ]]; then | ||
| GH_AW_MAX_AI_CREDITS="1000" | ||
| fi | ||
| printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.28.23/awf-config.schema.json\",\"network\":{\"allowDomains\":[\"api.snapcraft.io\",\"archive.ubuntu.com\",\"azure.archive.ubuntu.com\",\"crl.geotrust.com\",\"crl.globalsign.com\",\"crl.identrust.com\",\"crl.sectigo.com\",\"crl.thawte.com\",\"crl.usertrust.com\",\"crl.verisign.com\",\"crl3.digicert.com\",\"crl4.digicert.com\",\"crls.ssl.com\",\"json-schema.org\",\"json.schemastore.org\",\"keyserver.ubuntu.com\",\"ocsp.digicert.com\",\"ocsp.geotrust.com\",\"ocsp.globalsign.com\",\"ocsp.identrust.com\",\"ocsp.sectigo.com\",\"ocsp.ssl.com\",\"ocsp.thawte.com\",\"ocsp.usertrust.com\",\"ocsp.verisign.com\",\"packagecloud.io\",\"packages.cloud.google.com\",\"packages.microsoft.com\",\"ppa.launchpad.net\",\"s.symcb.com\",\"s.symcd.com\",\"security.ubuntu.com\",\"ts-crl.ws.symantec.com\",\"ts-ocsp.ws.symantec.com\",\"www.googleapis.com\"],\"isolation\":true,\"topologyAttach\":[\"awmg-mcpg\"]},\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS},\"maxCacheMisses\":5,\"models\":{\"agent\":[\"sonnet-6x\",\"gpt-6\",\"gpt-5.4\",\"gpt-5.5\",\"gpt-5.6\",\"gpt-5.3\",\"gemini-pro\",\"any\"],\"antigravity\":[\"copilot/antigravity*\",\"google/antigravity*\",\"gemini/antigravity*\"],\"any\":[\"copilot/*\",\"anthropic/*\",\"openai/*\",\"google/*\",\"gemini/*\"],\"auto\":[\"copilot/auto\",\"large\"],\"claude\":[\"agent\"],\"codex\":[\"agent\"],\"coding\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\",\"gpt-5-codex\",\"kimi\"],\"computer-use\":[\"copilot/*computer-use*\",\"google/*computer-use*\",\"gemini/*computer-use*\",\"openai/*computer-use*\"],\"copilot\":[\"agent\"],\"deep-research\":[\"copilot/deep-research*\",\"copilot/o3-deep-research*\",\"copilot/o4-mini-deep-research*\",\"google/deep-research*\",\"gemini/deep-research*\",\"openai/o3-deep-research*\",\"openai/o4-mini-deep-research*\"],\"detection\":[\"small\"],\"evals\":[\"small\"],\"fable\":[\"copilot/*fable*\",\"anthropic/*fable*\"],\"gemini\":[\"agent\"],\"gemini-3-flash\":[\"copilot/gemini-3*flash*\",\"google/gemini-3*flash*\",\"gemini/gemini-3*flash*\"],\"gemini-3-pro\":[\"copilot/gemini-3*pro*\",\"google/gemini-3*pro*\",\"google/nano-banana*\",\"gemini/gemini-3*pro*\"],\"gemini-3.1-flash\":[\"copilot/gemini-3.1*flash*\",\"google/gemini-3.1*flash*\",\"gemini/gemini-3.1*flash*\"],\"gemini-3.1-pro\":[\"copilot/gemini-3.1*pro*\",\"google/gemini-3.1*pro*\",\"gemini/gemini-3.1*pro*\"],\"gemini-3.5-flash\":[\"copilot/gemini-3.5*flash*\",\"google/gemini-3.5*flash*\",\"gemini/gemini-3.5*flash*\"],\"gemini-3.6-flash\":[\"copilot/gemini-3.6*flash*\",\"google/gemini-3.6*flash*\",\"gemini/gemini-3.6*flash*\"],\"gemini-3.7-flash\":[\"copilot/gemini-3.7*flash*\",\"google/gemini-3.7*flash*\",\"gemini/gemini-3.7*flash*\"],\"gemini-3.8-flash\":[\"copilot/gemini-3.8*flash*\",\"google/gemini-3.8*flash*\",\"gemini/gemini-3.8*flash*\"],\"gemini-flash\":[\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"],\"gemini-flash-lite\":[\"copilot/gemini-*flash*lite*\",\"google/gemini-*flash*lite*\",\"gemini/gemini-*flash*lite*\"],\"gemini-omni\":[\"copilot/gemini-omni*\",\"google/gemini-omni*\",\"gemini/gemini-omni*\"],\"gemini-pro\":[\"copilot/gemini-*pro*\",\"google/gemini-*pro*\",\"gemini/gemini-*pro*\"],\"gemma\":[\"copilot/gemma*\",\"google/gemma*\",\"gemini/gemma*\"],\"gpt-5\":[\"copilot/gpt-5*\",\"openai/gpt-5*\"],\"gpt-5-codex\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\"],\"gpt-5-mini\":[\"copilot/gpt-5*mini*\",\"openai/gpt-5*mini*\"],\"gpt-5-nano\":[\"copilot/gpt-5*nano*\",\"openai/gpt-5*nano*\"],\"gpt-5-pro\":[\"copilot/gpt-5*pro*\",\"openai/gpt-5*pro*\"],\"gpt-5.1\":[\"copilot/gpt-5.1*\",\"openai/gpt-5.1*\"],\"gpt-5.2\":[\"copilot/gpt-5.2*\",\"openai/gpt-5.2*\"],\"gpt-5.3\":[\"copilot/gpt-5.3*\",\"openai/gpt-5.3*\"],\"gpt-5.4\":[\"copilot/gpt-5.4*\",\"openai/gpt-5.4*\"],\"gpt-5.5\":[\"copilot/gpt-5.5*\",\"openai/gpt-5.5*\"],\"gpt-5.6\":[\"copilot/gpt-5.6*\",\"openai/gpt-5.6*\"],\"gpt-6\":[\"copilot/gpt-6*\",\"openai/gpt-6*\"],\"grok\":[\"copilot/*grok*\",\"openai/*grok*\"],\"haiku\":[\"copilot/*haiku*\",\"anthropic/*haiku*\"],\"image-generation\":[\"copilot/gpt-image*\",\"openai/gpt-image*\",\"openai/chatgpt-image*\",\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"google/imagen*\"],\"kimi\":[\"copilot/kimi*\",\"openai/kimi*\"],\"kiwi\":[\"copilot/kiwi*\",\"openai/kiwi*\"],\"large\":[\"sonnet\",\"gpt-6\",\"gpt-5-pro\",\"gpt-5\",\"gemini-pro\"],\"lyria\":[\"google/lyria*\",\"gemini/lyria*\",\"copilot/lyria*\"],\"mai-code\":[\"copilot/MAI-Code*\",\"copilot/mai-code*\",\"openai/MAI-Code*\"],\"mai-code-1-flash-picker\":[\"copilot/MAI-Code-1-Flash-picker*\",\"copilot/mai-code-1-flash-picker*\",\"openai/MAI-Code-1-Flash-picker*\"],\"mini\":[\"haiku\",\"gpt-5-mini\",\"gpt-5-nano\",\"gemini-flash-lite\"],\"nano-banana\":[\"copilot/nano-banana*\",\"google/nano-banana*\",\"gemini/nano-banana*\"],\"opus\":[\"copilot/*opus*\",\"anthropic/*opus*\"],\"opusplan\":[\"opus?effort=high\"],\"raptor-mini\":[\"copilot/raptor*\",\"openai/raptor*\"],\"reasoning\":[\"copilot/o1*\",\"copilot/o3*\",\"copilot/o4*\",\"openai/o1*\",\"openai/o3*\",\"openai/o4*\"],\"robotics\":[\"copilot/*robotics*\",\"google/*robotics*\",\"gemini/*robotics*\"],\"small\":[\"mini\"],\"small-agent\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash\"],\"sonnet\":[\"copilot/*sonnet*\",\"anthropic/*sonnet*\"],\"sonnet-6x\":[\"copilot/*sonnet-4.5*\",\"copilot/*sonnet-4.6*\",\"copilot/*sonnet-5*\",\"copilot/*sonnet-4-5-*\",\"anthropic/*sonnet-4-5-*\",\"copilot/*sonnet-4-6*\",\"anthropic/*sonnet-4-6*\",\"anthropic/*sonnet-5*\"],\"summarization\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash-lite\",\"mini\"],\"veo\":[\"google/veo*\",\"gemini/veo*\"],\"vision\":[\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"]}},\"container\":{\"imageTag\":\"0.28.23,squid=sha256:02ffc56dd40158223064ef03a78c2d9717473c93723b4e403d455ea6f0b09ae0,agent=sha256:2c78aaba1c108e130e2d6d01e4f2cca334ea04c53e6f258913ac34173fe7e3b2,api-proxy=sha256:c15c3d1208df10c5b588a3657be53742aa982ae0909d1eb1812525268794ca64,cli-proxy=sha256:9e31a6e518eba44652b9ae94ce55c3b6958e06290c3b81b08de4174751bb439a\"},\"logging\":{\"proxyLogsDir\":\"/tmp/gh-aw/sandbox/firewall/logs\",\"auditDir\":\"/tmp/gh-aw/sandbox/firewall/audit\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json" | ||
| cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json | ||
| export GH_AW_MODELS_JSON_PATH="/tmp/gh-aw/models.json" | ||
| GH_AW_DOCKER_HOST="" | ||
| if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then | ||
| GH_AW_DOCKER_HOST="${DOCKER_HOST}" | ||
| fi | ||
| if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then | ||
| GH_AW_CHROOT_BINARIES_SOURCE_PATH="${RUNNER_TEMP}/gh-aw" GH_AW_CHROOT_IDENTITY_HOME="${RUNNER_TEMP}/gh-aw/home" node "${RUNNER_TEMP}/gh-aw/actions/patch_awf_chroot_config.cjs" | ||
| fi | ||
| GH_AW_TOOL_CACHE_MOUNT="" | ||
| GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}" | ||
| if [ -d "$GH_AW_TOOL_CACHE" ]; then | ||
| if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then | ||
| GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro" | ||
| fi | ||
| fi | ||
| # shellcheck disable=SC1003,SC2016,SC2086 | ||
| mkdir -p "/tmp/gh-aw" | ||
| evidence_tmp="/tmp/gh-aw/agent_execution.json.tmp" | ||
| printf '{"version":1,"component":"agent","run_id":%s,"run_attempt":%s,"state":"started"}\n' "$GITHUB_RUN_ID" "$GITHUB_RUN_ATTEMPT" > "$evidence_tmp" | ||
| mv "$evidence_tmp" "/tmp/gh-aw/agent_execution.json" | ||
| export GH_AW_AWF_EXECUTION_COMPONENT="agent" | ||
| export GH_AW_AWF_EXECUTION_EVIDENCE_FILE="/tmp/gh-aw/agent_execution.json" | ||
| GH_AW_AWF_ENGINE_NAME=codex \ | ||
| GH_AW_AWF_HARNESS_MARKER='[codex-harness]' \ | ||
| GH_AW_AWF_LOG_FILE=/tmp/gh-aw/agent-stdio.log \ | ||
| GH_AW_AWF_ATTEMPT_LOG_NAME=codex \ | ||
| bash "${RUNNER_TEMP}/gh-aw/actions/run_awf_with_startup_retries.sh" -- \ | ||
| awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST:+--docker-host "$GH_AW_DOCKER_HOST"} --env-all --exclude-env ACTIONS_ID_TOKEN_REQUEST_TOKEN --exclude-env ACTIONS_ID_TOKEN_REQUEST_URL --exclude-env CODEX_API_KEY --exclude-env COPILOT_GITHUB_TOKEN --exclude-env GITHUB_MCP_SERVER_TOKEN --exclude-env MCP_GATEWAY_AGENT_ID --exclude-env OPENAI_API_KEY --mount /tmp/gh-aw:/tmp/gh-aw:rw --log-level info --skip-pull \ | ||
| -- /bin/bash -c 'set +o histexpand; export PATH="${RUNNER_TEMP}/gh-aw/mcp-cli/bin:$PATH" && : "${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}"; GH_AW_TOOL_CACHE="$RUNNER_TOOL_CACHE"; GH_AW_TOOL_BINS="$(find "$GH_AW_TOOL_CACHE" -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')"; GH_AW_TOOL_BINS="${GH_AW_TOOL_BINS%:}"; export PATH="$PATH${GH_AW_TOOL_BINS:+:}$GH_AW_TOOL_BINS"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true; [ -n "$ERLANG_HOME" ] && export PATH="$ERLANG_HOME/bin:$PATH" || true && GH_AW_NODE_EXEC="${GH_AW_NODE_BIN:-}"; if [ -z "$GH_AW_NODE_EXEC" ] || [ ! -x "$GH_AW_NODE_EXEC" ]; then GH_AW_NODE_EXEC="$(command -v node 2>/dev/null || true)"; fi; if [ -z "$GH_AW_NODE_EXEC" ]; then echo "node runtime missing on this runner — check runtimes.node in workflow YAML" >&2; exit 127; fi; GH_AW_NPM_GLOBAL_ROOT="$(npm root -g 2>/dev/null || true)"; if [ -n "$GH_AW_NPM_GLOBAL_ROOT" ]; then export NODE_PATH="${GH_AW_NPM_GLOBAL_ROOT}${NODE_PATH:+:${NODE_PATH}}"; fi; "$GH_AW_NODE_EXEC" ${RUNNER_TEMP}/gh-aw/actions/codex_harness.cjs codex exec${GH_AW_MODEL_AGENT_CODEX:+ --model "$GH_AW_MODEL_AGENT_CODEX"} -c web_search="disabled" -c fetch="disabled" --dangerously-bypass-approvals-and-sandbox --skip-git-repo-check -c model_reasoning_effort="high" --prompt-file /tmp/gh-aw/aw-prompts/prompt.txt' | ||
| env: | ||
| AWF_REFLECT_ENABLED: 1 | ||
| CODEX_API_KEY: ${{ secrets.CODEX_API_KEY || secrets.OPENAI_API_KEY }} | ||
| CODEX_HOME: /tmp/gh-aw/mcp-config | ||
| GH_AW_LLM_PROVIDER: openai | ||
| GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }} | ||
| GH_AW_MAX_TURNS: ${{ vars.GH_AW_DEFAULT_MAX_TURNS || '' }} | ||
| GH_AW_MCP_CONFIG: ${{ runner.temp }}/gh-aw/mcp-config/config.toml | ||
| GH_AW_MODEL_AGENT_CODEX: gpt-6-astra | ||
| GH_AW_PHASE: agent | ||
| GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt | ||
| GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} | ||
| GH_AW_VERSION: v0.89.20 | ||
| GITHUB_AW: true | ||
| GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md | ||
| GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com | ||
| GIT_AUTHOR_NAME: github-actions[bot] | ||
| GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com | ||
| GIT_COMMITTER_NAME: github-actions[bot] | ||
| OPENAI_API_KEY: ${{ secrets.CODEX_API_KEY || secrets.OPENAI_API_KEY }} | ||
| RUNNER_TEMP: ${{ runner.temp }} | ||
| RUST_LOG: ${{ runner.debug == 1 && 'trace,hyper_util=info,mio=info,reqwest=info,os_info=info,codex_otel=warn,codex_core=debug,codex_exec=debug' || 'warn' }} | ||
| TRACEPARENT: ${{ env.GITHUB_AW_OTEL_TRACE_ID != '' && env.GITHUB_AW_OTEL_PARENT_SPAN_ID != '' && format('00-{0}-{1}-01', env.GITHUB_AW_OTEL_TRACE_ID, env.GITHUB_AW_OTEL_PARENT_SPAN_ID) || '' }} | ||
| - name: Detect agent errors | ||
| if: always() | ||
| id: detect-agent-errors | ||
| continue-on-error: true | ||
| env: | ||
| GH_AW_AGENTIC_EXECUTION_OUTCOME: ${{ steps.agentic_execution.outcome }} | ||
| GH_AW_ENGINE_STEP_TIMEOUT_MINUTES: 30 | ||
| GH_AW_ENGINE_INTERNAL_LOGS_DIR: /tmp/gh-aw/mcp-config/logs | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| with: | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'detect_agent_errors.cjs')); | ||
| await main(); | ||
| - name: Configure Git credentials | ||
| env: | ||
| GITHUB_REPOSITORY: ${{ github.repository }} | ||
| GITHUB_SERVER_URL: ${{ github.server_url }} | ||
| GITHUB_TOKEN: ${{ github.token }} | ||
| run: bash "${RUNNER_TEMP}/gh-aw/actions/configure_git_credentials.sh" | ||
| - name: Stop MCP Gateway | ||
| if: always() | ||
| continue-on-error: true | ||
| env: | ||
| MCP_GATEWAY_PORT: ${{ steps.start-mcp-gateway.outputs.gateway-port }} | ||
| MCP_GATEWAY_AGENT_ID: ${{ steps.start-mcp-gateway.outputs.gateway-agent-id }} | ||
| GATEWAY_PID: ${{ steps.start-mcp-gateway.outputs.gateway-pid }} | ||
| run: | | ||
| bash "${RUNNER_TEMP}/gh-aw/actions/stop_mcp_gateway.sh" "$GATEWAY_PID" | ||
| - name: Redact secrets in logs | ||
| if: always() | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| with: | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'redact_secrets.cjs')); | ||
| await main(); | ||
| env: | ||
| GH_AW_SECRET_NAMES: 'CODEX_API_KEY,GH_AW_GITHUB_MCP_SERVER_TOKEN,GH_AW_GITHUB_TOKEN,GITHUB_TOKEN,OPENAI_API_KEY' | ||
| SECRET_CODEX_API_KEY: ${{ secrets.CODEX_API_KEY }} | ||
| SECRET_GH_AW_GITHUB_MCP_SERVER_TOKEN: ${{ secrets.GH_AW_GITHUB_MCP_SERVER_TOKEN }} | ||
| SECRET_GH_AW_GITHUB_TOKEN: ${{ secrets.GH_AW_GITHUB_TOKEN }} | ||
| SECRET_GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| SECRET_OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} | ||
| - name: Append agent step summary | ||
| if: always() | ||
| run: bash "${RUNNER_TEMP}/gh-aw/actions/append_agent_step_summary.sh" | ||
| - name: Copy Safe Outputs | ||
| if: always() | ||
| env: | ||
| GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} | ||
| run: | | ||
| mkdir -p /tmp/gh-aw | ||
| cp "$GH_AW_SAFE_OUTPUTS" /tmp/gh-aw/safeoutputs.jsonl 2>/dev/null || true | ||
| - name: Ingest agent output | ||
| id: collect_output | ||
| if: always() | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| env: | ||
| GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} | ||
| GH_AW_ALLOWED_DOMAINS: "api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,s.symcb.com,s.symcd.com,security.ubuntu.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" | ||
| GITHUB_SERVER_URL: ${{ github.server_url }} | ||
| GITHUB_API_URL: ${{ github.api_url }} | ||
| GH_AW_COMMANDS: "[\"codex\"]" | ||
| with: | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'collect_ndjson_output.cjs')); | ||
| await main(); | ||
| - name: Parse agent logs for step summary | ||
| if: always() | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| env: | ||
| GH_AW_AGENT_OUTPUT: /tmp/gh-aw/agent-stdio.log | ||
| GH_AW_SAFE_OUTPUTS: ${{ steps.set-runtime-paths.outputs.GH_AW_SAFE_OUTPUTS }} | ||
| with: | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'parse_codex_log.cjs')); | ||
| await main(); | ||
| - name: Parse MCP Gateway logs for step summary | ||
| if: always() | ||
| id: parse-mcp-gateway | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| with: | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'parse_mcp_gateway_log.cjs')); | ||
| await main(); | ||
| - name: Print firewall logs | ||
| if: always() | ||
| continue-on-error: true | ||
| env: | ||
| AWF_LOGS_DIR: /tmp/gh-aw/sandbox/firewall/logs | ||
| run: bash "${RUNNER_TEMP}/gh-aw/actions/print_firewall_logs.sh" --rootless | ||
| - name: Parse token usage for step summary | ||
| if: always() | ||
| id: parse-token-usage | ||
| continue-on-error: true | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| with: | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'parse_token_usage.cjs')); | ||
| await main(); | ||
| - name: Print AWF reflect summary | ||
| if: always() | ||
| continue-on-error: true | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| with: | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'awf_reflect_summary.cjs')); | ||
| await main(); | ||
| - name: Generate observability summary | ||
| if: always() | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| with: | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'generate_observability_summary.cjs')); | ||
| await main(core); | ||
| - name: Write agent output placeholder if missing | ||
| if: always() | ||
| run: | | ||
| if [ ! -f /tmp/gh-aw/agent_output.json ]; then | ||
| echo '{"items":[]}' > /tmp/gh-aw/agent_output.json | ||
| fi | ||
| # Small dedicated copy of the agent output so safe-output processing | ||
| # survives a failed or timed-out upload of the larger agent artifact | ||
| - name: Upload agent output fallback artifact | ||
| if: always() | ||
| continue-on-error: true | ||
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | ||
| with: | ||
| name: agent-output-fallback | ||
| path: | | ||
| /tmp/gh-aw/agent_output.json | ||
| /tmp/gh-aw/safeoutputs.jsonl | ||
| /tmp/gh-aw/agent_execution.json | ||
| /tmp/gh-aw/agent_usage.jsonl | ||
| /tmp/gh-aw/agent_usage.json | ||
| /tmp/gh-aw/sandbox/firewall-audit-logs/api-proxy-logs/token-usage.jsonl | ||
| /tmp/gh-aw/sandbox/firewall/logs/api-proxy-logs/token-usage.jsonl | ||
| /tmp/gh-aw/sandbox/firewall/audit/api-proxy-logs/token-usage.jsonl | ||
| if-no-files-found: ignore | ||
| - name: Upload agent artifacts | ||
| if: always() | ||
| continue-on-error: true | ||
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | ||
| with: | ||
| name: agent | ||
| path: | | ||
| /tmp/gh-aw/aw-prompts/prompt.txt | ||
| /tmp/gh-aw/agent_execution.json | ||
| /tmp/gh-aw/mcp-config/logs/ | ||
| /tmp/gh-aw/redacted-urls.log | ||
| /tmp/gh-aw/mcp-logs/ | ||
| /tmp/gh-aw/proxy-logs/ | ||
| !/tmp/gh-aw/proxy-logs/proxy-tls/ | ||
| /tmp/gh-aw/agent_usage.json | ||
| /tmp/gh-aw/agent-stdio.log | ||
| /tmp/gh-aw/pre-agent-audit.txt | ||
| /tmp/gh-aw/github_rate_limits.jsonl | ||
| /tmp/gh-aw/otel.jsonl | ||
| /tmp/gh-aw/otlp-export-errors.jsonl | ||
| /tmp/gh-aw/safeoutputs.jsonl | ||
| /tmp/gh-aw/agent_output.json | ||
| /tmp/gh-aw/aw-*.patch | ||
| /tmp/gh-aw/aw-*.bundle | ||
| /tmp/gh-aw/awf-config.json | ||
| /tmp/gh-aw/sandbox/firewall/logs/ | ||
| /tmp/gh-aw/sandbox/firewall/audit/ | ||
| /tmp/gh-aw/sandbox/firewall/awf-reflect.json | ||
| if-no-files-found: ignore | ||
| conclusion: | ||
| needs: | ||
| - activation | ||
| - agent | ||
| - detection | ||
| - safe_outputs | ||
| if: > | ||
| always() && (needs.agent.result != 'skipped' || needs.activation.outputs.lockdown_check_failed == 'true' || | ||
| needs.activation.outputs.oauth_token_check_failed == 'true' || needs.activation.outputs.stale_lock_file_failed == 'true' || | ||
| needs.activation.outputs.secret_verification_result == 'failed' || needs.activation.outputs.daily_ai_credits_exceeded == 'true' || | ||
| needs.activation.outputs.daily_ai_credits_guardrail_status == 'structural_error' || needs.activation.outputs.daily_ai_credits_guardrail_status == 'transient_error') | ||
| runs-on: ubuntu-slim | ||
| permissions: | ||
| actions: read | ||
| issues: write | ||
| pull-requests: write | ||
| concurrency: | ||
| group: "gh-aw-conclusion-codex-pr-review" | ||
| cancel-in-progress: false | ||
| queue: max | ||
| env: | ||
| GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }} | ||
| outputs: | ||
| incomplete_count: ${{ steps.report_incomplete.outputs.incomplete_count }} | ||
| noop_message: ${{ steps.noop.outputs.noop_message }} | ||
| tools_reported: ${{ steps.missing_tool.outputs.tools_reported }} | ||
| total_count: ${{ steps.missing_tool.outputs.total_count }} | ||
| steps: | ||
| - name: Setup Scripts | ||
| id: setup | ||
| uses: github/gh-aw-actions/setup@925900cb40de9cb7652268d0cd14e00f9b7d2189 # v0.89.20 | ||
| with: | ||
| destination: ${{ runner.temp }}/gh-aw/actions | ||
| job-name: ${{ github.job }} | ||
| trace-id: ${{ needs.activation.outputs.setup-trace-id }} | ||
| parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} | ||
| env: | ||
| GH_AW_SETUP_WORKFLOW_NAME: "Codex PR Review" | ||
| GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/codex-pr-review.lock.yml@${{ github.ref }} | ||
| GH_AW_INFO_VERSION: "0.154.0" | ||
| GH_AW_INFO_AWF_VERSION: "v0.28.23" | ||
| GH_AW_INFO_ENGINE_ID: "codex" | ||
| - name: Download agent output artifact | ||
| id: download-agent-output | ||
| continue-on-error: true | ||
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | ||
| with: | ||
| pattern: "{agent,agent-output-fallback}" | ||
| merge-multiple: true | ||
| path: /tmp/gh-aw/ | ||
| - name: Setup agent output environment variable | ||
| id: setup-agent-output-env | ||
| if: steps.download-agent-output.outcome == 'success' | ||
| run: | | ||
| mkdir -p /tmp/gh-aw/ | ||
| find "/tmp/gh-aw/" -type f -print | ||
| if [ -f "/tmp/gh-aw/agent_output.json" ]; then | ||
| echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" | ||
| fi | ||
| - name: Download detection artifact | ||
| id: download-detection-artifact | ||
| continue-on-error: true | ||
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | ||
| with: | ||
| name: detection | ||
| path: /tmp/gh-aw/threat-detection/ | ||
| - name: Download Safe Outputs Items Manifest | ||
| id: download-safe-outputs-manifest | ||
| if: always() | ||
| continue-on-error: true | ||
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | ||
| with: | ||
| pattern: safe-outputs-items | ||
| merge-multiple: true | ||
| path: /tmp/gh-aw/ | ||
| - name: Collect usage artifact files | ||
| if: always() | ||
| continue-on-error: true | ||
| run: bash "${RUNNER_TEMP}/gh-aw/actions/collect_usage_artifact_files.sh" | ||
| - name: Upload usage artifact | ||
| id: upload-usage-artifact | ||
| if: always() | ||
| continue-on-error: true | ||
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | ||
| with: | ||
| name: usage | ||
| path: | | ||
| /tmp/gh-aw/usage/aw_info.json | ||
| /tmp/gh-aw/usage/aw-info.jsonl | ||
| /tmp/gh-aw/usage/agent_usage.json | ||
| /tmp/gh-aw/usage/agent_usage.jsonl | ||
| /tmp/gh-aw/usage/detection_usage.jsonl | ||
| /tmp/gh-aw/usage/evals.jsonl | ||
| /tmp/gh-aw/usage/graders/grader_manifest.json | ||
| /tmp/gh-aw/usage/graders/grader_results.json | ||
| /tmp/gh-aw/usage/github_rate_limits.jsonl | ||
| /tmp/gh-aw/usage/agent/token_usage.jsonl | ||
| /tmp/gh-aw/usage/agent/execution.json | ||
| /tmp/gh-aw/usage/detection/token_usage.jsonl | ||
| /tmp/gh-aw/usage/detection/execution.json | ||
| /tmp/gh-aw/usage/evals/token_usage.jsonl | ||
| /tmp/gh-aw/usage/evals/execution.json | ||
| /tmp/gh-aw/usage/activity/summary.json | ||
| if-no-files-found: ignore | ||
| - name: Wait before retrying usage artifact upload | ||
| if: always() && steps.upload-usage-artifact.outcome == 'failure' | ||
| run: sleep 10 | ||
| - name: Retry upload usage artifact | ||
| id: upload-usage-artifact-retry | ||
| if: always() && steps.upload-usage-artifact.outcome == 'failure' | ||
| continue-on-error: true | ||
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | ||
| with: | ||
| name: usage | ||
| path: | | ||
| /tmp/gh-aw/usage/aw_info.json | ||
| /tmp/gh-aw/usage/aw-info.jsonl | ||
| /tmp/gh-aw/usage/agent_usage.json | ||
| /tmp/gh-aw/usage/agent_usage.jsonl | ||
| /tmp/gh-aw/usage/detection_usage.jsonl | ||
| /tmp/gh-aw/usage/evals.jsonl | ||
| /tmp/gh-aw/usage/graders/grader_manifest.json | ||
| /tmp/gh-aw/usage/graders/grader_results.json | ||
| /tmp/gh-aw/usage/github_rate_limits.jsonl | ||
| /tmp/gh-aw/usage/agent/token_usage.jsonl | ||
| /tmp/gh-aw/usage/agent/execution.json | ||
| /tmp/gh-aw/usage/detection/token_usage.jsonl | ||
| /tmp/gh-aw/usage/detection/execution.json | ||
| /tmp/gh-aw/usage/evals/token_usage.jsonl | ||
| /tmp/gh-aw/usage/evals/execution.json | ||
| /tmp/gh-aw/usage/activity/summary.json | ||
| if-no-files-found: ignore | ||
| overwrite: true | ||
| - name: Process no-op messages | ||
| id: noop | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| env: | ||
| GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} | ||
| GH_AW_NOOP_MAX: "1" | ||
| GH_AW_WORKFLOW_NAME: "Codex PR Review" | ||
| GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/codex-pr-review.md" | ||
| GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | ||
| GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} | ||
| GH_AW_NOOP_REPORT_AS_ISSUE: "false" | ||
| GH_AW_AIC: ${{ needs.agent.outputs.aic }} | ||
| GH_AW_THREAT_DETECTION_AIC: ${{ needs.detection.outputs.aic }} | ||
| GH_AW_AMBIENT_CONTEXT: ${{ needs.agent.outputs.ambient_context }} | ||
| GH_AW_WORKFLOW_ID: "codex-pr-review" | ||
| with: | ||
| github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'handle_noop_message.cjs')); | ||
| await main(); | ||
| - name: Log detection run | ||
| id: detection_runs | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| env: | ||
| GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} | ||
| GH_AW_WORKFLOW_NAME: "Codex PR Review" | ||
| GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/codex-pr-review.md" | ||
| GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | ||
| GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }} | ||
| GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }} | ||
| with: | ||
| github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'handle_detection_runs.cjs')); | ||
| await main(); | ||
| - name: Record missing tool | ||
| id: missing_tool | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| env: | ||
| GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} | ||
| GH_AW_MISSING_TOOL_CREATE_ISSUE: "true" | ||
| GH_AW_WORKFLOW_NAME: "Codex PR Review" | ||
| GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/codex-pr-review.md" | ||
| with: | ||
| github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'missing_tool.cjs')); | ||
| await main(); | ||
| - name: Record incomplete | ||
| id: report_incomplete | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| env: | ||
| GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} | ||
| GH_AW_REPORT_INCOMPLETE_CREATE_ISSUE: "true" | ||
| GH_AW_WORKFLOW_NAME: "Codex PR Review" | ||
| GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/codex-pr-review.md" | ||
| with: | ||
| github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'report_incomplete_handler.cjs')); | ||
| await main(); | ||
| - name: Handle agent failure | ||
| id: handle_agent_failure | ||
| if: always() | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| env: | ||
| GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} | ||
| GH_AW_WORKFLOW_NAME: "Codex PR Review" | ||
| GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/codex-pr-review.md" | ||
| GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | ||
| GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} | ||
| GH_AW_WORKFLOW_ID: "codex-pr-review" | ||
| GH_AW_ACTION_FAILURE_ISSUE_EXPIRES_HOURS: "0" | ||
| GH_AW_ENGINE_ID: "codex" | ||
| GH_AW_SECRET_VERIFICATION_RESULT: ${{ needs.activation.outputs.secret_verification_result }} | ||
| GH_AW_AI_CREDITS_RATE_LIMIT_ERROR: ${{ needs.agent.outputs.ai_credits_rate_limit_error || 'false' }} | ||
| GH_AW_UNKNOWN_MODEL_AI_CREDITS: ${{ needs.agent.outputs.unknown_model_ai_credits || 'false' }} | ||
| GH_AW_AIC: ${{ needs.agent.outputs.aic }} | ||
| GH_AW_THREAT_DETECTION_AIC: ${{ needs.detection.outputs.aic }} | ||
| GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_MAX_AI_CREDITS || '1000' }} | ||
| GH_AW_INFERENCE_ACCESS_ERROR: ${{ needs.agent.outputs.inference_access_error }} | ||
| GH_AW_MCP_POLICY_ERROR: ${{ needs.agent.outputs.mcp_policy_error }} | ||
| GH_AW_AGENTIC_ENGINE_TIMEOUT: ${{ needs.agent.outputs.agentic_engine_timeout }} | ||
| GH_AW_MODEL_NOT_SUPPORTED_ERROR: ${{ needs.agent.outputs.model_not_supported_error }} | ||
| GH_AW_HTTP_400_RESPONSE_ERROR: ${{ needs.agent.outputs.http_400_response_error }} | ||
| GH_AW_MAX_CACHE_MISSES_EXCEEDED: ${{ needs.agent.outputs.max_cache_misses_exceeded }} | ||
| GH_AW_MISSING_MODEL_PRICING_ERROR: ${{ needs.agent.outputs.missing_model_pricing_error }} | ||
| GH_AW_MISSING_MODEL_PRICING_MODEL_NAME: ${{ needs.agent.outputs.missing_model_pricing_model_name }} | ||
| GH_AW_SHELL_EXPANSION_GUARD_REJECTED: ${{ needs.agent.outputs.shell_expansion_guard_rejected }} | ||
| GH_AW_ENGINE_API_HOSTS: "api.openai.com" | ||
| GH_AW_LOCKDOWN_CHECK_FAILED: ${{ needs.activation.outputs.lockdown_check_failed }} | ||
| GH_AW_OAUTH_TOKEN_CHECK_FAILED: ${{ needs.activation.outputs.oauth_token_check_failed }} | ||
| GH_AW_STALE_LOCK_FILE_FAILED: ${{ needs.activation.outputs.stale_lock_file_failed }} | ||
| GH_AW_DAILY_AI_CREDITS_EXCEEDED: ${{ needs.activation.outputs.daily_ai_credits_exceeded }} | ||
| GH_AW_DAILY_AI_CREDITS_GUARDRAIL_STATUS: ${{ needs.activation.outputs.daily_ai_credits_guardrail_status }} | ||
| GH_AW_DAILY_AI_CREDITS_GUARDRAIL_ERROR: ${{ needs.activation.outputs.daily_ai_credits_guardrail_error }} | ||
| GH_AW_DAILY_AI_CREDITS_TOTAL: ${{ needs.activation.outputs.daily_ai_credits_total }} | ||
| GH_AW_DAILY_AI_CREDITS_THRESHOLD: ${{ needs.activation.outputs.daily_ai_credits_threshold }} | ||
| GH_AW_DAILY_AI_CREDITS_CONTINUE_ON_ERROR: "false" | ||
| GH_AW_GROUP_REPORTS: "false" | ||
| GH_AW_FAILURE_REPORT_AS_ISSUE: "true" | ||
| GH_AW_MISSING_TOOL_REPORT_AS_FAILURE: "true" | ||
| GH_AW_MISSING_DATA_REPORT_AS_FAILURE: "true" | ||
| GH_AW_TIMEOUT_MINUTES: "30" | ||
| with: | ||
| github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'handle_agent_failure.cjs')); | ||
| await main(); | ||
| - name: Report failed jobs | ||
| id: report_failed_jobs | ||
| if: always() | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| env: | ||
| GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} | ||
| GH_AW_WORKFLOW_NAME: "Codex PR Review" | ||
| GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/codex-pr-review.md" | ||
| GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | ||
| GH_AW_REPORT_FAILED_JOBS: "true" | ||
| with: | ||
| github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'report_failed_jobs.cjs')); | ||
| await main(); | ||
| - name: Update reaction comment with completion status | ||
| id: conclusion | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| env: | ||
| GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} | ||
| GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }} | ||
| GH_AW_COMMENT_REPO: ${{ needs.activation.outputs.comment_repo }} | ||
| GH_AW_RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | ||
| GH_AW_WORKFLOW_NAME: "Codex PR Review" | ||
| GH_AW_AGENT_CONCLUSION: ${{ needs.agent.result }} | ||
| GH_AW_SAFE_OUTPUTS_RESULT: ${{ needs.safe_outputs.result }} | ||
| GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }} | ||
| GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }} | ||
| with: | ||
| github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'notify_comment_error.cjs')); | ||
| await main(); | ||
| detection: | ||
| needs: | ||
| - activation | ||
| - agent | ||
| if: always() && needs.agent.result != 'skipped' | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: read | ||
| timeout-minutes: 10 | ||
| env: | ||
| GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }} | ||
| outputs: | ||
| aic: ${{ steps.parse_detection_token_usage.outputs.aic }} | ||
| detection_conclusion: ${{ steps.detection_conclusion.outputs.conclusion }} | ||
| detection_reason: ${{ steps.detection_conclusion.outputs.reason }} | ||
| detection_success: ${{ steps.detection_conclusion.outputs.success }} | ||
| steps: | ||
| - name: Setup Scripts | ||
| id: setup | ||
| uses: github/gh-aw-actions/setup@925900cb40de9cb7652268d0cd14e00f9b7d2189 # v0.89.20 | ||
| with: | ||
| destination: ${{ runner.temp }}/gh-aw/actions | ||
| job-name: ${{ github.job }} | ||
| trace-id: ${{ needs.activation.outputs.setup-trace-id }} | ||
| parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} | ||
| env: | ||
| GH_AW_SETUP_WORKFLOW_NAME: "Codex PR Review" | ||
| GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/codex-pr-review.lock.yml@${{ github.ref }} | ||
| GH_AW_INFO_VERSION: "0.154.0" | ||
| GH_AW_INFO_AWF_VERSION: "v0.28.23" | ||
| GH_AW_INFO_ENGINE_ID: "codex" | ||
| - name: Download activation artifact | ||
| continue-on-error: true | ||
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | ||
| with: | ||
| name: activation | ||
| path: /tmp/gh-aw | ||
| - name: Download agent output artifact | ||
| id: download-agent-output | ||
| continue-on-error: true | ||
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | ||
| with: | ||
| pattern: "{agent,agent-output-fallback}" | ||
| merge-multiple: true | ||
| path: /tmp/gh-aw/ | ||
| - name: Setup agent output environment variable | ||
| id: setup-agent-output-env | ||
| if: steps.download-agent-output.outcome == 'success' | ||
| run: | | ||
| mkdir -p /tmp/gh-aw/ | ||
| find "/tmp/gh-aw/" -type f -print | ||
| if [ -f "/tmp/gh-aw/agent_output.json" ]; then | ||
| echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" | ||
| fi | ||
| - name: Checkout repository for patch context | ||
| if: needs.agent.outputs.has_patch == 'true' | ||
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 | ||
| with: | ||
| persist-credentials: false | ||
| # --- Threat Detection --- | ||
| - name: Initialize detection execution evidence | ||
| run: | | ||
| mkdir -p "/tmp/gh-aw/threat-detection" | ||
| evidence_tmp="/tmp/gh-aw/threat-detection/execution.json.tmp" | ||
| printf '{"version":1,"component":"detection","run_id":%s,"run_attempt":%s,"state":"not_started"}\n' "$GITHUB_RUN_ID" "$GITHUB_RUN_ATTEMPT" > "$evidence_tmp" | ||
| mv "$evidence_tmp" "/tmp/gh-aw/threat-detection/execution.json" | ||
| - name: Clear inherited Copilot session state | ||
| run: rm -rf /tmp/gh-aw/sandbox/agent/logs/copilot-session-state | ||
| - name: Clean stale firewall files from agent artifact | ||
| run: | | ||
| rm -rf /tmp/gh-aw/sandbox/firewall/logs | ||
| rm -rf /tmp/gh-aw/sandbox/firewall/audit | ||
| - name: Download container images | ||
| run: bash "${RUNNER_TEMP}/gh-aw/actions/download_docker_images.sh" ghcr.io/github/gh-aw-firewall/agent:0.28.23@sha256:2c78aaba1c108e130e2d6d01e4f2cca334ea04c53e6f258913ac34173fe7e3b2 ghcr.io/github/gh-aw-firewall/api-proxy:0.28.23@sha256:c15c3d1208df10c5b588a3657be53742aa982ae0909d1eb1812525268794ca64 ghcr.io/github/gh-aw-firewall/squid:0.28.23@sha256:02ffc56dd40158223064ef03a78c2d9717473c93723b4e403d455ea6f0b09ae0 | ||
| - name: Check if detection needed | ||
| id: detection_guard | ||
| if: always() | ||
| env: | ||
| OUTPUT_TYPES: ${{ needs.agent.outputs.output_types }} | ||
| HAS_PATCH: ${{ needs.agent.outputs.has_patch }} | ||
| run: | | ||
| if [[ -n "$OUTPUT_TYPES" || "$HAS_PATCH" == "true" ]]; then | ||
| echo "run_detection=true" >> "$GITHUB_OUTPUT" | ||
| echo "Detection will run: output_types=$OUTPUT_TYPES, has_patch=$HAS_PATCH" | ||
| else | ||
| echo "run_detection=false" >> "$GITHUB_OUTPUT" | ||
| echo "Detection skipped: no agent outputs or patches to analyze" | ||
| fi | ||
| - name: Clear MCP Config for detection | ||
| if: always() && steps.detection_guard.outputs.run_detection == 'true' | ||
| run: | | ||
| rm -f "${RUNNER_TEMP}/gh-aw/mcp-config/mcp-servers.json" | ||
| rm -f "$HOME/.copilot/mcp-config.json" | ||
| rm -f "$GITHUB_WORKSPACE/.gemini/settings.json" | ||
| - name: Prepare threat detection files | ||
| if: always() && steps.detection_guard.outputs.run_detection == 'true' | ||
| run: | | ||
| bash "${RUNNER_TEMP}/gh-aw/actions/prepare_threat_detection_files.sh" | ||
| - name: Setup threat detection | ||
| if: always() && steps.detection_guard.outputs.run_detection == 'true' | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| env: | ||
| WORKFLOW_NAME: "Codex PR Review" | ||
| WORKFLOW_DESCRIPTION: "No description provided" | ||
| HAS_PATCH: ${{ needs.agent.outputs.has_patch }} | ||
| GH_AW_DETECTION_CONTINUE_ON_ERROR: "true" | ||
| GH_AW_DETECTION_SKIP_PROMPT_SUMMARY: "true" | ||
| with: | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'setup_threat_detection.cjs')); | ||
| await main(); | ||
| - name: Ensure threat-detection directory and log | ||
| if: always() && steps.detection_guard.outputs.run_detection == 'true' | ||
| run: | | ||
| mkdir -p /tmp/gh-aw/threat-detection | ||
| touch /tmp/gh-aw/threat-detection/detection.log | ||
| - name: Install AWF binary | ||
| run: bash "${RUNNER_TEMP}/gh-aw/actions/install_awf_binary.sh" v0.28.23 --rootless | ||
| - name: Setup Node.js | ||
| uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 | ||
| with: | ||
| node-version: '24' | ||
| package-manager-cache: false | ||
| - name: Install Codex CLI | ||
| run: npm install --ignore-scripts -g @openai/codex@0.154.0 | ||
| - name: Prepare Codex config for threat-detect | ||
| if: always() && steps.detection_guard.outputs.run_detection == 'true' | ||
| run: | | ||
| mkdir -p "${RUNNER_TEMP}/gh-aw/mcp-config" "/tmp/gh-aw/mcp-config" "/tmp/gh-aw/mcp-config/logs/" | ||
| printf '%s\n' "{\"mcpServers\":{}}" > "${RUNNER_TEMP}/gh-aw/mcp-config/mcp-servers.json" | ||
| # Point Codex at the AWF OpenAI proxy and disable websocket startup. | ||
| cat > "${RUNNER_TEMP}/gh-aw/mcp-config/config.toml" << GH_AW_CODEX_DETECTION_CONFIG_af28c8b5454431f5_EOF | ||
| model_provider = "openai-proxy" | ||
| [history] | ||
| persistence = "none" | ||
| [model_providers.openai-proxy] | ||
| name = "OpenAI AWF proxy" | ||
| base_url = "http://172.30.0.30:10000" | ||
| api_base = "http://172.30.0.30:10000" | ||
| wss_base = "ws://172.30.0.30:10000" | ||
| env_key = "CODEX_API_KEY" | ||
| wire_api = "responses" | ||
| requires_openai_auth = false | ||
| supports_websockets = false | ||
| GH_AW_CODEX_DETECTION_CONFIG_af28c8b5454431f5_EOF | ||
| cp "${RUNNER_TEMP}/gh-aw/mcp-config/config.toml" "/tmp/gh-aw/mcp-config/config.toml" | ||
| chmod 600 "${RUNNER_TEMP}/gh-aw/mcp-config/config.toml" "/tmp/gh-aw/mcp-config/config.toml" | ||
| - name: Install threat-detect binary | ||
| id: threat_detect_install | ||
| if: always() && steps.detection_guard.outputs.run_detection == 'true' | ||
| continue-on-error: true | ||
| run: | | ||
| bash "${RUNNER_TEMP}/gh-aw/actions/install_threat_detect_binary.sh" v0.5.2 --artifact-base-url https://github.com/github/gh-aw-threat-detection/releases/download --sha256-amd64 b4ecda6a8f1ee09913c40b58e5e9d3337d2173618d41b1bfdef9207e4e7959b9 --sha256-arm64 f6260a0f9ad72bcb67c7af19c4ce262ca34e2c3d5ccbf912832a8bd277200904 | ||
| - name: Execute threat detection with AWF | ||
| id: detection_agentic_execution | ||
| if: always() && steps.detection_guard.outputs.run_detection == 'true' && steps.threat_detect_install.outcome == 'success' | ||
| continue-on-error: true | ||
| timeout-minutes: 10 | ||
| env: | ||
| AWF_REFLECT_ENABLED: 1 | ||
| CODEX_API_KEY: ${{ secrets.CODEX_API_KEY || secrets.OPENAI_API_KEY }} | ||
| CODEX_HOME: /tmp/gh-aw/mcp-config | ||
| GH_AW_HARNESS_MAX_RETRIES: 0 | ||
| GH_AW_LLM_PROVIDER: openai | ||
| GH_AW_MAX_AI_CREDITS: ${{ vars.GH_AW_DEFAULT_DETECTION_MAX_AI_CREDITS || '400' }} | ||
| GH_AW_MAX_TURNS: ${{ vars.GH_AW_DEFAULT_MAX_TURNS || '' }} | ||
| GH_AW_MCP_CONFIG: ${{ runner.temp }}/gh-aw/mcp-config/config.toml | ||
| GH_AW_MODEL_DETECTION_CODEX: gpt-6-astra | ||
| GH_AW_PHASE: detection | ||
| GH_AW_PROMPT: /tmp/gh-aw/aw-prompts/prompt.txt | ||
| GH_AW_VERSION: v0.89.20 | ||
| GITHUB_AW: true | ||
| GITHUB_STEP_SUMMARY: /tmp/gh-aw/agent-step-summary.md | ||
| GIT_AUTHOR_EMAIL: github-actions[bot]@users.noreply.github.com | ||
| GIT_AUTHOR_NAME: github-actions[bot] | ||
| GIT_COMMITTER_EMAIL: github-actions[bot]@users.noreply.github.com | ||
| GIT_COMMITTER_NAME: github-actions[bot] | ||
| OPENAI_API_KEY: ${{ secrets.CODEX_API_KEY || secrets.OPENAI_API_KEY }} | ||
| RUNNER_TEMP: ${{ runner.temp }} | ||
| RUST_LOG: ${{ runner.debug == 1 && 'trace,hyper_util=info,mio=info,reqwest=info,os_info=info,codex_otel=warn,codex_core=debug,codex_exec=debug' || 'warn' }} | ||
| TRACEPARENT: ${{ env.GITHUB_AW_OTEL_TRACE_ID != '' && env.GITHUB_AW_OTEL_PARENT_SPAN_ID != '' && format('00-{0}-{1}-01', env.GITHUB_AW_OTEL_TRACE_ID, env.GITHUB_AW_OTEL_PARENT_SPAN_ID) || '' }} | ||
| WORKFLOW_NAME: "Codex PR Review" | ||
| WORKFLOW_DESCRIPTION: "No description provided" | ||
| HAS_PATCH: ${{ needs.agent.outputs.has_patch }} | ||
| GH_AW_DETECTION_CONTINUE_ON_ERROR: "true" | ||
| run: | | ||
| mkdir -p "/tmp/gh-aw/threat-detection" | ||
| evidence_tmp="/tmp/gh-aw/threat-detection/execution.json.tmp" | ||
| printf '{"version":1,"component":"detection","run_id":%s,"run_attempt":%s,"state":"started"}\n' "$GITHUB_RUN_ID" "$GITHUB_RUN_ATTEMPT" > "$evidence_tmp" | ||
| mv "$evidence_tmp" "/tmp/gh-aw/threat-detection/execution.json" | ||
| export GH_AW_AWF_EXECUTION_COMPONENT="detection" | ||
| export GH_AW_AWF_EXECUTION_EVIDENCE_FILE="/tmp/gh-aw/threat-detection/execution.json" | ||
| set -o pipefail | ||
| printf '%s' "$(date +%s%3N)" > /tmp/gh-aw/agent_cli_start_ms.txt | ||
| (umask 177 && touch /tmp/gh-aw/threat-detection/detection.log) | ||
| GH_AW_MAX_AI_CREDITS="${GH_AW_MAX_AI_CREDITS:-400}" | ||
| if [[ ! "$GH_AW_MAX_AI_CREDITS" =~ ^[0-9]+$ ]]; then | ||
| GH_AW_MAX_AI_CREDITS="400" | ||
| fi | ||
| printf '%s\n' "{\"\$schema\":\"https://github.com/github/gh-aw-firewall/releases/download/v0.28.23/awf-config.schema.json\",\"network\":{\"allowDomains\":[\"172.30.0.1\",\"api.github.com\",\"api.openai.com\",\"chatgpt.com\",\"github.com\",\"host.docker.internal\",\"openai.com\"]},\"apiProxy\":{\"enabled\":true,\"enableTokenSteering\":true,\"maxRuns\":500,\"maxAiCredits\":${GH_AW_MAX_AI_CREDITS},\"maxCacheMisses\":5,\"models\":{\"agent\":[\"sonnet-6x\",\"gpt-6\",\"gpt-5.4\",\"gpt-5.5\",\"gpt-5.6\",\"gpt-5.3\",\"gemini-pro\",\"any\"],\"antigravity\":[\"copilot/antigravity*\",\"google/antigravity*\",\"gemini/antigravity*\"],\"any\":[\"copilot/*\",\"anthropic/*\",\"openai/*\",\"google/*\",\"gemini/*\"],\"auto\":[\"copilot/auto\",\"large\"],\"claude\":[\"agent\"],\"codex\":[\"agent\"],\"coding\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\",\"gpt-5-codex\",\"kimi\"],\"computer-use\":[\"copilot/*computer-use*\",\"google/*computer-use*\",\"gemini/*computer-use*\",\"openai/*computer-use*\"],\"copilot\":[\"agent\"],\"deep-research\":[\"copilot/deep-research*\",\"copilot/o3-deep-research*\",\"copilot/o4-mini-deep-research*\",\"google/deep-research*\",\"gemini/deep-research*\",\"openai/o3-deep-research*\",\"openai/o4-mini-deep-research*\"],\"detection\":[\"small\"],\"evals\":[\"small\"],\"fable\":[\"copilot/*fable*\",\"anthropic/*fable*\"],\"gemini\":[\"agent\"],\"gemini-3-flash\":[\"copilot/gemini-3*flash*\",\"google/gemini-3*flash*\",\"gemini/gemini-3*flash*\"],\"gemini-3-pro\":[\"copilot/gemini-3*pro*\",\"google/gemini-3*pro*\",\"google/nano-banana*\",\"gemini/gemini-3*pro*\"],\"gemini-3.1-flash\":[\"copilot/gemini-3.1*flash*\",\"google/gemini-3.1*flash*\",\"gemini/gemini-3.1*flash*\"],\"gemini-3.1-pro\":[\"copilot/gemini-3.1*pro*\",\"google/gemini-3.1*pro*\",\"gemini/gemini-3.1*pro*\"],\"gemini-3.5-flash\":[\"copilot/gemini-3.5*flash*\",\"google/gemini-3.5*flash*\",\"gemini/gemini-3.5*flash*\"],\"gemini-3.6-flash\":[\"copilot/gemini-3.6*flash*\",\"google/gemini-3.6*flash*\",\"gemini/gemini-3.6*flash*\"],\"gemini-3.7-flash\":[\"copilot/gemini-3.7*flash*\",\"google/gemini-3.7*flash*\",\"gemini/gemini-3.7*flash*\"],\"gemini-3.8-flash\":[\"copilot/gemini-3.8*flash*\",\"google/gemini-3.8*flash*\",\"gemini/gemini-3.8*flash*\"],\"gemini-flash\":[\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"],\"gemini-flash-lite\":[\"copilot/gemini-*flash*lite*\",\"google/gemini-*flash*lite*\",\"gemini/gemini-*flash*lite*\"],\"gemini-omni\":[\"copilot/gemini-omni*\",\"google/gemini-omni*\",\"gemini/gemini-omni*\"],\"gemini-pro\":[\"copilot/gemini-*pro*\",\"google/gemini-*pro*\",\"gemini/gemini-*pro*\"],\"gemma\":[\"copilot/gemma*\",\"google/gemma*\",\"gemini/gemma*\"],\"gpt-5\":[\"copilot/gpt-5*\",\"openai/gpt-5*\"],\"gpt-5-codex\":[\"copilot/gpt-5*codex*\",\"openai/gpt-5*codex*\"],\"gpt-5-mini\":[\"copilot/gpt-5*mini*\",\"openai/gpt-5*mini*\"],\"gpt-5-nano\":[\"copilot/gpt-5*nano*\",\"openai/gpt-5*nano*\"],\"gpt-5-pro\":[\"copilot/gpt-5*pro*\",\"openai/gpt-5*pro*\"],\"gpt-5.1\":[\"copilot/gpt-5.1*\",\"openai/gpt-5.1*\"],\"gpt-5.2\":[\"copilot/gpt-5.2*\",\"openai/gpt-5.2*\"],\"gpt-5.3\":[\"copilot/gpt-5.3*\",\"openai/gpt-5.3*\"],\"gpt-5.4\":[\"copilot/gpt-5.4*\",\"openai/gpt-5.4*\"],\"gpt-5.5\":[\"copilot/gpt-5.5*\",\"openai/gpt-5.5*\"],\"gpt-5.6\":[\"copilot/gpt-5.6*\",\"openai/gpt-5.6*\"],\"gpt-6\":[\"copilot/gpt-6*\",\"openai/gpt-6*\"],\"grok\":[\"copilot/*grok*\",\"openai/*grok*\"],\"haiku\":[\"copilot/*haiku*\",\"anthropic/*haiku*\"],\"image-generation\":[\"copilot/gpt-image*\",\"openai/gpt-image*\",\"openai/chatgpt-image*\",\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"google/imagen*\"],\"kimi\":[\"copilot/kimi*\",\"openai/kimi*\"],\"kiwi\":[\"copilot/kiwi*\",\"openai/kiwi*\"],\"large\":[\"sonnet\",\"gpt-6\",\"gpt-5-pro\",\"gpt-5\",\"gemini-pro\"],\"lyria\":[\"google/lyria*\",\"gemini/lyria*\",\"copilot/lyria*\"],\"mai-code\":[\"copilot/MAI-Code*\",\"copilot/mai-code*\",\"openai/MAI-Code*\"],\"mai-code-1-flash-picker\":[\"copilot/MAI-Code-1-Flash-picker*\",\"copilot/mai-code-1-flash-picker*\",\"openai/MAI-Code-1-Flash-picker*\"],\"mini\":[\"haiku\",\"gpt-5-mini\",\"gpt-5-nano\",\"gemini-flash-lite\"],\"nano-banana\":[\"copilot/nano-banana*\",\"google/nano-banana*\",\"gemini/nano-banana*\"],\"opus\":[\"copilot/*opus*\",\"anthropic/*opus*\"],\"opusplan\":[\"opus?effort=high\"],\"raptor-mini\":[\"copilot/raptor*\",\"openai/raptor*\"],\"reasoning\":[\"copilot/o1*\",\"copilot/o3*\",\"copilot/o4*\",\"openai/o1*\",\"openai/o3*\",\"openai/o4*\"],\"robotics\":[\"copilot/*robotics*\",\"google/*robotics*\",\"gemini/*robotics*\"],\"small\":[\"mini\"],\"small-agent\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash\"],\"sonnet\":[\"copilot/*sonnet*\",\"anthropic/*sonnet*\"],\"sonnet-6x\":[\"copilot/*sonnet-4.5*\",\"copilot/*sonnet-4.6*\",\"copilot/*sonnet-5*\",\"copilot/*sonnet-4-5-*\",\"anthropic/*sonnet-4-5-*\",\"copilot/*sonnet-4-6*\",\"anthropic/*sonnet-4-6*\",\"anthropic/*sonnet-5*\"],\"summarization\":[\"haiku\",\"gpt-5-mini\",\"gemini-flash-lite\",\"mini\"],\"veo\":[\"google/veo*\",\"gemini/veo*\"],\"vision\":[\"copilot/gemini-*image*\",\"google/gemini-*image*\",\"gemini/gemini-*image*\",\"copilot/gemini-*flash*\",\"google/gemini-*flash*\",\"gemini/gemini-*flash*\"]}},\"container\":{\"imageTag\":\"0.28.23,squid=sha256:02ffc56dd40158223064ef03a78c2d9717473c93723b4e403d455ea6f0b09ae0,agent=sha256:2c78aaba1c108e130e2d6d01e4f2cca334ea04c53e6f258913ac34173fe7e3b2,api-proxy=sha256:c15c3d1208df10c5b588a3657be53742aa982ae0909d1eb1812525268794ca64,cli-proxy=sha256:9e31a6e518eba44652b9ae94ce55c3b6958e06290c3b81b08de4174751bb439a\"},\"logging\":{\"proxyLogsDir\":\"/tmp/gh-aw/sandbox/firewall/logs\",\"auditDir\":\"/tmp/gh-aw/sandbox/firewall/audit\"}}" > "${RUNNER_TEMP}/gh-aw/awf-config.json" | ||
| cp "${RUNNER_TEMP}/gh-aw/awf-config.json" /tmp/gh-aw/awf-config.json | ||
| export GH_AW_MODELS_JSON_PATH="/tmp/gh-aw/models.json" | ||
| GH_AW_DOCKER_HOST="" | ||
| if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then | ||
| GH_AW_DOCKER_HOST="${DOCKER_HOST}" | ||
| fi | ||
| if [[ "${DOCKER_HOST:-}" =~ ^tcp:// ]]; then | ||
| _GH_AW_CHROOT_JSON=$(jq -c --arg src "${RUNNER_TEMP}/gh-aw" --arg user "$(id -un)" --argjson uid "$(id -u)" --argjson gid "$(id -g)" --arg home "${RUNNER_TEMP}/gh-aw/home" '.chroot={"binariesSourcePath":$src,"identity":{"user":$user,"uid":$uid,"gid":$gid,"home":$home}}' "${RUNNER_TEMP}/gh-aw/awf-config.json") || { echo "chroot config patch failed" >&2; exit 1; } | ||
| printf '%s\n' "$_GH_AW_CHROOT_JSON" > "${RUNNER_TEMP}/gh-aw/awf-config.json" | ||
| fi | ||
| GH_AW_TOOL_CACHE_MOUNT="" | ||
| GH_AW_TOOL_CACHE="${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}" | ||
| if [ -d "$GH_AW_TOOL_CACHE" ]; then | ||
| if [[ "$GH_AW_TOOL_CACHE" != /opt/* ]]; then | ||
| GH_AW_TOOL_CACHE_MOUNT="$GH_AW_TOOL_CACHE:$GH_AW_TOOL_CACHE:ro" | ||
| fi | ||
| fi | ||
| # shellcheck disable=SC1003,SC2016,SC2086 | ||
| awf --config "${RUNNER_TEMP}/gh-aw/awf-config.json" --container-workdir "${GITHUB_WORKSPACE}" --mount "${RUNNER_TEMP}/gh-aw:${RUNNER_TEMP}/gh-aw:ro" --mount "${RUNNER_TEMP}/gh-aw:/host${RUNNER_TEMP}/gh-aw:ro" ${GH_AW_TOOL_CACHE_MOUNT:+--mount "$GH_AW_TOOL_CACHE_MOUNT"} ${GH_AW_DOCKER_HOST:+--docker-host "$GH_AW_DOCKER_HOST"} --env-all --exclude-env ACTIONS_ID_TOKEN_REQUEST_TOKEN --exclude-env ACTIONS_ID_TOKEN_REQUEST_URL --exclude-env CODEX_API_KEY --exclude-env COPILOT_GITHUB_TOKEN --exclude-env OPENAI_API_KEY --mount /tmp/gh-aw:/tmp/gh-aw:rw --mount /tmp/gh-aw/threat-detection:/tmp/gh-aw/threat-detection:rw --log-level info --skip-pull \ | ||
| -- /bin/bash -c 'set +o histexpand; : "${RUNNER_TOOL_CACHE:?RUNNER_TOOL_CACHE must be set}"; GH_AW_TOOL_CACHE="$RUNNER_TOOL_CACHE"; GH_AW_TOOL_BINS="$(find "$GH_AW_TOOL_CACHE" -maxdepth 5 -type d -name bin 2>/dev/null | tr '\''\n'\'' '\'':'\'')"; GH_AW_TOOL_BINS="${GH_AW_TOOL_BINS%:}"; export PATH="$PATH${GH_AW_TOOL_BINS:+:}$GH_AW_TOOL_BINS"; [ -n "$GOROOT" ] && export PATH="$GOROOT/bin:$PATH" || true; [ -n "$ERLANG_HOME" ] && export PATH="$ERLANG_HOME/bin:$PATH" || true && threat-detect --engine codex --output /tmp/gh-aw/threat-detection/detection_result.json /tmp/gh-aw/threat-detection' 2>&1 | tee -a /tmp/gh-aw/threat-detection/detection.log | ||
| - name: Render detection log | ||
| if: always() && steps.detection_guard.outputs.run_detection == 'true' | ||
| continue-on-error: true | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| with: | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'render_detection_log.cjs')); | ||
| await main(); | ||
| - name: Copy detection firewall logs | ||
| if: always() && steps.detection_guard.outputs.run_detection == 'true' | ||
| continue-on-error: true | ||
| run: | | ||
| mkdir -p /tmp/gh-aw/threat-detection/sandbox/firewall | ||
| if [ -d /tmp/gh-aw/sandbox/firewall/logs ]; then mkdir -p /tmp/gh-aw/threat-detection/sandbox/firewall/logs && cp -r /tmp/gh-aw/sandbox/firewall/logs/. /tmp/gh-aw/threat-detection/sandbox/firewall/logs/; fi | ||
| if [ -d /tmp/gh-aw/sandbox/firewall/audit ]; then mkdir -p /tmp/gh-aw/threat-detection/sandbox/firewall/audit && cp -r /tmp/gh-aw/sandbox/firewall/audit/. /tmp/gh-aw/threat-detection/sandbox/firewall/audit/; fi | ||
| - name: Parse threat detection token usage for step summary | ||
| id: parse_detection_token_usage | ||
| if: always() | ||
| continue-on-error: true | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| env: | ||
| GH_AW_TOKEN_USAGE_SUMMARY_TITLE: Threat Detection Token Usage | ||
| GH_AW_AGENT_USAGE_PATH: /tmp/gh-aw/threat-detection/detection_usage.json | ||
| GH_AW_AGENT_USAGE_JSONL_PATH: /tmp/gh-aw/threat-detection/detection_usage.jsonl | ||
| GH_AW_WRITE_EMPTY_USAGE: "true" | ||
| with: | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'parse_token_usage.cjs')); | ||
| await main(); | ||
| - name: Upload threat detection artifact | ||
| if: always() | ||
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | ||
| with: | ||
| name: detection | ||
| path: | | ||
| /tmp/gh-aw/threat-detection/detection_result.json | ||
| /tmp/gh-aw/threat-detection/execution.json | ||
| /tmp/gh-aw/threat-detection/detection_usage.json | ||
| /tmp/gh-aw/threat-detection/detection_usage.jsonl | ||
| /tmp/gh-aw/threat-detection/sandbox/firewall/logs/ | ||
| /tmp/gh-aw/threat-detection/sandbox/firewall/audit/ | ||
| if-no-files-found: ignore | ||
| - name: Conclude threat detection | ||
| id: detection_conclusion | ||
| if: always() | ||
| continue-on-error: true | ||
| env: | ||
| RUN_DETECTION: ${{ steps.detection_guard.outputs.run_detection }} | ||
| DETECTION_AGENTIC_EXECUTION_OUTCOME: ${{ steps.detection_agentic_execution.outcome }} | ||
| THREAT_DETECT_INSTALL_OUTCOME: ${{ steps.threat_detect_install.outcome }} | ||
| GH_AW_DETECTION_CONTINUE_ON_ERROR: "true" | ||
| run: | | ||
| bash "${RUNNER_TEMP}/gh-aw/actions/conclude_threat_detection.sh" /tmp/gh-aw/threat-detection/detection_result.json | ||
| pre_activation: | ||
| runs-on: ubuntu-slim | ||
| permissions: | ||
| actions: read | ||
| pull-requests: read | ||
| env: | ||
| GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }} | ||
| outputs: | ||
| activated: ${{ steps.check_command_position.outputs.command_position_ok == 'true' }} | ||
| matched_command: ${{ steps.check_command_position.outputs.matched_command }} | ||
| oca_verification_result: ${{ steps.oca_verification.outcome }} | ||
| oca_verified: ${{ steps.oca_verification.outputs.verified }} | ||
| review_rate_limit_ok: ${{ steps.review_rate_limit.outputs.rate_limit_ok }} | ||
| review_rate_limit_result: ${{ steps.review_rate_limit.outcome }} | ||
| setup-parent-span-id: ${{ steps.setup.outputs.parent-span-id || steps.setup.outputs.span-id }} | ||
| setup-span-id: ${{ steps.setup.outputs.span-id }} | ||
| setup-trace-id: ${{ steps.setup.outputs.trace-id }} | ||
| steps: | ||
| - name: Setup Scripts | ||
| id: setup | ||
| uses: github/gh-aw-actions/setup@925900cb40de9cb7652268d0cd14e00f9b7d2189 # v0.89.20 | ||
| with: | ||
| destination: ${{ runner.temp }}/gh-aw/actions | ||
| job-name: ${{ github.job }} | ||
| env: | ||
| GH_AW_SETUP_WORKFLOW_NAME: "Codex PR Review" | ||
| GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/codex-pr-review.lock.yml@${{ github.ref }} | ||
| GH_AW_INFO_VERSION: "0.154.0" | ||
| GH_AW_INFO_AWF_VERSION: "v0.28.23" | ||
| GH_AW_INFO_ENGINE_ID: "codex" | ||
| - name: Check command position | ||
| id: check_command_position | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| env: | ||
| GH_AW_COMMANDS: "[\"codex\"]" | ||
| with: | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'check_command_position.cjs')); | ||
| await main(); | ||
| - name: Check OCA verification | ||
| id: oca_verification | ||
| if: |- | ||
| steps.check_command_position.outputs.command_position_ok == 'true' && (github.event_name != 'pull_request_target' || | ||
| (github.event.pull_request.draft == false && | ||
| (github.event.action != 'labeled' || github.event.label.name == 'OCA Verified'))) | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| with: | ||
| script: | | ||
| core.setOutput('verified', 'false'); | ||
| const pull_number = context.payload.pull_request?.number ?? | ||
| (context.payload.issue?.pull_request ? context.payload.issue.number : undefined); | ||
| if (!pull_number) return; | ||
| // Read current labels for both automatic and requested reviews. | ||
| const { data: pull } = await github.rest.pulls.get({ | ||
| ...context.repo, | ||
| pull_number, | ||
| }); | ||
| core.setOutput('verified', pull.labels.some(label => label.name === 'OCA Verified')); | ||
| - name: Check review rate limit | ||
| id: review_rate_limit | ||
| if: steps.oca_verification.outputs.verified == 'true' | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| env: | ||
| GH_AW_RATE_LIMIT_EVENTS: pull_request_target,issue_comment | ||
| GH_AW_RATE_LIMIT_IGNORED_ROLES: admin,maintain,write | ||
| GH_AW_RATE_LIMIT_MAX: "3" | ||
| GH_AW_RATE_LIMIT_WINDOW: "20" | ||
| with: | ||
| github-token: ${{ secrets.GITHUB_TOKEN }} | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'check_rate_limit.cjs')); | ||
| await main(); | ||
| safe_outputs: | ||
| needs: | ||
| - activation | ||
| - agent | ||
| - detection | ||
| if: (!cancelled()) && needs.agent.result != 'skipped' && needs.detection.result == 'success' | ||
| runs-on: ubuntu-slim | ||
| permissions: | ||
| issues: write | ||
| pull-requests: write | ||
| timeout-minutes: 45 | ||
| env: | ||
| GH_AW_AGENT_AIC: ${{ needs.agent.outputs.aic }} | ||
| GH_AW_AIC: ${{ needs.agent.outputs.aic }} | ||
| GH_AW_AMBIENT_CONTEXT: ${{ needs.agent.outputs.ambient_context }} | ||
| GH_AW_CALLER_WORKFLOW_ID: "${{ github.repository }}/codex-pr-review" | ||
| GH_AW_COMMANDS: "[\"codex\"]" | ||
| GH_AW_DETECTION_CONCLUSION: ${{ needs.detection.outputs.detection_conclusion }} | ||
| GH_AW_DETECTION_REASON: ${{ needs.detection.outputs.detection_reason }} | ||
| GH_AW_ENGINE_ID: "codex" | ||
| GH_AW_ENGINE_MODEL: "gpt-6-astra" | ||
| GH_AW_ENGINE_VERSION: "0.154.0" | ||
| GH_AW_HEAD_SHA: ${{ github.event.pull_request.head.sha }} | ||
| GH_AW_RUNTIME_FEATURES: ${{ vars.GH_AW_RUNTIME_FEATURES }} | ||
| GH_AW_THREAT_DETECTION_AIC: ${{ needs.detection.outputs.aic }} | ||
| GH_AW_WORKFLOW_ID: "codex-pr-review" | ||
| GH_AW_WORKFLOW_NAME: "Codex PR Review" | ||
| GH_AW_WORKFLOW_SOURCE_URL: "${{ github.server_url }}/${{ github.repository }}/blob/${{ github.ref_name }}/.github/workflows/codex-pr-review.md" | ||
| outputs: | ||
| code_push_failure_count: ${{ steps.process_safe_outputs.outputs.code_push_failure_count }} | ||
| code_push_failure_errors: ${{ steps.process_safe_outputs.outputs.code_push_failure_errors }} | ||
| comment_id: ${{ steps.process_safe_outputs.outputs.comment_id }} | ||
| comment_url: ${{ steps.process_safe_outputs.outputs.comment_url }} | ||
| create_discussion_error_count: ${{ steps.process_safe_outputs.outputs.create_discussion_error_count }} | ||
| create_discussion_errors: ${{ steps.process_safe_outputs.outputs.create_discussion_errors }} | ||
| process_safe_outputs_items_applied: ${{ steps.process_safe_outputs.outputs.items_applied }} | ||
| process_safe_outputs_items_cancelled: ${{ steps.process_safe_outputs.outputs.items_cancelled }} | ||
| process_safe_outputs_items_deferred: ${{ steps.process_safe_outputs.outputs.items_deferred }} | ||
| process_safe_outputs_items_failed: ${{ steps.process_safe_outputs.outputs.items_failed }} | ||
| process_safe_outputs_items_skipped: ${{ steps.process_safe_outputs.outputs.items_skipped }} | ||
| process_safe_outputs_items_succeeded: ${{ steps.process_safe_outputs.outputs.items_succeeded }} | ||
| process_safe_outputs_items_warnings: ${{ steps.process_safe_outputs.outputs.items_warnings }} | ||
| process_safe_outputs_processed_count: ${{ steps.process_safe_outputs.outputs.processed_count }} | ||
| process_safe_outputs_status: ${{ steps.process_safe_outputs.outputs.status }} | ||
| steps: | ||
| - name: Setup Scripts | ||
| id: setup | ||
| uses: github/gh-aw-actions/setup@925900cb40de9cb7652268d0cd14e00f9b7d2189 # v0.89.20 | ||
| with: | ||
| destination: ${{ runner.temp }}/gh-aw/actions | ||
| job-name: ${{ github.job }} | ||
| trace-id: ${{ needs.activation.outputs.setup-trace-id }} | ||
| parent-span-id: ${{ needs.activation.outputs.setup-parent-span-id || needs.activation.outputs.setup-span-id }} | ||
| env: | ||
| GH_AW_SETUP_WORKFLOW_NAME: "Codex PR Review" | ||
| GH_AW_CURRENT_WORKFLOW_REF: ${{ github.repository }}/.github/workflows/codex-pr-review.lock.yml@${{ github.ref }} | ||
| GH_AW_INFO_VERSION: "0.154.0" | ||
| GH_AW_INFO_AWF_VERSION: "v0.28.23" | ||
| GH_AW_INFO_ENGINE_ID: "codex" | ||
| - name: Mask OTLP telemetry headers | ||
| run: bash "${RUNNER_TEMP}/gh-aw/actions/mask_otlp_headers.sh" | ||
| - name: Download agent output artifact | ||
| id: download-agent-output | ||
| continue-on-error: true | ||
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 | ||
| with: | ||
| pattern: "{agent,agent-output-fallback}" | ||
| merge-multiple: true | ||
| path: /tmp/gh-aw/ | ||
| - name: Setup agent output environment variable | ||
| id: setup-agent-output-env | ||
| if: steps.download-agent-output.outcome == 'success' | ||
| run: | | ||
| mkdir -p /tmp/gh-aw/ | ||
| find "/tmp/gh-aw/" -type f -print | ||
| if [ -f "/tmp/gh-aw/agent_output.json" ]; then | ||
| echo "GH_AW_AGENT_OUTPUT=/tmp/gh-aw/agent_output.json" >> "$GITHUB_OUTPUT" | ||
| fi | ||
| - name: Configure GH_HOST for enterprise compatibility | ||
| id: ghes-host-config | ||
| shell: bash | ||
| run: | # zizmor: ignore[github-env] - GITHUB_SERVER_URL is set by GitHub Actions, not user input. | ||
| # Derive GH_HOST from GITHUB_SERVER_URL so the gh CLI targets the correct | ||
| # GitHub instance (GHES/GHEC). On github.com this is a harmless no-op. | ||
| GH_HOST="${GITHUB_SERVER_URL#https://}" | ||
| GH_HOST="${GH_HOST#http://}" | ||
| echo "GH_HOST=${GH_HOST}" >> "$GITHUB_ENV" | ||
| - name: Process Safe Outputs | ||
| id: process_safe_outputs | ||
| uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 | ||
| env: | ||
| GH_AW_AGENT_OUTPUT: ${{ steps.setup-agent-output-env.outputs.GH_AW_AGENT_OUTPUT }} | ||
| GH_AW_COMMENT_ID: ${{ needs.activation.outputs.comment_id }} | ||
| GH_AW_ALLOWED_DOMAINS: "api.snapcraft.io,archive.ubuntu.com,azure.archive.ubuntu.com,crl.geotrust.com,crl.globalsign.com,crl.identrust.com,crl.sectigo.com,crl.thawte.com,crl.usertrust.com,crl.verisign.com,crl3.digicert.com,crl4.digicert.com,crls.ssl.com,json-schema.org,json.schemastore.org,keyserver.ubuntu.com,ocsp.digicert.com,ocsp.geotrust.com,ocsp.globalsign.com,ocsp.identrust.com,ocsp.sectigo.com,ocsp.ssl.com,ocsp.thawte.com,ocsp.usertrust.com,ocsp.verisign.com,packagecloud.io,packages.cloud.google.com,packages.microsoft.com,ppa.launchpad.net,s.symcb.com,s.symcd.com,security.ubuntu.com,ts-crl.ws.symantec.com,ts-ocsp.ws.symantec.com,www.googleapis.com" | ||
| GITHUB_SERVER_URL: ${{ github.server_url }} | ||
| GITHUB_API_URL: ${{ github.api_url }} | ||
| GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: "{\"add_comment\":{\"max\":1},\"create_pull_request_review_comment\":{\"max\":50,\"side\":\"RIGHT\"},\"create_report_incomplete_issue\":{},\"missing_data\":{},\"missing_tool\":{},\"noop\":{\"max\":1,\"report-as-issue\":\"false\"},\"report_incomplete\":{},\"submit_pull_request_review\":{\"allowed_events\":[\"COMMENT\"],\"max\":1}}" | ||
| with: | ||
| github-token: ${{ secrets.GH_AW_GITHUB_TOKEN || secrets.GITHUB_TOKEN }} | ||
| script: | | ||
| const path = require('path'); | ||
| const actionsDir = path.join(process.env.RUNNER_TEMP, 'gh-aw', 'actions'); | ||
| const { setupGlobals } = require(path.join(actionsDir, 'setup_globals.cjs')); | ||
| setupGlobals(core, github, context, exec, io, getOctokit); | ||
| const { main } = require(path.join(actionsDir, 'process_safe_outputs.cjs')); | ||
| await main(); | ||
| - name: Upload Safe Outputs Items | ||
| if: always() | ||
| uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 | ||
| with: | ||
| name: safe-outputs-items | ||
| path: | | ||
| /tmp/gh-aw/safe-output-items.jsonl | ||
| /tmp/gh-aw/temporary-id-map.json | ||
| /tmp/gh-aw/safe-output-errors.json | ||
| if-no-files-found: ignore | ||