Português

Executar o Codex Security em CI

Analise alterações de pull requests e merge requests, preserve resultados estruturados, carregue SARIF e defina uma política de gravidade.

Execute a CLI do Codex Security em CI para rever as alterações exatas num pull request ou merge request, conservar as conclusões e a cobertura e, opcionalmente, fazer a verificação falhar a partir de uma gravidade escolhida. Comece com resultados consultivos, reveja a qualidade e o tempo de execução da análise e, em seguida, adicione uma política de gravidade adequada ao seu repositório.

Este guia inclui exemplos para GitHub Actions e GitLab CI/CD. Os mesmos comandos de análise e exportação funcionam noutros sistemas de CI.

Preparar o fluxo de trabalho

Guarde uma API key da OpenAI no armazenamento de segredos do seu fornecedor de CI como CODEX_SECURITY_API_KEY.

Mapeie este segredo diretamente para a variável de ambiente OPENAI_API_KEY do passo de análise. Restrinja a credencial ao processo de análise e utilize --auth api-key para a selecionar explicitamente.

O executor necessita de:

  • Node.js 22 ou posterior.
  • Python 3.10 ou posterior.
  • O pacote @openai/codex-security publicado, instalado fora da cópia de trabalho do repositório.
  • O histórico da cabeça e da base do pull request ou merge request para que o Git possa calcular a base de intercalação.

Adicionar o fluxo de trabalho do GitHub Actions

Para repositórios privados ou internos, ative o GitHub Code Security antes de carregar SARIF.

Crie .github/workflows/codex-security.yml. Antes de obter o pull request, instale @openai/codex-security em $RUNNER_TEMP/codex-security para que o executável fidedigno esteja disponível em $RUNNER_TEMP/codex-security/node_modules/.bin/codex-security:

name: Codex Security scan

on:
  pull_request:

jobs:
  codex-security:
    if: github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]'
    runs-on: ubuntu-latest
    permissions:
      actions: read
      contents: read
      security-events: write
    steps:
      - name: Set up Node.js
        uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
        with:
          node-version: "26"

      - name: Set up Python
        uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7
        with:
          python-version: "3.14"

      - name: Install Codex Security
        run: |
          set -euo pipefail
          npm install \
            --prefix "$RUNNER_TEMP/codex-security" \
            --ignore-scripts \
            --no-audit \
            --no-fund \
            @openai/codex-security

      - name: Verify Codex Security
        env:
          CODEX_SECURITY_BIN: ${{ runner.temp }}/codex-security/node_modules/.bin/codex-security
        run: |
          set -euo pipefail
          test -x "$CODEX_SECURITY_BIN"
          "$CODEX_SECURITY_BIN" --version

      - name: Check out the pull request
        uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
        with:
          ref: ${{ github.event.pull_request.head.sha }}
          fetch-depth: 0
          persist-credentials: false

      - name: Scan the pull request
        env:
          OPENAI_API_KEY: ${{ secrets.CODEX_SECURITY_API_KEY }}
          CODEX_SECURITY_BIN: ${{ runner.temp }}/codex-security/node_modules/.bin/codex-security
          CODEX_SECURITY_STATE_DIR: ${{ runner.temp }}/codex-security-state
          BASE_SHA: ${{ github.event.pull_request.base.sha }}
          HEAD_SHA: ${{ github.event.pull_request.head.sha }}
          SCAN_DIR: ${{ runner.temp }}/codex-security-results
        run: |
          set -euo pipefail
          BASE_REVISION="$(git merge-base "$BASE_SHA" "$HEAD_SHA")"
          "$CODEX_SECURITY_BIN" scan . \
            --diff "$BASE_REVISION" \
            --head "$HEAD_SHA" \
            --auth api-key \
            --output-dir "$SCAN_DIR" \
            --json > "$RUNNER_TEMP/codex-security.json"

      - name: Export SARIF
        id: export-sarif
        if: always()
        env:
          CODEX_SECURITY_BIN: ${{ runner.temp }}/codex-security/node_modules/.bin/codex-security
          SCAN_DIR: ${{ runner.temp }}/codex-security-results
          SARIF_FILE: ${{ runner.temp }}/codex-security.sarif
        run: |
          set -euo pipefail
          if test -f "$SCAN_DIR/scan-manifest.json"; then
            "$CODEX_SECURITY_BIN" export "$SCAN_DIR" \
              --export-format sarif \
              --source-root "$GITHUB_WORKSPACE" \
              --output "$SARIF_FILE"
            echo "available=true" >> "$GITHUB_OUTPUT"
          fi

      - name: Upload SARIF
        if: always() && steps.export-sarif.outputs.available == 'true'
        uses: github/codeql-action/upload-sarif@e4fba868fa4b1b91e1fdab776edc8cfbe6e9fb81 # v4
        with:
          sarif_file: ${{ runner.temp }}/codex-security.sarif
          ref: refs/pull/${{ github.event.pull_request.number }}/head
          sha: ${{ github.event.pull_request.head.sha }}
          category: codex-security

      - name: Preserve scan results
        if: always()
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
        with:
          name: codex-security-results
          path: |
            ${{ runner.temp }}/codex-security-results
            ${{ runner.temp }}/codex-security.json
          if-no-files-found: warn
          retention-days: 7

O fluxo de trabalho obtém a cabeça do pull request, calcula a respetiva base de intercalação e analisa as alterações consolidadas entre essas revisões. O histórico completo mantém o alvo exato. persist-credentials: false mantém o token do repositório fora da configuração do Git da cópia de trabalho. Instalar a CLI antes da obtenção e executá-la através do caminho absoluto mantém os executáveis controlados pelo repositório afastados da credencial de análise. --auth api-key seleciona explicitamente a API key restrita. A análise guarda o respetivo histórico num diretório de estado gravável fora do repositório.

--json escreve um documento JSON completo em stdout, para que o fluxo de trabalho o possa guardar diretamente. O progresso, os resumos de conclusão e os erros permanecem em stderr. Isto difere de codex exec --json, que emite um fluxo de eventos JSON Lines.

O passo de exportação lê uma análise concluída e selada e escreve SARIF. Não altera o runtime nem as credenciais do Codex. Os artefactos de análise podem conter excertos de código-fonte vulnerável, provas e detalhes de correção. Escolha controlos de acesso e um período de retenção curto adequados ao seu repositório.

Adicionar o pipeline do GitLab CI/CD

O GitLab pode ingerir relatórios SARIF 2.1.0 no GitLab Ultimate 19.2 ou posterior. Adicione uma variável de CI/CD CODEX_SECURITY_API_KEY mascarada e oculta antes de executar o pipeline.

Adicione a fase security e a tarefa do Codex Security ao .gitlab-ci.yml raiz. Mantenha quaisquer fases e tarefas existentes no ficheiro. Por predefinição, o exemplo analisa as alterações do merge request. Defina CODEX_SECURITY_FULL_SCAN_DEFAULT_BRANCH como "true" para analisar também o ramo predefinido completo:

variables:
  CODEX_SECURITY_FULL_SCAN_DEFAULT_BRANCH: "false"

stages:
  - test
  - security

codex-security:
  stage: security
  image: node:26-bookworm-slim
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_SOURCE_PROJECT_ID == $CI_PROJECT_ID'
      variables:
        CODEX_SECURITY_SCAN_SCOPE: "diff"
    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CODEX_SECURITY_FULL_SCAN_DEFAULT_BRANCH == "true"'
      variables:
        CODEX_SECURITY_SCAN_SCOPE: "full"
  variables:
    GIT_DEPTH: "0"
    CODEX_SECURITY_CLI_DIR: "/tmp/codex-security-cli"
  before_script:
    - |
      set -eu
      apt-get update -qq
      apt-get install -y -qq --no-install-recommends \
        ca-certificates \
        git \
        python3 \
        ripgrep
      npm install \
        --prefix "$CODEX_SECURITY_CLI_DIR" \
        --ignore-scripts \
        --no-audit \
        --no-fund \
        @openai/codex-security
      export CODEX_SECURITY_BIN="$CODEX_SECURITY_CLI_DIR/node_modules/.bin/codex-security"
      test -x "$CODEX_SECURITY_BIN"
      "$CODEX_SECURITY_BIN" --version
  script:
    - |
      set -eu
      if test -z "${CODEX_SECURITY_API_KEY:-}"; then
        echo "Set the CODEX_SECURITY_API_KEY CI/CD variable." >&2
        exit 2
      fi

      codex_security_api_key="$CODEX_SECURITY_API_KEY"
      unset CODEX_SECURITY_API_KEY

      case "${CODEX_SECURITY_SCAN_SCOPE:-}" in
        diff)
          BASE_SHA="$CI_MERGE_REQUEST_DIFF_BASE_SHA"
          HEAD_SHA="$CI_COMMIT_SHA"
          BASE_REVISION="$(git merge-base "$BASE_SHA" "$HEAD_SHA")"
          set -- --diff "$BASE_REVISION" --head "$HEAD_SHA"
          echo "Scanning committed changes from $BASE_REVISION to $HEAD_SHA."
          ;;
        full)
          set -- --mode standard
          echo "Scanning the complete default branch at $CI_COMMIT_SHA."
          ;;
        *)
          echo "Unsupported Codex Security scan scope: ${CODEX_SECURITY_SCAN_SCOPE:-unset}" >&2
          exit 2
          ;;
      esac

      export CODEX_SECURITY_STATE_DIR="/tmp/codex-security-state-$CI_JOB_ID"
      SCAN_DIR="/tmp/codex-security-results-$CI_JOB_ID"
      JSON_FILE="/tmp/codex-security-$CI_JOB_ID.json"
      SARIF_FILE="/tmp/codex-security-$CI_JOB_ID.sarif"

      install -d -m 700 "$CODEX_SECURITY_STATE_DIR" "$SCAN_DIR"

      set +e
      OPENAI_API_KEY="$codex_security_api_key" \
        "$CODEX_SECURITY_BIN" scan . \
          "$@" \
          --auth api-key \
          --output-dir "$SCAN_DIR" \
          --json > "$JSON_FILE"
      scan_exit="$?"
      set -e
      unset codex_security_api_key

      install -d -m 700 codex-security-artifacts/results
      cp -R "$SCAN_DIR"/. codex-security-artifacts/results/
      if test -s "$JSON_FILE"; then
        cp "$JSON_FILE" codex-security-artifacts/codex-security.json
      fi
      printf '%s\n' "$scan_exit" > codex-security-artifacts/scan-exit-code.txt

      export_exit=0
      if test -f "$SCAN_DIR/scan-manifest.json"; then
        set +e
        "$CODEX_SECURITY_BIN" export "$SCAN_DIR" \
          --export-format sarif \
          --source-root "$CI_PROJECT_DIR" \
          --output "$SARIF_FILE"
        export_exit="$?"
        set -e
        if test -s "$SARIF_FILE"; then
          cp "$SARIF_FILE" codex-security-artifacts/codex-security.sarif
        fi
      fi

      if test "$scan_exit" -ne 0; then
        exit "$scan_exit"
      fi
      exit "$export_exit"
  artifacts:
    when: always
    access: maintainer
    expire_in: 7 days
    paths:
      - codex-security-artifacts/
    reports:
      sarif: codex-security-artifacts/codex-security.sarif

Por predefinição, a tarefa é executada apenas para merge requests provenientes de ramos do mesmo projeto, pelo que os pipelines de forks não recebem a credencial de análise. Defina CODEX_SECURITY_FULL_SCAN_DEFAULT_BRANCH como "true" ao nível do grupo, projeto ou pipeline para executar também uma análise completa normal no ramo predefinido. As análises completas demoram mais tempo e custam mais do que as análises de diferenças.

GIT_DEPTH: "0" fornece o histórico necessário para calcular a base de intercalação a partir de CI_MERGE_REQUEST_DIFF_BASE_SHA e CI_COMMIT_SHA nas análises de merge requests.

A tarefa instala a CLI em /tmp, executa-a através do caminho absoluto e expõe a API key apenas ao processo de análise. artifacts: when: always preserva o relatório SARIF quando a análise falha, enquanto artifacts:access: maintainer limita o acesso a resultados detalhados da análise.

As alterações a .gitlab-ci.yml podem expor variáveis de CI/CD, pelo que deve rever as alterações do pipeline antes de executar a tarefa. Se proteger CODEX_SECURITY_API_KEY, o GitLab disponibiliza-a apenas para merge requests do mesmo projeto entre ramos protegidos e apenas quando o utilizador pode aceder ao ramo de destino.

Escolher uma política de gravidade

Ambos os exemplos apenas produzem relatórios porque omitem --fail-on-severity. Quando estiver preparado para que as conclusões afetem a verificação, adicione um limiar ao comando de análise:

"$CODEX_SECURITY_BIN" scan . \
  --diff origin/main \
  --output-dir /path/outside/repository/results \
  --fail-on-severity high

Os limiares suportados são critical, high, medium e low. Um limiar inclui conclusões dessa gravidade e superiores.

O passo de análise utiliza estes códigos de saída:

Saída Significado
0 A análise foi concluída com cobertura completa e qualquer política configurada foi satisfeita.
1 A análise concluída contém uma conclusão com gravidade igual ou superior ao limiar.
2 A CLI encontrou um erro de entrada ou de runtime, ou a análise concluída tem cobertura incompleta.
130 Ctrl-C interrompeu a análise.
143 SIGTERM terminou a análise.

Uma análise com cobertura partial ou unknown devolve 2, mesmo sem uma política de gravidade. A CLI continua a escrever as conclusões e a cobertura disponíveis. Reveja as áreas adiadas em coverage.json antes de considerar a verificação conclusiva.

Repetir com um diretório de resultados existente

Utilize um diretório de executor novo para cada tarefa de CI. Num executor persistente ou autoalojado, preserve um resultado anterior com --archive-existing:

"$CODEX_SECURITY_BIN" scan . \
  --diff origin/main \
  --output-dir /path/outside/repository/results \
  --archive-existing

O comando arquiva os resultados anteriores e começa com um diretório de análise vazio.

Resolver problemas de uma análise em CI

  • Referência Git desconhecida ou diferença inesperada: Obtenha o histórico da base e da cabeça, calcule a base de intercalação e forneça explicitamente ambas as revisões.
  • Diretório de saída protegido ou não vazio: Escolha um diretório privado fora da árvore de trabalho Git envolvente. Utilize --archive-existing quando o diretório já contiver resultados.
  • Credenciais em falta: Confirme que CODEX_SECURITY_API_KEY está disponível para o fluxo de trabalho ou pipeline fidedigno e diretamente mapeada para a variável de ambiente OPENAI_API_KEY do processo de análise.
  • Erro no histórico da análise: Defina CODEX_SECURITY_STATE_DIR como um diretório gravável fora do repositório.
  • Erro de configuração do Python: Confirme que o executor utiliza Python 3.10 ou posterior.
  • Cobertura incompleta: Reveja coverage.json, incluindo superfícies adiadas e questões em aberto, e volte a executar com um alvo ou ambiente adequado.
  • Erro de exportação SARIF: Confirme que a análise foi concluída e que o diretório completo da análise está disponível. A exportação valida os artefactos selados antes de escrever SARIF.
  • Erro de carregamento SARIF: Para GitHub Actions, confirme que a sua organização ativou o GitHub Code Security para o repositório e que o fluxo de trabalho concede actions: read, contents: read e security-events: write. Para GitLab CI/CD, confirme que o projeto utiliza GitLab Ultimate 19.2 ou posterior e que a tarefa carrega um ficheiro SARIF 2.1.0 através de artifacts:reports:sarif.

Para todos os comandos, sinalizadores, artefactos e campos de saída, consulte a referência da CLI. Para uma revisão interativa de CI baseada em plugins, consulte Rever alterações de código quanto à segurança.