Reusable Codex AI review gate for any repo
indexable-inc/index/.github/workflows/ai-review-gate.yml@main is a workflow_call reviewer that any repo can mount as the default AI review on main. The current implementation runs openai/codex-action against a JSON schema, posts each finding as a GitHub review suggestion with a suggested_replacement, and reports an overall_correctness verdict that becomes the final gate.
jobs:
ai-review-gate:
permissions:
actions: read
checks: read
contents: read
issues: write
pull-requests: write
uses: indexable-inc/index/.github/workflows/ai-review-gate.yml@main
with:
caller_event_name: ${{ github.event_name }}
required_check_name: ai review approved
secrets:
openai_api_key: ${{ secrets.OPENAI_API_KEY }}
repository_token: ${{ secrets.GITHUB_TOKEN }} Same-repo PRs from regular users run the secret-backed reviewer. Fork and Dependabot PRs stay on a no-secret path until a trusted maintainer approves the current head SHA, so a forked PR cannot edit the prompt and reach the OpenAI key. The reviewer instruction files (AGENTS.md and CLAUDE.md) are restored from the trusted base commit before Codex runs, so a PR that rewrites them cannot bend the reviewer’s rules.
The structured output keeps each finding mechanically actionable: title, body, confidence_score, priority, code_location.{relative_file_path, line_range}, and a suggested_replacement GitHub renders as a one-click apply. AI_REVIEW_MODEL and AI_REVIEW_EFFORT are repo variables, with xhigh reasoning effort as the default.
{
"findings": [
{
"title": "fork PRs can leak OPENAI_API_KEY",
"priority": 0,
"code_location": { "relative_file_path": ".github/workflows/foo.yml", "line_range": {"start": 12, "end": 18} },
"suggested_replacement": "...",
"confidence_score": 0.92
}
],
"overall_correctness": "patch is incorrect"
} Direct users can require the ai review approved check. Reusable-workflow callers should require GitHub’s called-job check name, such as ai-review-gate / ai review approved for the example above. The gate only passes when the reviewer returns a well-formed JSON document and votes patch is correct; missing or malformed output fails closed.