Bahasa Indonesia

Menjalankan Codex Security di CI

Pindai perubahan pull request dan merge request, pertahankan hasil terstruktur, unggah SARIF, dan tetapkan kebijakan tingkat keparahan.

Jalankan Codex Security CLI di CI untuk meninjau perubahan yang persis dalam pull request atau merge request, mempertahankan temuan dan cakupan, serta secara opsional menggagalkan pemeriksaan pada tingkat keparahan yang dipilih. Mulailah dengan hasil berupa saran, tinjau kualitas dan waktu proses pemindaian, lalu tambahkan kebijakan tingkat keparahan yang sesuai dengan repositori Anda.

Panduan ini menyertakan contoh untuk GitHub Actions dan GitLab CI/CD. Perintah pemindaian dan ekspor yang sama dapat digunakan di sistem CI lainnya.

Menyiapkan alur kerja

Simpan API key OpenAI di penyimpanan rahasia penyedia CI Anda sebagai CODEX_SECURITY_API_KEY.

Petakan rahasia ini secara langsung ke variabel lingkungan OPENAI_API_KEY pada langkah pemindaian. Batasi kredensial hanya untuk proses pemindaian dan gunakan --auth api-key untuk memilihnya secara eksplisit.

Jalankan alur kerja hanya untuk repositori dan pull request yang Anda percayai. Pemindaian menggunakan izin lokal runner dan tidak berhenti untuk meminta persetujuan. Proses pemindaian dapat mewarisi lingkungan job, jadi jangan sertakan token dan kredensial cloud yang tidak terkait di dalamnya.

Runner memerlukan:

  • Node.js 22 (22.13.0 atau yang lebih baru), 24, atau 26.
  • Python 3.10 atau yang lebih baru.
  • Paket @openai/codex-security yang telah dipublikasikan, diinstal di luar checkout repositori.
  • Riwayat head dan base pull request atau merge request agar Git dapat menghitung merge base.

Menambahkan alur kerja GitHub Actions

Untuk repositori privat atau internal, aktifkan GitHub Code Security sebelum mengunggah SARIF.

Buat .github/workflows/codex-security.yml. Sebelum melakukan checkout pull request, instal @openai/codex-security di bawah $RUNNER_TEMP/codex-security agar executable tepercaya tersedia di $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

Alur kerja melakukan checkout head pull request, menghitung merge base-nya, dan memindai perubahan yang telah di-commit di antara revisi tersebut. Riwayat lengkap menjaga target tetap tepat. persist-credentials: false mencegah token repositori masuk ke konfigurasi Git hasil checkout. Menginstal CLI sebelum checkout dan menjalankannya melalui path absolut menjauhkan executable yang dikendalikan repositori dari kredensial pemindaian. --auth api-key secara eksplisit memilih API key yang dibatasi cakupannya. Pemindaian menyimpan riwayatnya dalam direktori status yang dapat ditulis di luar repositori.

--json menulis satu dokumen JSON lengkap ke stdout sehingga alur kerja dapat langsung menyimpannya. Progres, ringkasan penyelesaian, dan kesalahan tetap berada di stderr. Ini berbeda dari codex exec --json, yang menghasilkan aliran peristiwa JSON Lines.

Langkah ekspor membaca pemindaian yang telah selesai dan disegel, lalu menulis SARIF. Langkah ini tidak mengubah runtime Codex maupun kredensial. Artefak pemindaian dapat berisi cuplikan kode sumber yang rentan, bukti, dan detail remediasi. Pilih kontrol akses dan jangka retensi singkat yang sesuai untuk repositori Anda.

Menambahkan pipeline GitLab CI/CD

Untuk alur kerja produksi dengan pemindaian cabang default yang dilindungi, pemindaian mendalam terjadwal yang diaktifkan secara eksplisit, pembatasan kebijakan SARIF terpisah, dan merge request draf terverifikasi opsional, gunakan Jalankan Codex Security di GitLab CI/CD.

GitLab dapat menyerap laporan SARIF 2.1.0 pada GitLab Ultimate 19.2 atau yang lebih baru. Tambahkan variabel CI/CD CODEX_SECURITY_API_KEY yang disamarkan dan disembunyikan sebelum menjalankan pipeline.

Contoh minimal berikut menambahkan job security khusus pemindaian ke .gitlab-ci.yml di root. Pertahankan semua tahapan dan job yang sudah ada dalam file. Secara default, job ini memindai perubahan merge request. Atur CODEX_SECURITY_FULL_SCAN_DEFAULT_BRANCH ke "true" untuk turut memindai seluruh cabang default:

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@0.1.20
      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

Secara default, job hanya berjalan untuk merge request dari branch dalam proyek yang sama, sehingga pipeline fork tidak menerima kredensial pemindaian. Tetapkan CODEX_SECURITY_FULL_SCAN_DEFAULT_BRANCH ke "true" pada tingkat grup, proyek, atau pipeline untuk turut menjalankan pemindaian penuh standar pada branch default. Pemindaian penuh memerlukan waktu lebih lama dan biaya lebih besar daripada pemindaian diff.

GIT_DEPTH: "0" menyediakan riwayat yang diperlukan untuk menghitung merge base dari CI_MERGE_REQUEST_DIFF_BASE_SHA dan CI_COMMIT_SHA bagi pemindaian merge request.

Job menginstal CLI di bawah /tmp, menjalankannya melalui path absolut, dan hanya mengekspos API key kepada proses pemindaian. artifacts: when: always mempertahankan laporan SARIF ketika pemindaian gagal, sedangkan artifacts:access: maintainer membatasi akses ke hasil pemindaian terperinci.

Perubahan pada .gitlab-ci.yml dapat mengekspos variabel CI/CD, jadi tinjau perubahan pipeline sebelum menjalankan job. Jika Anda melindungi CODEX_SECURITY_API_KEY, GitLab hanya menyediakannya bagi merge request dalam proyek yang sama di antara branch yang dilindungi dan hanya jika pengguna dapat mengakses branch target.

Panduan khusus GitLab mengembangkan job minimal ini menjadi alur kerja produksi yang ditautkan pada awal bagian ini.

Memilih kebijakan tingkat keparahan

Kedua contoh hanya membuat laporan karena tidak menyertakan --fail-on-severity. Setelah Anda siap membuat temuan memengaruhi pemeriksaan, tambahkan ambang batas ke perintah pemindaian:

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

Ambang batas yang didukung adalah critical, high, medium, dan low. Sebuah ambang batas mencakup temuan dari pemindaian saat ini pada tingkat keparahan tersebut dan yang lebih tinggi. Temuan terbuka sebelumnya yang ditampilkan dalam ringkasan repositori tidak memengaruhi kebijakan.

Langkah pemindaian menggunakan kode keluar berikut:

Kode keluar Arti
0 Pemindaian selesai dengan cakupan lengkap dan semua kebijakan yang dikonfigurasi terpenuhi.
1 Pemindaian yang selesai memuat temuan pada atau di atas ambang batas.
2 CLI menemukan kesalahan input atau runtime, atau pemindaian yang selesai memiliki cakupan tidak lengkap.
130 Ctrl-C menginterupsi pemindaian.
143 SIGTERM menghentikan pemindaian.

Pemindaian dengan cakupan partial atau unknown mengembalikan 2, bahkan tanpa kebijakan tingkat keparahan. CLI tetap menulis temuan dan cakupan yang tersedia. Tinjau area yang ditangguhkan dalam coverage.json sebelum menganggap pemeriksaan tersebut konklusif.

Mencoba kembali dengan direktori hasil yang sudah ada

Gunakan direktori runner baru untuk setiap job CI. Untuk runner persisten atau yang di-host sendiri, pertahankan hasil sebelumnya dengan --archive-existing:

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

Perintah tersebut mengarsipkan hasil sebelumnya dan memulai dengan direktori pemindaian kosong.

Memecahkan masalah pemindaian CI

  • Ref Git tidak dikenal atau diff tidak sesuai harapan: Ambil riwayat base dan head, hitung merge base, lalu teruskan kedua revisi secara eksplisit.
  • Direktori output dilindungi atau tidak kosong: Pilih direktori privat di luar worktree Git yang menaunginya. Gunakan --archive-existing ketika direktori tersebut sudah berisi hasil.
  • Kredensial tidak ada: Pastikan CODEX_SECURITY_API_KEY tersedia bagi alur kerja atau pipeline tepercaya dan dipetakan secara langsung ke variabel lingkungan OPENAI_API_KEY milik proses pemindaian.
  • Kesalahan riwayat pemindaian: Tetapkan CODEX_SECURITY_STATE_DIR ke direktori yang dapat ditulis di luar repositori.
  • Kesalahan penyiapan Python: Pastikan runner menggunakan Python 3.10 atau yang lebih baru.
  • Cakupan tidak lengkap: Tinjau coverage.json, termasuk permukaan yang ditangguhkan dan pertanyaan terbuka, lalu jalankan kembali dengan target atau lingkungan yang sesuai.
  • Kesalahan ekspor SARIF: Pastikan pemindaian telah selesai dan seluruh direktori pemindaian tersedia. Ekspor memvalidasi artefak tersegel sebelum menulis SARIF.
  • Kesalahan pengunggahan SARIF: Untuk GitHub Actions, pastikan organisasi Anda mengaktifkan GitHub Code Security bagi repositori dan alur kerja memberikan actions: read, contents: read, dan security-events: write. Untuk GitLab CI/CD, pastikan proyek menggunakan GitLab Ultimate 19.2 atau yang lebih baru dan job mengunggah file SARIF 2.1.0 melalui artifacts:reports:sarif.

Untuk setiap perintah, flag, artefak, dan bidang output, lihat referensi CLI. Untuk peninjauan CI interaktif berbasis plugin, lihat Meninjau perubahan kode untuk keamanan.