Deutsch

Codex Security in CI ausführen

Änderungen aus Pull Requests und Merge Requests scannen, strukturierte Ergebnisse aufbewahren, SARIF hochladen und eine Schweregradrichtlinie festlegen.

Führen Sie die Codex Security CLI in CI aus, um genau die Änderungen in einem Pull Request oder Merge Request zu prüfen, Befunde und Abdeckung beizubehalten und die Prüfung optional ab einem ausgewählten Schweregrad fehlschlagen zu lassen. Beginnen Sie mit informativen Ergebnissen, prüfen Sie Scanqualität und Laufzeit und fügen Sie anschließend eine zu Ihrem Repository passende Schweregradrichtlinie hinzu.

Dieser Leitfaden enthält Beispiele für GitHub Actions und GitLab CI/CD. Dieselben Scan- und Exportbefehle funktionieren auch in anderen CI-Systemen.

Workflow vorbereiten

Speichern Sie einen OpenAI API key im Secret-Speicher Ihres CI-Anbieters als CODEX_SECURITY_API_KEY.

Ordnen Sie dieses Secret direkt der Umgebungsvariable OPENAI_API_KEY des Scan-Schritts zu. Beschränken Sie die Anmeldedaten auf den Scanprozess und verwenden Sie --auth api-key, um sie ausdrücklich auszuwählen.

Der Runner benötigt:

  • Node.js 22 oder höher.
  • Python 3.10 oder höher.
  • Das veröffentlichte Paket @openai/codex-security, das außerhalb des Repository-Checkouts installiert ist.
  • Den Verlauf des Head- und Base-Branches des Pull Requests oder Merge Requests, damit Git die Merge-Basis berechnen kann.

GitHub-Actions-Workflow hinzufügen

Aktivieren Sie für private oder interne Repositorys GitHub Code Security, bevor Sie SARIF hochladen.

Erstellen Sie .github/workflows/codex-security.yml. Installieren Sie vor dem Auschecken des Pull Requests @openai/codex-security unter $RUNNER_TEMP/codex-security, damit die vertrauenswürdige ausführbare Datei unter $RUNNER_TEMP/codex-security/node_modules/.bin/codex-security verfügbar ist:

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

Der Workflow checkt den Head des Pull Requests aus, berechnet dessen Merge-Basis und scannt die committeten Änderungen zwischen diesen Revisionen. Der vollständige Verlauf stellt sicher, dass das Ziel exakt ist. persist-credentials: false hält das Repository-Token aus der ausgecheckten Git-Konfiguration heraus. Indem die CLI vor dem Checkout installiert und über ihren absoluten Pfad ausgeführt wird, bleiben vom Repository kontrollierte ausführbare Dateien von den Scan-Anmeldedaten getrennt. --auth api-key wählt den eingeschränkten API key ausdrücklich aus. Der Scan speichert seinen Verlauf in einem beschreibbaren Zustandsverzeichnis außerhalb des Repositorys.

--json schreibt ein vollständiges JSON-Dokument nach stdout, sodass der Workflow es direkt speichern kann. Fortschritt, Abschlusszusammenfassungen und Fehler verbleiben auf stderr. Dies unterscheidet sich von codex exec --json, das einen JSON-Lines-Ereignisstrom ausgibt.

Der Exportschritt liest einen abgeschlossenen, versiegelten Scan und schreibt SARIF. Die Codex-Laufzeit und die Anmeldedaten bleiben unverändert. Scan-Artefakte können anfällige Quelltextausschnitte, Nachweise und Details zur Behebung enthalten. Wählen Sie Zugriffskontrollen und ein kurzes Aufbewahrungsfenster, die für Ihr Repository angemessen sind.

GitLab-CI/CD-Pipeline hinzufügen

GitLab kann SARIF-2.1.0-Berichte ab GitLab Ultimate 19.2 verarbeiten. Fügen Sie eine maskierte und ausgeblendete CI/CD-Variable CODEX_SECURITY_API_KEY hinzu, bevor Sie die Pipeline ausführen.

Fügen Sie die Stufe security und den Codex-Security-Job zur .gitlab-ci.yml im Stammverzeichnis hinzu. Behalten Sie alle vorhandenen Stufen und Jobs in der Datei bei. Das Beispiel scannt standardmäßig Änderungen aus Merge Requests. Setzen Sie CODEX_SECURITY_FULL_SCAN_DEFAULT_BRANCH auf "true", um zusätzlich den vollständigen Standard-Branch zu scannen:

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

Standardmäßig wird der Job nur für Merge Requests aus Branches desselben Projekts ausgeführt, sodass Fork-Pipelines keine Scan-Anmeldedaten erhalten. Setzen Sie CODEX_SECURITY_FULL_SCAN_DEFAULT_BRANCH auf Gruppen-, Projekt- oder Pipeline-Ebene auf "true", um zusätzlich einen regulären vollständigen Scan auf dem Standard-Branch auszuführen. Vollständige Scans dauern länger und kosten mehr als Diff-Scans.

GIT_DEPTH: "0" stellt den Verlauf bereit, der benötigt wird, um bei Merge-Request-Scans die Merge-Basis aus CI_MERGE_REQUEST_DIFF_BASE_SHA und CI_COMMIT_SHA zu berechnen.

Der Job installiert die CLI unter /tmp, führt sie über ihren absoluten Pfad aus und stellt den API key nur dem Scanprozess bereit. artifacts: when: always bewahrt den SARIF- Bericht auf, wenn der Scan fehlschlägt, während artifacts:access: maintainer den Zugriff auf detaillierte Scanergebnisse beschränkt.

Änderungen an .gitlab-ci.yml können CI/CD-Variablen offenlegen. Prüfen Sie daher Pipeline- Änderungen, bevor Sie den Job ausführen. Wenn Sie CODEX_SECURITY_API_KEY schützen, stellt GitLab die Variable nur für projektinterne Merge Requests zwischen geschützten Branches bereit und nur dann, wenn der Benutzer auf den Ziel-Branch zugreifen kann.

Schweregradrichtlinie auswählen

Beide Beispiele dienen nur der Berichterstellung, da sie --fail-on-severity weglassen. Sobald Befunde die Prüfung beeinflussen sollen, fügen Sie dem Scanbefehl einen Schwellenwert hinzu:

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

Die unterstützten Schwellenwerte sind critical, high, medium und low. Ein Schwellenwert umfasst Befunde dieses und höherer Schweregrade.

Der Scan-Schritt verwendet diese Exitcodes:

Exit Bedeutung
0 Der Scan wurde mit vollständiger Abdeckung abgeschlossen und alle konfigurierten Richtlinien wurden erfüllt.
1 Der abgeschlossene Scan enthält einen Befund auf oder über dem Schwellenwert.
2 Die CLI hat einen Eingabe- oder Laufzeitfehler gefunden oder der abgeschlossene Scan weist eine unvollständige Abdeckung auf.
130 Strg-C hat den Scan unterbrochen.
143 SIGTERM hat den Scan beendet.

Ein Scan mit der Abdeckung partial oder unknown gibt auch ohne Schweregrad- richtlinie 2 zurück. Die CLI schreibt dennoch die verfügbaren Befunde und Abdeckungsdaten. Prüfen Sie die zurückgestellten Bereiche in coverage.json, bevor Sie die Prüfung als aussagekräftig betrachten.

Mit einem vorhandenen Ergebnisverzeichnis erneut versuchen

Verwenden Sie für jeden CI-Job ein neues Runner-Verzeichnis. Bewahren Sie bei einem persistenten oder selbst gehosteten Runner ein früheres Ergebnis mit --archive-existing auf:

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

Der Befehl archiviert die früheren Ergebnisse und beginnt mit einem leeren Scanverzeichnis.

Fehler bei einem CI-Scan beheben

  • Unbekannte Git-Referenz oder unerwarteter Diff: Rufen Sie den Verlauf von Base und Head ab, berechnen Sie die Merge-Basis und übergeben Sie beide Revisionen ausdrücklich.
  • Geschütztes oder nicht leeres Ausgabeverzeichnis: Wählen Sie ein privates Verzeichnis außerhalb des umgebenden Git-Worktrees. Verwenden Sie --archive-existing, wenn das Verzeichnis bereits Ergebnisse enthält.
  • Fehlende Anmeldedaten: Vergewissern Sie sich, dass CODEX_SECURITY_API_KEY für den vertrauenswürdigen Workflow oder die Pipeline verfügbar und direkt der Umgebungsvariable OPENAI_API_KEY des Scanprozesses zugeordnet ist.
  • Fehler im Scanverlauf: Setzen Sie CODEX_SECURITY_STATE_DIR auf ein beschreibbares Verzeichnis außerhalb des Repositorys.
  • Fehler bei der Python-Einrichtung: Vergewissern Sie sich, dass der Runner Python 3.10 oder höher verwendet.
  • Unvollständige Abdeckung: Prüfen Sie coverage.json einschließlich zurückgestellter Bereiche und offener Fragen und führen Sie den Scan anschließend mit einem geeigneten Ziel oder einer geeigneten Umgebung erneut aus.
  • SARIF-Exportfehler: Vergewissern Sie sich, dass der Scan abgeschlossen wurde und das vollständige Scanverzeichnis verfügbar ist. Der Export validiert die versiegelten Artefakte, bevor er SARIF schreibt.
  • SARIF-Uploadfehler: Vergewissern Sie sich bei GitHub Actions, dass Ihre Organisation GitHub Code Security für das Repository aktiviert hat und der Workflow actions: read, contents: read und security-events: write gewährt. Vergewissern Sie sich bei GitLab CI/CD, dass das Projekt GitLab Ultimate 19.2 oder höher verwendet und der Job über artifacts:reports:sarif eine SARIF-2.1.0-Datei hochlädt.

Informationen zu allen Befehlen, Flags, Artefakten und Ausgabefeldern finden Sie in der CLI- Referenz. Informationen zu einer interaktiven, Plugin-basierten CI- Prüfung finden Sie unter Codeänderungen auf Sicherheitsprobleme prüfen.