GitLab CI/CD で Codex Security を実行すると、コミット済みの変更や保護ブランチをスキャンし、検出結果を GitLab Security に公開できます。必要に応じて、検証済みの修正をドラフトのマージリクエストで提案することもできます。
このワークフローでは、スキャン用の認証情報とリポジトリへの書き込み権限を分離します。生成された変更をマージする前に、必ず人によるレビューが必要です。
まずはスキャン結果の報告のみを行います。自動修正を有効にする前に、プロジェクトのランナー、検出結果、各ジョブがアクセスできる認証情報の範囲を確認してください。
前提条件
次のものが必要です。
- Codex サンドボックスのユーザー名前空間に対応した、信頼できるランナーを備えた GitLab プロジェクト
- プロジェクトの CI/CD 変数と保護リソースを設定できる、GitLab プロジェクトの Maintainer または Owner ロール
- Codex Security にアクセスできる OpenAI API キー。Platform API キーを使用する組織は、Trusted Access for Cyber を申請できます。ChatGPT 認証を使用する個人は、個人向けの Trusted Access 申請手続きを利用できます。一部のアカウントやリポジトリでは、リポジトリ全体のスキャンにこのアクセス権が必要です。
- SARIF 2.1.0 の取り込みに対応する GitLab Ultimate 19.2 以降
- マージリクエストのジョブでマージベースを算出するための完全な Git 履歴
パイプラインのイメージには、Node.js 26、Python 3、Git、rg、バージョンを固定した Codex Security CLI がインストールされます。自動修正にはさらに、既存の回帰テストと、保護された認証情報を使わずにリポジトリで定義されたコマンドを実行できるランナーが必要です。
スキャン専用パイプラインの導入
CODEX_SECURITY_API_KEY という名前の GitLab CI/CD 変数を作成し、マスク、非表示、保護を有効にします。値には Codex Security にアクセスできる OpenAI Platform API キーを使用し、環境スコープを codex-security/openai に設定します。詳しくは、CI/CD 変数の環境スコープを参照してください。
まずはテスト用プロジェクトに次のパイプラインを追加します。このパイプラインは、条件を満たす保護ブランチ間のマージリクエストでコミット済みの変更をスキャンします。レポートジョブが成功すると SARIF を公開し、別のゲートジョブでスキャナーと同じ終了コードを返します。
stages:
- security_scan
- security_gate
.codex-security-merge-request:
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_SOURCE_PROJECT_ID == $CI_PROJECT_ID && $CI_MERGE_REQUEST_SOURCE_BRANCH_PROTECTED == "true" && $CI_MERGE_REQUEST_TARGET_BRANCH_PROTECTED == "true"'
codex-security:
extends: .codex-security-merge-request
stage: security_scan
image: node:26-bookworm-slim
environment:
name: codex-security/openai
action: access
variables:
GIT_DEPTH: "0"
before_script:
- apt-get update -qq
- apt-get install -y -qq --no-install-recommends ca-certificates git python3 ripgrep
- npm install --prefix /tmp/codex-security-cli --ignore-scripts --no-audit --no-fund @openai/codex-security@0.8.1
script:
- |
set -eu
test -n "${CODEX_SECURITY_API_KEY:-}"
CODEX_SECURITY_BIN="/tmp/codex-security-cli/node_modules/.bin/codex-security"
RESULTS_DIR="/tmp/codex-security-results-$CI_JOB_ID"
ARTIFACT_DIR="codex-security-artifacts"
BASE_REVISION="$(git merge-base \
"$CI_MERGE_REQUEST_DIFF_BASE_SHA" "$CI_COMMIT_SHA")"
install -d -m 700 "$RESULTS_DIR" "$ARTIFACT_DIR/results"
codex_security_api_key="$CODEX_SECURITY_API_KEY"
unset CODEX_SECURITY_API_KEY
set +e
OPENAI_API_KEY="$codex_security_api_key" \
"$CODEX_SECURITY_BIN" scan . \
--diff "$BASE_REVISION" \
--head "$CI_COMMIT_SHA" \
--auth api-key \
--output-dir "$RESULTS_DIR" \
--fail-on-severity high \
--json
scan_exit="$?"
set -e
unset codex_security_api_key
case "$scan_exit" in
0|1) ;;
*) exit "$scan_exit" ;;
esac
"$CODEX_SECURITY_BIN" export "$RESULTS_DIR" \
--export-format sarif \
--source-root "$CI_PROJECT_DIR" \
--output "$ARTIFACT_DIR/results.sarif"
test -s "$ARTIFACT_DIR/results.sarif"
cp -R "$RESULTS_DIR"/. "$ARTIFACT_DIR/results/"
printf '%s\n' "$scan_exit" > "$ARTIFACT_DIR/scan-exit-code.txt"
exit 0
artifacts:
when: always
access: maintainer
expire_in: 7 days
paths:
- codex-security-artifacts/
reports:
sarif: codex-security-artifacts/results.sarif
codex-security-gate:
extends: .codex-security-merge-request
stage: security_gate
image: alpine:3.20
needs:
- job: codex-security
artifacts: true
script:
- exit "$(cat codex-security-artifacts/scan-exit-code.txt)"
シークレットを扱うジョブを実行する前に、.gitlab-ci.yml への変更をすべてレビューしてください。この例では、リポジトリ全体のスキャンと自動修正は省いています。
本番用パイプラインの導入
- GitLab パイプラインの完全版をダウンロードし、リポジトリのルートに
.gitlab-ci.ymlとして保存します。既存のパイプラインがある場合は、サンプルのステージ、非表示テンプレート、ジョブを既存のファイルに組み込みます。 - 既存のビルド、テスト、デプロイの各ステージは維持します。プロジェクトで
workflow: rulesを使用している場合は、スキャン対象のイベントでパイプラインを実行できることを確認します。
この例では、security_scan、security_remediation、security_publish、security_gate の各ステージを追加します。スキャン結果の報告のみを行う場合、必要な変数は CODEX_SECURITY_API_KEY だけです。
デフォルトでは、スキャンジョブは同一プロジェクトの保護ブランチ間のマージリクエストでのみ実行されます。保護されたデフォルトブランチへのプッシュ時や、そのブランチでのパイプラインの手動実行時にもスキャンするには、CODEX_SECURITY_FULL_SCAN_DEFAULT_BRANCH=true を設定します。保護されたデフォルトブランチで定期的に詳細スキャンを実行するには、CODEX_SECURITY_SCHEDULED_DEEP_SCAN=true を設定し、時間とコストの予算を明示的に指定します。
マージリクエストのパイプラインが保護変数と保護ランナーにアクセスできるのは、次の条件をすべて満たす場合のみです。
- ソースブランチとターゲットブランチが同一プロジェクトにあり、両方が保護されている
- プロジェクトでマージリクエストのパイプラインから保護変数と保護ランナーへのアクセスを許可している
- パイプラインを開始するユーザーがターゲットブランチにプッシュまたはマージできる
フォークのパイプラインや保護されていないマージリクエストには、スキャン用の認証情報は渡されません。シークレットを扱うジョブを実行する前に、.gitlab-ci.yml への変更をすべてレビューしてください。変数をマスクして非表示にしても、信頼できない CI コードを安全に実行できるわけではありません。
スキャンの実行と検出結果のレビュー
条件を満たす保護ブランチ間のマージリクエストを作成するか、保護されたデフォルトブランチでパイプラインを実行します。リポジトリ全体を対象とした有料スキャンを実行する前に、小さな差分で試してください。
codex-security ジョブを開き、次のアーティファクトが含まれていることを確認します。
results/scan-manifest.jsonresults/findings.jsonresults/report.mdresults.sarifscan-exit-code.txt
次に、パイプラインの セキュリティ タブを開き、取り込み時の警告を確認します。各検出結果の識別子、重大度、ソースコード上の位置も確認してください。デフォルトブランチのスキャンでは、プロジェクトの脆弱性レコードも作成されます。マージリクエストの検出結果は、パイプラインのセキュリティタブまたはマージリクエストのセキュリティウィジェットに表示されますが、プロジェクト全体の脆弱性レコードは作成されません。
スキャン結果には、脆弱性のあるソースコードの抜粋、検出の根拠、修正の詳細が含まれることがあるため、アーティファクトへのアクセスを制限してください。
スキャンプロファイルの選択
パイプラインはトリガーに応じてプロファイルを選択します。
| トリガー | 対象 | モード | 推論強度 |
|---|---|---|---|
| 同一プロジェクトの保護ブランチ間のマージリクエスト | コミット済みの差分 | standard |
low |
| 保護されたデフォルトブランチへのプッシュまたは手動実行(明示的に有効化) | リポジトリ全体 | standard |
high |
| 保護されたデフォルトブランチでの定期実行(明示的に有効化) | リポジトリ全体 | deep |
xhigh |
マージリクエストのスキャンは、コミット済みの変更に絞ってフィードバックを返します。デフォルトブランチのスキャンでは、変更を統合したリポジトリを確認します。定期的な詳細スキャンでは、より広い範囲を調べます。差分スキャンの結果が適用されるのは、その変更だけです。スキャンが完了しても、リポジトリ全体に問題がないことは保証されません。
ワークフローはリポジトリの外に CLI をインストールし、絶対パスで実行します。ドライランによる事前チェックでは、そのプロセスにだけ API キーを渡します。有料スキャンは開始せず、API 認証、Codex Security へのアクセス権、クォータ、モデルの利用可否も検証しません。
ワークフローはスキャンの状態と結果を作業ツリーの外に書き込み、OPENAI_API_KEY をスキャンプロセスにのみ渡します。CLI に渡す環境変数は必要なものだけを明示的に指定し、GitLab の変数を一括で継承しないようにしています。差分スキャンではマージベースを算出し、レビュー対象のベースリビジョンとヘッドリビジョンを指定してスキャンします。
この例では @openai/codex-security のバージョンを 0.8.1 に固定しています。バージョンを変更する前に、認証、アーティファクト、SARIF の取り込み、ポリシーゲートの動作を再テストしてください。
結果の報告とポリシー適用の分離
GitLab は、成功したレポートジョブから SARIF を取り込みます。パイプラインは先にレポートを公開し、別の codex-security-gate ジョブでスキャナーと同じ終了ステータスを返します。
レポートジョブが検出結果をエクスポートするのは、終了コードが 0 または 1 の場合だけです。それ以外の終了コードでは SARIF のエクスポートをスキップし、パイプラインを失敗させます。エクスポートに失敗した場合もパイプラインは失敗します。
実行エラーや中断はレポートジョブの終了ステータスに反映されます。レポートジョブが成功した場合は、最終ゲートでスキャナーのポリシー判定を次のように反映します。
| 終了コード | 意味 |
|---|---|
0 |
スキャンが完了し、ポリシーの条件を満たしました。 |
1 |
スキャンが完了し、設定したしきい値以上の重大度の問題が見つかりました。 |
2 |
入力、実行時の処理、スキャン対象の整合性、または必須の出力に関するエラーが発生しました。 |
130 / 143 |
スキャンが中断されたか、終了シグナルを受けて停止しました。 |
この例では --fail-on-severity high を指定しているため、重大度が「高」または「クリティカル」の問題が見つかるとゲートは失敗します。重大度のしきい値を指定しない場合、完了したスキャンの終了コードはデフォルトで 0 です。results/scan-manifest.json の scan.scope には設定されたスキャン範囲が、scan.review.excludedPaths には検出結果の比較から除外されたパスが記録されます。今後の対応については results/report.md を確認してください。
修正と公開は最終ポリシーゲートの前に実行されます。対象となる問題が見つかれば、最終ゲートでパイプラインが失敗する場合でも、検証済みの修正を含むドラフトのマージリクエストを作成できます。
検証を伴う自動修正の有効化
自動修正は任意で、保護されたデフォルトブランチのパイプラインでのみ実行されます。Codex の修正プロセスにも、リポジトリで定義された検証コマンドにも、GitLab プロジェクトアクセストークンやランナーが注入する認証情報は渡されません。
ワークフローは次の手順で修正を行います。
- 現在のリビジョンでスキャンが完了したことを示すマニフェストがあり、重大度が
highまたはcriticalの問題が検出されていることを条件とします。 - パッチを適用する前に、指定した回帰テストが失敗することを確認します。
- パッチを生成し、CI 関連ファイル、認証情報ファイル、バイナリファイル、その他の保護対象ファイルへの変更を拒否します。
- OpenAI、GitLab、レジストリ、デプロイの認証情報やジョブトークンを渡さずに回帰テストを実行します。
verify-fixを実行してfixed、still_vulnerable、inconclusiveのいずれかの結果を取得します。ジョブがパッチを公開するのは、verify-fixがfixedを返し、検証処理によってパッチが変更されなかった場合だけです。
自動修正を有効にするには、次の保護変数を設定します。
CODEX_SECURITY_ENABLE_REMEDIATIONをtrueに設定します。CODEX_SECURITY_VERIFICATION_COMMANDに、修正前は終了コード1、修正後は0を返す既存の回帰テストを指定します。- 必要に応じて、
CODEX_SECURITY_SETUP_COMMANDに依存関係を非対話形式でセットアップするコマンドを指定します。
特定の実装に依存せず、セキュリティ上常に満たすべき条件を検証できる回帰テストを選んでください。生成されたテストの変更も、ソースコードの変更と同じ厳密さでレビューしてください。
詳細設定:リポジトリで定義されたコマンドの分離
validate、patch、verify-fix の各コマンドには、プロセスごとに OPENAI_API_KEY を渡し、--auth api-key を指定します。リポジトリで定義されたセットアップコマンドとテストコマンドは、追跡対象のソースファイルの書き込み可能なコピーで、別の非特権ユーザーとして実行します。コピーには Git メタデータ、サブモジュールの内容、ダウンロード済みのアーティファクトは含まれません。.git やサブモジュールが必要なセットアップコマンドやテストコマンドは、認証情報を渡さない専用のジョブを別途用意して実行してください。
正規のチェックアウト先や、その隣にある GitLab のファイル型変数用ディレクトリにアクセスできるのは、root が所有する Codex のステップだけです。コピー先では環境変数を PATH、HOME、LANG、CI、CI_PROJECT_DIR だけに限定します。コマンドに他の非機密の値が必要な場合は、コマンドをレビューしてから、その値を許可リストに追加してください。ランナーでユーザーを切り替えられない場合は、自動修正を有効にする前に、認証情報を渡さない別のジョブに検証処理を移してください。
ドラフトのマージリクエストの公開
GitLab プロジェクトアクセストークンを作成し、Developer ロールと api、write_repository の両スコープを付与します。トークンは保護、マスク、非表示を有効にした変数 GITLAB_REMEDIATION_TOKEN に保存し、環境スコープを codex-security/publish のみに限定します。
公開を有効にするには、CODEX_SECURITY_CREATE_MR=true を設定します。また、機密情報を含まない CODEX_SECURITY_MR_TEST_COMMAND に、生成されるすべての修正ブランチが合格する必要のある、プロジェクト固有のセキュリティ回帰テストを指定します。生成された保護対象外のマージリクエストからコマンドを読み取れるよう、この変数は保護しないでください。公開ワークフローは次のように動作します。
- リポジトリへの書き込み用トークンを受け取ります。OpenAI の認証情報は受け取りません。
codex-security/fix-<finding-hash>ブランチを作成します。- ドラフトのマージリクエストを作成します。すでに開いているドラフトがあれば、それを再利用して重複を避けます。
- 保護対象外の修正ブランチの回帰テストは、追跡対象ファイルだけをコピーした環境で、保護された認証情報を渡さずに非特権ユーザーとして実行します。
- 生成された変更を自動でマージすることはありません。
プロジェクトアクセストークンの代わりに CI_JOB_TOKEN を使わないでください。このトークンでは必要なマージリクエストを作成できません。マージする前に、提案されたパッチ、検証の根拠、検出された問題をレビューしてください。
オプション変数の設定
有効にする機能に必要な変数だけを設定してください。
| 変数 | 必要となる場面 | デフォルト値または用途 |
|---|---|---|
CODEX_SECURITY_API_KEY |
すべてのスキャン | 保護、マスク、非表示を有効にし、スコープを codex-security/openai に限定 |
CODEX_SECURITY_VERSION |
CLI のアップグレード | 0.8.1 に固定。変更前に再テストが必要 |
CODEX_SECURITY_FULL_SCAN_DEFAULT_BRANCH |
デフォルトブランチの全体スキャン | 明示的に有効化。デフォルトは無効 |
CODEX_SECURITY_SCHEDULED_DEEP_SCAN |
定期的な詳細スキャン | 明示的に有効化。デフォルトは無効 |
CODEX_SECURITY_DEEP_MAX_TIME_MINUTES |
定期的な詳細スキャン | 実行時間の予算を分単位で指定(必須)。0 分より長く 480 分未満 |
CODEX_SECURITY_DEEP_MAX_COST |
定期的な詳細スキャン | 推定コストの上限を米ドルで指定(必須)。0 より大きい値 |
CODEX_SECURITY_ENABLE_REMEDIATION |
パッチの生成 | 保護変数で明示的に有効化。デフォルトは無効 |
CODEX_SECURITY_VERIFICATION_COMMAND |
パッチの生成 | 保護変数に指定する回帰テスト |
CODEX_SECURITY_SETUP_COMMAND |
修正用のセットアップ(任意) | 保護変数に指定する依存関係のインストールコマンド |
CODEX_SECURITY_REMEDIATION_EFFORT |
修正時の推論強度の調整(任意) | high |
CODEX_SECURITY_MAX_CHANGED_FILES |
パッチで変更するファイル数の制限(任意) | 8。指定可能な範囲は 1 から 20 |
CODEX_SECURITY_CREATE_MR |
ドラフトのマージリクエストの作成 | 保護変数で明示的に有効化。デフォルトは無効 |
GITLAB_REMEDIATION_TOKEN |
ドラフトのマージリクエストの作成 | Developer ロールのプロジェクトトークン。環境スコープは codex-security/publish に限定 |
CODEX_SECURITY_GITLAB_INTERNAL_URL |
セルフホスト環境での公開(任意) | ランナーからアクセスできる GitLab のオリジン |
CODEX_SECURITY_MR_TEST_COMMAND |
ドラフトのマージリクエストの公開 | 機密情報を含まない、プロジェクト固有の回帰テストが必須 |
CODEX_SECURITY_MR_SETUP_COMMAND |
修正ブランチのセットアップ(任意) | 機密情報を含まない依存関係のセットアップコマンド |
CI_* 変数は GitLab が提供します。CODEX_SECURITY_BIN、CODEX_SECURITY_EFFORT、CODEX_SECURITY_MODE、CODEX_SECURITY_STATE_DIR、CODEX_SECURITY_TARGET はパイプラインが管理するため、プロジェクト変数として設定しないでください。差分スキャンでは、CLI が正規化したベースリビジョンとヘッドリビジョンから、スキャン対象の正規の識別子を導出します。
ポリシー適用とコストの調整
マージリクエストへのフィードバックには差分スキャン、デフォルトブランチには標準のリポジトリスキャン、より広い範囲を調べるには定期的な詳細スキャンを使用します。リポジトリ全体を対象とする 2 つのプロファイルは、どちらもデフォルトで無効です。定期的な詳細スキャンには CODEX_SECURITY_DEEP_MAX_TIME_MINUTES と CODEX_SECURITY_DEEP_MAX_COST の指定も必要です。CLI の時間予算は、ジョブのタイムアウトである 8 時間より短く設定してください。新しい YAML を導入する際は、既存の時間単位の設定値を分単位に換算します。予算を設定する前に、代表的な条件でスキャンを実行し、所要時間とコストを測定してください。--max-cost は推定コストを抑えるための目安であり、請求額に厳密な上限を設けるものではありません。
この例では、重大度が「高」または「クリティカル」の問題が見つかるとゲートは失敗します。報告のみを行うスキャンでは --fail-on-severity high を削除してください。しきい値は、代表的な検出結果、スキャンの対象範囲、コスト、実行時間を確認してから決定します。重大度に基づくポリシーについては CI/CD の概要、終了コードの詳細については CLI リファレンスを参照してください。
ジョブが失敗した場合は、次の点を確認します。
- スキャンのアーティファクトが見つからない場合は、設定またはランナーに問題があると考えられます。
- 想定外の除外がある場合は、
results/scan-manifest.jsonでスキャン範囲とレビューの詳細を確認します。 - GitLab に検出結果が表示されない場合は、SARIF レポートジョブが成功したか、GitLab がレポートを受理したかを確認します。
- 自動修正がスキップされた場合は、保護ブランチ、スキャンマニフェスト、検出された問題の重大度、検証コマンド、機能を有効にする変数を確認します。
- 公開時にエラーが発生した場合は、プロジェクトトークンのロール、スコープ、環境の制限を確認します。
すべてのコマンド、フラグ、アーティファクトについては、Codex Security CLI リファレンスを参照してください。