GitHub Actions

Review pull-request diffs with a repository-bound OIDC identity and a persistent package cache.

1. Trust the repository

  1. Open the project that owns the adversaries, then open CI / OIDC.
  2. Choose GitHub Actions and trust either owner/repository or owner/*.
  3. Choose Pull. Publishing uses a separate grant.
  4. For stronger rename protection, add the numeric GitHub repository or organization ID.

2. Add the workflow

.github/workflows/adversary.yml
name: Adversary review

on:
  pull_request:

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

jobs:
  review:
    # Fork PRs and Dependabot runs cannot read repository secrets.
    if: github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]'
    runs-on: ubuntu-24.04
    timeout-minutes: 30
    permissions:
      contents: read
      id-token: write
      pull-requests: write

    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
          persist-credentials: false

      - name: Restore adversary packages
        uses: actions/cache@v4
        with:
          path: ${{ runner.temp }}/adversary-data
          key: adversary-${{ runner.os }}-${{ github.event.repository.id }}-v1-${{ github.sha }}
          restore-keys: |
            adversary-${{ runner.os }}-${{ github.event.repository.id }}-v1-

      - name: Run adversaries
        uses: doomerlabs/actions/run@v1
        with:
          adversaries: auto
          path: .
          data-dir: ${{ runner.temp }}/adversary-data
          timeout-minutes: 20
          auth-mode: oidc
          registry-namespace: your-project-slug
          model-provider: openai
          model: your-model-id
          model-api-key: ${{ secrets.OPENAI_API_KEY }}
          fail-on-findings: false
  • id-token: write lets the job request the GitHub OIDC identity. It does not grant source write access.
  • pull-requests: write lets the action submit inline review findings.
  • fetch-depth: 0 lets the CLI resolve the pull-request merge base.
  • The cache is repository-specific because it may contain private adversary package contents.

Service-account fallback

If OIDC is unavailable, create a service account under the project's Service accounts settings with registry:pull, save it as ADVERSARY_SERVICE_ACCOUNT_TOKEN, and replace the action's auth inputs:

.github/workflows/adversary.yml
- name: Run adversaries
  uses: doomerlabs/actions/run@v1
  with:
    adversaries: auto
    auth-mode: token
    token: ${{ secrets.ADVERSARY_SERVICE_ACCOUNT_TOKEN }}
    registry-namespace: your-project-slug
    timeout-minutes: 20

Service accounts are long-lived and are not repository-bound. They do not enable repository feedback memory.

Fork pull requests and Dependabot

GitHub does not pass repository secrets to workflows triggered by a fork, and Dependabot pull requests receive the same restricted treatment. The example skips the model-backed review job for both, so it does not fail with a missing model credential.

To review one of these changes, a maintainer can run the adversaries locally or inspect the change and reproduce it on a branch in the base repository. Approving and rerunning a fork workflow does not make repository secrets available. Do not switch this workflow to pull_request_target and check out the fork: that would expose privileged credentials while processing untrusted code.

What makes the check fail?

Findings are informational by default because fail-on-findings is false. Authentication, download, configuration, execution, and wall-clock timeout failures still fail the job. Increase timeout-minutes for cold caches or large automatic review sets.

Reviews without this workflow

Install the GitHub App from Repos to get hosted pull-request reviews with hosted inference. That path does not add a workflow file or a repository model key. See Hosted reviews.