Skip to content

fix(review): honor trusted advisory dispositions #511

fix(review): honor trusted advisory dispositions

fix(review): honor trusted advisory dispositions #511

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