コンテンツにスキップ

セキュリティのためにコード変更をレビューする

1 つの Git 管理された変更セットによって導入されたリグレッションの証拠が必要な場合は、セキュリティ変更レビューを使用します。このワークフローでは、リポジトリ全体の一般的な監査にすることなく、変更されたすべてのソースに類するファイルと、それを直接サポートするコードをレビューします。

特定の変更ではなくリポジトリ全体をスキャンする場合は、セキュリティスキャンを実行するを参照してください。

手動レビューを実行する

コミットされていない変更の場合は、次の内容を送信します。

Use $codex-security:security-diff-scan to review my current uncommitted changes for security regressions.

コミットまたはブランチ範囲の場合は、必要に応じて両端を指定します。

Use $codex-security:security-diff-scan to review the changes from origin/main to HEAD for security regressions. Focus on authentication, authorization, input handling, filesystem access, network requests, and secrets.

ローカルチェックアウトでベースとヘッドのリビジョンを利用できる場合は、プルリクエストを指定することもできます。

セットアップで変更を確認する

  1. スキャンタイプChanges であることを確認します。
  2. チェックアウトされている コードベース現在のブランチ最後のコミットを確認します。
  3. レビューする変更で、次のいずれかを選択します。
  4. 現在の作業ツリーには Uncommitted changes を選択します。
  5. 1 つのコミットをレビューするには、最新のコミットを選択します。
  6. ブランチまたはプルリクエストの範囲には、ベースとヘッドのリビジョンを選択します。
  7. 概要に、レビューする意図した変更が記載されていることを確認します。
  8. スキャンを開始を選択します。

このワークフローでは、別のブランチをチェックアウトしたり、選択した作業ツリーを変更したりすることはありません。要求されたリビジョンがローカルで利用できない場合は、レビューの前にフェッチするか、ローカルで利用できるベースとヘッドを指定してください。

検出結果に対応する

結果をレビューしたら、承認した検出結果を修正して検証するか、検出結果をエクスポートして追跡することができます。

CI/CD でレビューを自動化する

ランナーが Codex CLI を対話なしで呼び出せる場合は、CI から同じ $codex-security:security-diff-scan スキルを実行します。まず、スキャン認証情報を公開せずに CLI とプラグインをインストールします。

npm install --global @openai/codex
codex plugin add codex-security@openai-curated

次に、CI のシークレットストアから OpenAI API キーを CODEX_SECURITY_API_KEY として、スキャン時にのみ公開します。

CODEX_API_KEY="$CODEX_SECURITY_API_KEY" codex exec \
  --sandbox workspace-write \
  "Use \$codex-security:security-diff-scan to review changes from $BASE_REVISION to $HEAD_REVISION for security regressions. Do not modify the checkout."

スキャンは出力を $TMPDIR/codex-security-scans/<repository>/<scan-id>/ に書き込みます。

ファイル 内容
report.md 完全なスキャンディレクトリへの、主要な可読エントリポイントです。
findings/<slug>/ 報告対象の検出結果ごとに 1 つ作成される詳細な脆弱性レポートです。利用可能な場合は、裏付けとなる概念実証ファイルも含まれます。
hardening/ 構造的な強化のポートフォリオと、スキャンに報告対象の検出結果がある場合の補足提案または図です。
findings.json 安定した識別子、重大度、信頼度、ソースの場所、修正方法を含む検出結果です。プルリクエストのコメント作成や下流ツールへの入力に使用します。
scan-manifest.json レビュー対象、リビジョン、アーティファクトのハッシュを含む、封印されたスキャンレシートです。
coverage.json レビュー済みおよび保留中のサーフェス、除外、カバレッジの完全性です。

findings.json スキーマでは、完全な構造を定義しています。主なフィールドは次のとおりです。

フィールド 説明
documentType String ドキュメントが codex-security.findings であることを識別します。
schemaVersion String 検出結果スキーマのバージョンを識別します。
scanId String 検出結果を生成したスキャンを識別します。
findings Array 0 個以上の検出結果オブジェクトを含みます。
findings[].findingId String 検出結果のフィンガープリントから導出された安定した検出結果識別子です。
findings[].occurrenceId String 特定のスキャンにおける、この検出結果の発生を識別します。
findings[].ruleId String 脆弱性ファミリーを識別します。
findings[].identity Object セマンティックアンカーと、任意の兄弟インスタンス識別子を含みます。
findings[].fingerprints Object フィンガープリントアルゴリズムと主要なフィンガープリントを含みます。
findings[].title String 検出結果の短いタイトルを指定します。
findings[].summary String 脆弱性とその影響を要約します。
findings[].severity Object 重大度レベルと、任意のスコアリングの詳細を含みます。
findings[].confidence Object 信頼度レベルとその根拠を含みます。
findings[].taxonomy Object 脆弱性カテゴリと CWE 識別子を含みます。
findings[].locations Array 影響を受けるファイル、行番号、場所の役割を一覧表示します。
findings[].remediation String 推奨される修正方法を説明します。
findings[].provenance Object 検出結果のソースを識別します。

たとえば、次のコマンドは検出結果ごとにタブ区切りの行を 1 行出力します。

jq -r '
  .findings[] |
  [.findingId, .severity.level, .confidence.level, .locations[0].path, .locations[0].startLine, .title] |
  @tsv
' findings.json

これらの例では、Node.js と npm、Git、Python 3、jq、およびプロバイダーのコマンドラインツールがインストールされた、信頼できる Linux ランナーを想定しています。npm グローバルパッケージプレフィックスは書き込み可能である必要があります。

一般的なパイプラインで Codex Security を使用する例を次に示します。

<Tabs id="codex-security-ci-examples" param="ci" defaultTab="github" tabs={[ { id: "github", label: "GitHub Actions" }, { id: "gitlab", label: "GitLab CI/CD" }, { id: "azure", label: "Azure Pipelines" }, { id: "jenkins", label: "Jenkins" }, ]}

name: Codex Security review

on:
  pull_request:

jobs:
  security-review:
    if: github.event.pull_request.head.repo.full_name == github.repository
    runs-on: ubuntu-latest
    permissions:
      contents: read
      pull-requests: write
    steps:
      - uses: actions/checkout@v5
        with:
          ref: ${{ github.event.pull_request.head.sha }}
          fetch-depth: 0
          persist-credentials: false

      - name: Install Codex Security
        env:
          CODEX_HOME: ${{ runner.temp }}/codex-home
        run: |
          npm install --global @openai/codex
          codex plugin add codex-security@openai-curated

      - name: Review code changes
        env:
          CODEX_SECURITY_API_KEY: ${{ secrets.CODEX_SECURITY_API_KEY }}
          CODEX_HOME: ${{ runner.temp }}/codex-home
          TMPDIR: ${{ runner.temp }}/codex-security
          BASE_SHA: ${{ github.event.pull_request.base.sha }}
          HEAD_REVISION: ${{ github.event.pull_request.head.sha }}
        run: |
          BASE_REVISION="$(git merge-base "$BASE_SHA" "$HEAD_REVISION")"
          CODEX_API_KEY="$CODEX_SECURITY_API_KEY" codex exec \
            --sandbox workspace-write \
            "Use \$codex-security:security-diff-scan to review changes from $BASE_REVISION to $HEAD_REVISION for security regressions. Do not modify the checkout."

      - name: Comment with findings
        if: always()
        env:
          GH_TOKEN: ${{ github.token }}
          PR_NUMBER: ${{ github.event.pull_request.number }}
        run: |
          findings="$(find "${{ runner.temp }}/codex-security/codex-security-scans" -name findings.json -print -quit 2>/dev/null || true)"
          test -n "$findings" || exit 0
          jq -r '
            "## Codex Security findings",
            "",
            if (.findings | length) == 0 then "No findings reported."
            else .findings[] | "- **\(.severity.level | ascii_upcase)**: \(.title) (`\(.locations[0].path):\(.locations[0].startLine)`)\n  \(.summary)"
            end
          ' "$findings" | gh pr comment "$PR_NUMBER" --body-file -

      - uses: actions/upload-artifact@v4
        if: always()
        with:
          name: codex-security-review
          path: ${{ runner.temp }}/codex-security/codex-security-scans
マスクされた `CODEX_SECURITY_API_KEY` と `GITLAB_TOKEN` の CI/CD 変数を作成します。GitLab トークンには、マージリクエストのノートを作成するための API アクセスが必要です。
codex-security-review:
  rules:
    - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_SOURCE_PROJECT_ID == $CI_PROJECT_ID'
  variables:
    GIT_DEPTH: "0"
  script:
    - |
      codex_security_api_key="$CODEX_SECURITY_API_KEY"
      unset CODEX_SECURITY_API_KEY GITLAB_TOKEN
      export CODEX_HOME="/tmp/codex-home-$CI_JOB_ID"
      export TMPDIR="/tmp/codex-security-$CI_JOB_ID"
      export BASE_REVISION="$CI_MERGE_REQUEST_DIFF_BASE_SHA"
      export HEAD_REVISION="${CI_MERGE_REQUEST_SOURCE_BRANCH_SHA:-$CI_COMMIT_SHA}"
      npm install --global @openai/codex
      codex plugin add codex-security@openai-curated
      CODEX_API_KEY="$codex_security_api_key" codex exec \
        --sandbox workspace-write \
        "Use \$codex-security:security-diff-scan to review changes from $BASE_REVISION to $HEAD_REVISION for security regressions. Do not modify the checkout."
  after_script:
    - |
      gitlab_token="$GITLAB_TOKEN"
      unset CODEX_SECURITY_API_KEY GITLAB_TOKEN
      scan_root="/tmp/codex-security-$CI_JOB_ID/codex-security-scans"
      findings="$(find "$scan_root" -name findings.json -print -quit 2>/dev/null || true)"
      if [ -n "$findings" ]; then
        jq -r '
          "## Codex Security findings",
          "",
          if (.findings | length) == 0 then "No findings reported."
          else .findings[] | "- **\(.severity.level | ascii_upcase)**: \(.title) (`\(.locations[0].path):\(.locations[0].startLine)`)\n  \(.summary)"
          end
        ' "$findings" > codex-security-comment.md
        curl --fail --request POST \
          --header "PRIVATE-TOKEN: $gitlab_token" \
          --form "body=<codex-security-comment.md" \
          "$CI_API_V4_URL/projects/$CI_PROJECT_ID/merge_requests/$CI_MERGE_REQUEST_IID/notes"
      fi
      if [ -d "$scan_root" ]; then
        tar -czf codex-security-artifacts.tar.gz -C "$scan_root" .
      fi
  artifacts:
    when: always
    paths:
      - codex-security-artifacts.tar.gz
trigger: none

pool:
  vmImage: ubuntu-latest

steps:
  - checkout: self
    fetchDepth: 0

  - bash: |
      set -euo pipefail
      export CODEX_HOME="$AGENT_TEMPDIRECTORY/codex-home"
      npm install --global @openai/codex
      codex plugin add codex-security@openai-curated
    displayName: Install Codex Security

  - bash: |
      set -euo pipefail
      export CODEX_HOME="$AGENT_TEMPDIRECTORY/codex-home"
      export TMPDIR="$AGENT_TEMPDIRECTORY/codex-security"
      export HEAD_REVISION="$SYSTEM_PULLREQUEST_SOURCECOMMITID"
      export BASE_REVISION="$(git merge-base HEAD^1 "$HEAD_REVISION")"
      CODEX_API_KEY="$CODEX_SECURITY_API_KEY" codex exec \
        --sandbox workspace-write \
        "Use \$codex-security:security-diff-scan to review changes from $BASE_REVISION to $HEAD_REVISION for security regressions. Do not modify the checkout."
    displayName: Review code changes
    condition: and(succeeded(), ne(variables['System.PullRequest.IsFork'], 'True'))
    env:
      CODEX_SECURITY_API_KEY: $(CODEX_SECURITY_API_KEY)

  - publish: $(Agent.TempDirectory)/codex-security/codex-security-scans
    artifact: codex-security-review
    condition: always()
Azure Repos の場合は、プルリクエストでパイプラインを実行するように **ビルド検証**ブランチポリシーを設定します。
pipeline {
  agent { label 'linux' }
  stages {
    stage('Codex Security review') {
      when {
        allOf {
          changeRequest()
          expression { !env.CHANGE_FORK?.trim() }
        }
      }
      steps {
        sh '''#!/usr/bin/env bash
          set -euo pipefail
          export CODEX_HOME="/tmp/codex-home-$BUILD_TAG"
          export TMPDIR="/tmp/codex-security-$BUILD_TAG"
          mkdir -p "$TMPDIR"
          git fetch --no-tags origin "$CHANGE_TARGET"
          target="$(git rev-parse FETCH_HEAD)"
          git fetch --no-tags origin "$CHANGE_BRANCH"
          git rev-parse FETCH_HEAD > "$TMPDIR/head"
          git merge-base "$target" "$(cat "$TMPDIR/head")" > "$TMPDIR/base"
          npm install --global @openai/codex
          codex plugin add codex-security@openai-curated
        '''
        withCredentials([string(credentialsId: 'codex-security-api-key', variable: 'CODEX_SECURITY_API_KEY')]) {
          sh '''#!/usr/bin/env bash
            set +x
            set -euo pipefail
            export CODEX_HOME="/tmp/codex-home-$BUILD_TAG"
            export TMPDIR="/tmp/codex-security-$BUILD_TAG"
            export HEAD_REVISION="$(cat "$TMPDIR/head")"
            export BASE_REVISION="$(cat "$TMPDIR/base")"
            CODEX_API_KEY="$CODEX_SECURITY_API_KEY" codex exec \
              --sandbox workspace-write \
              "Use \$codex-security:security-diff-scan to review changes from $BASE_REVISION to $HEAD_REVISION for security regressions. Do not modify the checkout."
          '''
        }
      }
      post {
        always {
          sh '''#!/usr/bin/env bash
            set -euo pipefail
            scan_root="/tmp/codex-security-$BUILD_TAG/codex-security-scans"
            if [ -d "$scan_root" ]; then
              tar -czf codex-security-artifacts.tar.gz -C "$scan_root" .
            fi
          '''
          archiveArtifacts artifacts: 'codex-security-artifacts.tar.gz', allowEmptyArchive: true
        }
      }
    }
  }
}

この例では、フォークからのプルリクエストをスキップします。認証情報を使用するジョブは、保護されたパイプライン定義からのみ実行し、スキャン認証情報を信頼できる貢献者に対してのみ実行してください。構造化された検出結果、マニフェスト、カバレッジアーティファクト、report.md、およびそれにリンクされた findings/hardening/ の出力をまとめて保持するために、codex-security-scans をアーカイブします。まずは助言的な結果から始め、ジョブを必須チェックにする前に、カバレッジと実行時間を確認してください。

API キーの処理とサンドボックス制御については、非対話モードを参照してください。組織で Codex GitHub Action が許可されている場合は、実行時に CLI をインストールできますが、それでも最初にプラグインをインストールし、アクションの codex-home 入力を同じ CODEX_HOME に指定する必要があります。