fix(review): honor trusted advisory dispositions #511
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
| name: Codex PR Review | |
| # Runs on PRs AND can be called as a reusable workflow from other repos. | |
| # Consumer repos use: | |
| # uses: QuantStrategyLab/AIAuditBridge/.github/workflows/codex_pr_review.yml@main | |
| # secrets: | |
| # CODEX_AUDIT_SERVICE_URL: ${{ secrets.CODEX_AUDIT_SERVICE_URL }} | |
| on: | |
| pull_request_target: | |
| types: [opened, synchronize, reopened] | |
| workflow_call: | |
| inputs: | |
| caller_concurrency_key: | |
| description: "Stable caller-side key used to cancel stale review jobs for the same PR." | |
| required: false | |
| type: string | |
| allow_unconfigured_backend: | |
| description: "Deprecated compatibility input. The review check always fails closed when no backend is available." | |
| required: false | |
| type: boolean | |
| default: false | |
| api_fallback_enabled: | |
| description: "Optional true/false override for direct API fallback. Reusable callers default to false and do not inherit repository variables." | |
| required: false | |
| type: string | |
| default: "false" | |
| direct_api_primary_enabled: | |
| description: "Optional true/false override for API-only PR review. Reusable callers default to false and do not inherit repository variables." | |
| required: false | |
| type: string | |
| default: "false" | |
| secrets: | |
| CODEX_AUDIT_REUSABLE_WORKFLOW_TOKEN: | |
| description: "Token that can read QuantStrategyLab/AIAuditBridge when this workflow is called from another private repo." | |
| required: false | |
| ANTHROPIC_API_KEY: | |
| required: false | |
| OPENAI_API_KEY: | |
| required: false | |
| CODEX_AUDIT_SERVICE_URL: | |
| required: false | |
| permissions: | |
| contents: read | |
| id-token: write | |
| issues: write | |
| pull-requests: write | |
| concurrency: | |
| group: codex-pr-review-${{ github.repository }}-${{ inputs.caller_concurrency_key || github.event.pull_request.number || github.run_id }} | |
| cancel-in-progress: true | |
| jobs: | |
| review: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 30 | |
| env: | |
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" | |
| steps: | |
| - name: Reject unsupported fork pull requests | |
| if: github.event_name == 'pull_request_target' && github.event.pull_request.head.repo.full_name != github.repository | |
| run: | | |
| echo "::error::Codex review is not configured for fork pull requests; merge remains blocked." >&2 | |
| exit 1 | |
| - name: Checkout review target | |
| uses: actions/checkout@v6 | |
| with: | |
| path: source | |
| ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || github.sha }} | |
| persist-credentials: false | |
| - name: Validate AIAuditBridge self-review ref | |
| if: github.repository == 'QuantStrategyLab/AIAuditBridge' | |
| env: | |
| PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} | |
| run: | | |
| set -euo pipefail | |
| if [ "${GITHUB_EVENT_NAME}" != "pull_request_target" ] || [ -z "${PR_HEAD_SHA}" ]; then | |
| echo "::error::AIAuditBridge self-review requires pull_request_target with a PR head SHA." >&2 | |
| exit 1 | |
| fi | |
| - name: Checkout bridge review scripts | |
| uses: actions/checkout@v6 | |
| with: | |
| repository: ${{ github.repository == 'QuantStrategyLab/AIAuditBridge' && 'QuantStrategyLab/AIAuditBridge' || job.workflow_repository }} | |
| ref: ${{ github.repository == 'QuantStrategyLab/AIAuditBridge' && github.event.pull_request.base.sha || job.workflow_sha }} | |
| path: bridge | |
| token: ${{ secrets.CODEX_AUDIT_REUSABLE_WORKFLOW_TOKEN || github.token }} | |
| persist-credentials: false | |
| - name: Set up Python | |
| uses: actions/setup-python@v6 | |
| with: | |
| python-version: "3.11" | |
| - name: Run Codex PR Review | |
| id: review | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} | |
| ANTHROPIC_MODEL: ${{ vars.ANTHROPIC_MODEL || 'claude-sonnet-4-6' }} | |
| OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} | |
| OPENAI_MODEL: ${{ vars.OPENAI_MODEL || 'gpt-5.4-mini' }} | |
| CODEX_AUDIT_SERVICE_URL: ${{ secrets.CODEX_AUDIT_SERVICE_URL }} | |
| CODEX_AUDIT_SERVICE_AUDIENCE: ${{ vars.CODEX_AUDIT_SERVICE_AUDIENCE || 'quant-codex-audit' }} | |
| CODEX_PR_REVIEW_REPO_ROOT: ${{ github.workspace }}/source | |
| CODEX_PR_REVIEW_REUSABLE_CALL: ${{ github.repository != 'QuantStrategyLab/AIAuditBridge' && 'true' || 'false' }} | |
| CODEX_PR_REVIEW_API_FALLBACK_INPUT: ${{ inputs.api_fallback_enabled }} | |
| CODEX_PR_REVIEW_DIRECT_API_PRIMARY_INPUT: ${{ inputs.direct_api_primary_enabled }} | |
| CODEX_PR_REVIEW_API_FALLBACK_DEFAULT: ${{ vars.CODEX_PR_REVIEW_API_FALLBACK_ENABLED || 'true' }} | |
| CODEX_PR_REVIEW_DIRECT_API_PRIMARY_DEFAULT: ${{ vars.CODEX_PR_REVIEW_DIRECT_API_PRIMARY_ENABLED || 'true' }} | |
| working-directory: source | |
| run: | | |
| set -euo pipefail | |
| bridge_script="${GITHUB_WORKSPACE}/bridge/scripts/run_codex_pr_review.py" | |
| if [ -f "${bridge_script}" ]; then | |
| script_path="${bridge_script}" | |
| else | |
| echo "::error::Trusted Codex review script not found. Ensure the bridge checkout can read QuantStrategyLab/AIAuditBridge." >&2 | |
| exit 1 | |
| fi | |
| resolve_boolean() { | |
| local name="$1" requested="$2" fallback="$3" value | |
| if [ "${CODEX_PR_REVIEW_REUSABLE_CALL}" = "true" ]; then | |
| # Only consumers reach this branch; their explicit/default input is authoritative. | |
| value="${requested}" | |
| else | |
| # AIAuditBridge self-review has no workflow_call inputs; retain its local policy. | |
| value="${fallback}" | |
| fi | |
| value="$(printf '%s' "${value}" | tr '[:upper:]' '[:lower:]')" | |
| case "${value}" in | |
| true|false) printf '%s' "${value}" ;; | |
| *) echo "::error::${name} must be true or false" >&2; return 1 ;; | |
| esac | |
| } | |
| if ! api_fallback_enabled="$(resolve_boolean CODEX_PR_REVIEW_API_FALLBACK_ENABLED "${CODEX_PR_REVIEW_API_FALLBACK_INPUT}" "${CODEX_PR_REVIEW_API_FALLBACK_DEFAULT}")"; then | |
| exit 1 | |
| fi | |
| if ! direct_api_primary_enabled="$(resolve_boolean CODEX_PR_REVIEW_DIRECT_API_PRIMARY_ENABLED "${CODEX_PR_REVIEW_DIRECT_API_PRIMARY_INPUT}" "${CODEX_PR_REVIEW_DIRECT_API_PRIMARY_DEFAULT}")"; then | |
| exit 1 | |
| fi | |
| CODEX_PR_REVIEW_API_FALLBACK_ENABLED="${api_fallback_enabled}" \ | |
| CODEX_PR_REVIEW_DIRECT_API_PRIMARY_ENABLED="${direct_api_primary_enabled}" \ | |
| timeout --signal=TERM --kill-after=60s 25m python -I "${script_path}" | |
| - name: Upload review diagnostics | |
| if: always() | |
| uses: actions/upload-artifact@v7 | |
| with: | |
| name: codex-pr-review-${{ github.event.pull_request.number || github.run_id }}-${{ github.run_id }} | |
| path: source/data/output/codex_pr_review/ | |
| if-no-files-found: warn |