+190 XP

Codex on GitHub: PR reviews and actions

# Codex on GitHub: PR reviews and actions

Codex can review pull requests and run inside GitHub Actions, so every diff gets an automated read before a human ever opens it. This turns Codex from a thing you invoke by hand into part of your pipeline: a reviewer that comments on style, catches obvious bugs, flags risky changes, and never gets tired at 11pm on a Friday deploy.

This lesson wires that up concretely. You will see the two ways Codex connects to GitHub, a clean workflow that reviews each PR, the exact token permissions involved, and how to stop it from quietly draining your budget.

Two ways Codex meets your repo

There are two distinct integration paths, and mixing them up causes most of the confusion.

The Codex GitHub app (managed). You install Codex from the ChatGPT side and connect your GitHub account. Codex can then be assigned to issues and pull requests directly in the GitHub UI. You mention it, it reads the PR, and it can propose changes or leave review comments. This is the low-effort path: no YAML, no runner, OpenAI hosts the execution.

Codex CLI inside GitHub Actions (self-driven). You run the Codex CLI as a step in your own workflow. This is what you want when you need control: custom prompts, your own secrets, gating on specific file paths, and output that flows into other steps. You own the runner and the logic.

The managed app is faster to adopt. The Actions route is what a serious team ships, because you can version the review logic in the repo itself and reason about exactly what runs. The rest of this lesson focuses on the Actions route.

What "review the diff" actually means

A pull request is a diff plus context. When Codex reviews a PR in Actions, the useful pattern is:

1. The workflow triggers on pull_request.

2. A step computes the diff (the changed lines, not the whole repo).

3. Codex reads the diff with a review prompt.

4. Codex posts a comment back on the PR using the GitHub API.

The critical design choice is what you feed the model. Do not dump the entire repository into context on every PR. That is slow, expensive, and mostly noise. Feed the diff, plus maybe the files the diff touches. The signal is in what changed.

A clean workflow that reviews each PR

Here is a minimal, runnable workflow. It runs on every PR, sends the diff to Codex with a focused review prompt, and posts the result as a single comment.

yaml
name: Codex PR Review
on:
  pull_request:
    types: [opened, synchronize]

permissions:
  contents: read
  pull-requests: write

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Compute diff
        run: |
          git diff origin/${{ github.base_ref }}...HEAD > pr.diff
          echo "Diff size: $(wc -l < pr.diff) lines"

      - name: Review with Codex
        env:
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
        run: |
          npm install -g @openai/codex
          codex exec --skip-git-repo-check \
            "Review the changes in pr.diff. Flag bugs, security \
             issues, and missing tests. Be concise. If it looks \
             good, say so in one line." > review.md

      - name: Post comment
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: gh pr comment ${{ github.event.pull_request.number }} --body-file review.md

A few things worth noticing.

fetch-depth: 0 pulls full history so the git diff against the base branch actually works. Without it you get a shallow clone and the diff breaks.

codex exec runs Codex non-interactively, which is exactly what you want in CI. It reads the prompt, does the work, and exits. The --skip-git-repo-check flag stops it from complaining about the runner's checkout state.

The final step uses gh, the GitHub CLI, which is preinstalled on GitHub-hosted runners. gh pr comment posts the review. No custom API glue needed.

Token permissions, precisely

Two different tokens are in play, and treating them the same is a security mistake.

`GITHUB_TOKEN` is the automatic token GitHub mints for the workflow run. It is scoped by the permissions: block at the top of the file. The block above grants:

  • contents: read so the checkout can read your code.
  • pull-requests: write so gh pr comment can post.

That is the entire footprint. Notice what is missing: no contents: write, no actions: write, nothing that lets the job push code or rewrite the repo. Grant the narrowest set that makes the job work. If your workflow only comments, it never needs write access to code. GitHub's permissions documentation lists every scope.

`OPENAI_API_KEY` is your key for the OpenAI API, stored as a repository or organization secret. It authorizes the Codex calls and is what you get billed against. It has nothing to do with GitHub permissions; it is the model-side credential.

Keep them separate in your head: GITHUB_TOKEN controls what the job can do *to your repo*, OPENAI_API_KEY controls what it can do *with OpenAI* (and what it costs).

Keeping it safe

The dangerous version of this pattern runs on pull_request_target with write permissions and then executes code from the PR. That combination lets a malicious fork run arbitrary commands with your secrets. Do not do it.

The workflow above uses pull_request, not pull_request_target. On the standard pull_request trigger, workflows from forks run with a read-only GITHUB_TOKEN and no access to your secrets, which means the Codex step is skipped for outside contributors. That is the safe default. For internal PRs from branches in your own repo, the secrets are available and the review runs normally.

Three more guardrails:

  • Never let the reviewer execute PR code. Reviewing a diff as text is safe. Running the branch's build scripts or tests with your OPENAI_API_KEY in the environment is how supply-chain attacks happen. Keep review and execution separate.
  • Pin your actions. actions/checkout@v4 is fine for a tag, but for anything third-party, pin to a full commit SHA so a compromised tag cannot inject code.
  • Store the key at the org level with environment protection if multiple repos share it, so you rotate in one place.

Securing GitHub Actions Workflows

Watch on YouTube

Keeping it cheap

Every PR that triggers this workflow makes an API call, and large diffs mean large token counts. A repo with heavy PR traffic can run up real cost if you are careless. Control it at three layers.

Filter what triggers. Only run on the branches and paths that matter. Skip docs-only or generated-file changes:

yaml
on:
  pull_request:
    types: [opened, synchronize]
    paths:
      - "src/**"
      - "!**/*.md"

Now a PR that only touches markdown never spends a token.

Cap the diff you send. A 4,000-line refactor does not need a full-context review comment; the diff itself is the noise. Truncate or reject oversized diffs before the model sees them:

bash
if [ "$(wc -l < pr.diff)" -gt 800 ]; then
  echo "Diff too large for automated review; skipping." > review.md
  exit 0
fi

Debounce on `synchronize`. The synchronize event fires on every push to the PR branch. If someone pushes ten commits in a minute, you get ten reviews. Use concurrency to cancel superseded runs so only the latest push gets reviewed:

yaml
concurrency:
  group: codex-review-${{ github.event.pull_request.number }}
  cancel-in-progress: true

That single block often cuts spend on active PRs by more than half, because you stop paying for reviews of code that was replaced seconds later.

Vérification des acquis

1. What is the primary value of having Codex review pull requests inside GitHub Actions?

2. Why does the lesson recommend feeding Codex the diff (and possibly the files it touches) rather than the entire repository on every PR?

3. According to the lesson, why would a serious team prefer the Codex CLI in GitHub Actions over the managed GitHub app?

CHOIX MULTIPLES

4. Select ALL statements that correctly describe the managed Codex GitHub app path.

Sélectionnez toutes les réponses correctes.

CHOIX MULTIPLES

5. Select ALL steps that match the useful pattern for reviewing a PR in GitHub Actions as described in the lesson.

Sélectionnez toutes les réponses correctes.

Going beyond a single comment

A flat comment is the starting point. Once the plumbing works, the interesting moves are about *where the output goes* and *how structured it is*.

Inline review comments. Instead of one comment on the PR, you can post comments on specific lines using the GitHub review API. This requires mapping Codex's findings back to file paths and line numbers, which is where structured outputs earn their keep: have the model return JSON with path, line, and comment fields, then loop over them and post each with gh api. You already met structured outputs in the API block; this is a clean place to apply them, because "leave a comment on line 42 of auth.py" is only actionable if the model gives you the line number in a parseable shape.

Gating the merge. A review comment is advisory. If you want teeth, have the job exit non-zero when Codex flags something critical, and mark the check as required in branch protection. Be conservative here: a reviewer that blocks merges on style nitpicks gets disabled within a week. Block only on the categories you genuinely care about, like a leaked secret pattern or a removed test.

Feeding richer context selectively. For a PR touching a single module, pulling in that module's full source (not the whole repo) gives Codex enough context to catch "you changed the function signature but not its callers." The rule holds: expand context deliberately, per the files that changed, never blanket.

When to use the managed app instead

If your team is small and you mostly want a competent second opinion on PRs without maintaining YAML, the managed Codex GitHub app is the better call. You assign Codex to a PR and it reviews. You lose the fine control over prompts, gating, and cost filters, but you gain simplicity, and OpenAI handles the runner.

Reach for the Actions route when you need any of: custom review criteria versioned in the repo, integration with other CI steps, strict cost controls, or air-gapped handling of which secrets touch which jobs. Most teams start with the app and graduate to Actions when the review logic becomes something they want to own and tune.

Key Takeaways

  • Use the `pull_request` trigger, not `pull_request_target`, so forked PRs run without your secrets. Never execute PR code in a job that holds your OPENAI_API_KEY.
  • Scope `GITHUB_TOKEN` to the minimum: contents: read and pull-requests: write is enough to review and comment. Keep it separate in your mind from OPENAI_API_KEY, which controls cost.
  • Send the diff, not the repo. Filter triggers by path, cap oversized diffs before the API call, and add a concurrency block to cancel superseded runs on rapid pushes.
  • Use structured outputs (JSON with path and line) when you want inline review comments rather than one summary blob.
  • Start with the managed Codex app; move to Actions when you need versioned review logic, merge gating, or tight cost control.

À faire, tiré de cette leçon

Ces actions sont compilées dans le plan d'action du rôle.

  • Trigger PR-review Actions with pull_request, never pull_request_target
Voir le plan d'action complet