运行 Codex 中的安全性 CI
如需完整文档索引,请参阅 llms.txt。文档页面的 Markdown 版本可通过在页面后追加
.md来获取 URL。
运行 Codex Security CLI 于 CI 以审查拉取请求中的确切变更 或合并请求,保留发现和覆盖范围,并可选择在 所选严重级别使检查失败。先从建议性结果开始,审查扫描质量和 运行时间,然后添加适合你仓库的严重级别策略。
安装公开的 @openai/codex-security 包。运行扫描仍然
需要 Codex Security 访问权限。
本指南包含 GitHub Actions 和 GitLab CI/CD的示例。同样的扫描 和导出命令也适用于其他 CI 系统。
将一个 OpenAI API 密钥存储在你的 CI 提供方的密钥存储中,名称为
CODEX_SECURITY_API_KEY。
将此密钥直接映射到扫描步骤的 OPENAI_API_KEY 环境
变量。将凭据限定在扫描进程范围内,并使用
--auth api-key 显式选择它。
运行器需要:
- Node.js 22.13.0 或更高版本。
- Python 3.10 或更高版本。
- 已发布的
@openai/codex-security软件包,安装在 仓库检出目录之外。 - 拉取请求或合并请求的头部和基准历史记录,以便 Git 计算 合并基点。
添加 GitHub Actions 工作流
Section titled “添加 GitHub Actions 工作流”对于私有或内部仓库,请先启用 GitHub Code Security 然后再上传 SARIF。
创建 .github/workflows/codex-security.yml。在检出拉取
请求之前,将 @openai/codex-security 安装到
$RUNNER_TEMP/codex-security 下,使可信可执行文件可在
$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该工作流会检出拉取请求 head,计算其合并基点,并
扫描这些修订版本之间已提交的更改。完整历史记录可保持
目标精确。 persist-credentials: false 会使仓库令牌不进入
已检出的 Git 配置。在检出前安装 CLI 并
运行其绝对路径,可避免仓库控制的可执行文件接触
扫描凭据。 --auth api-key 会显式选择作用域限定的 API 密钥。
扫描会将其历史记录保存在仓库之外的可写状态目录中。
。
--json 会向 stdout 写入一个完整的 JSON 文档,因此工作流可以直接保存
它。进度、完成摘要和错误仍保留在 stderr。这
不同于 codex exec --json,后者会发出 JSON Lines 事件流。
导出步骤会读取已完成且已封存的扫描,并写入 SARIF。它不会改动 Codex 运行时和凭据。扫描工件可能包含有漏洞的 源代码片段、证据和修复详情。请为你的仓库选择合适的访问控制和 较短的保留期限。
添加 GitLab CI/CD 流水线
Section titled “添加 GitLab CI/CD 流水线”GitLab 可以摄取
SARIF 2.1.0 报告
在 GitLab Ultimate 19.2 或更高版本中。在运行流水线之前,添加一个已遮蔽且隐藏的
CODEX_SECURITY_API_KEY CI/CD 变量。
将 security 阶段和 Codex Security 作业添加到根 .gitlab-ci.yml。
保留文件中所有现有阶段和作业。该示例默认扫描合并请求
变更。将 CODEX_SECURITY_FULL_SCAN_DEFAULT_BRANCH 设置为 "true"
以同时扫描完整的默认分支:
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默认情况下,该作业仅针对同一
项目中分支发起的合并请求运行,因此复刻流水线不会收到扫描凭据。将
CODEX_SECURITY_FULL_SCAN_DEFAULT_BRANCH 设置为 "true" 可在组、项目或
流水线级别同时在默认分支上运行标准完整扫描。完整
扫描比差异扫描耗时更长、成本更高。
GIT_DEPTH: "0" 提供计算合并基点所需的历史记录,来源为
CI_MERGE_REQUEST_DIFF_BASE_SHA 和 CI_COMMIT_SHA 用于合并请求扫描。
该作业会安装 CLI 到 /tmp下,通过绝对路径运行它,并且只向扫描进程暴露
API 密钥。 artifacts: when: always 会在扫描失败时保留 SARIF
报告,而 artifacts:access: maintainer 会限制对
详细扫描结果的访问。
对 .gitlab-ci.yml 的更改可能会暴露 CI/CD 变量,因此在运行作业前请审查流水线
变更。如果你
保护 CODEX_SECURITY_API_KEY,
GitLab 会使其仅可用于受保护分支之间的同项目合并请求,
且仅当用户可以访问目标分支时才可用。
选择严重性策略
Section titled “选择严重性策略”两个示例都是仅报告模式,因为它们省略了 --fail-on-severity。当你
准备好让发现影响检查时,请向扫描
命令添加阈值:
"$CODEX_SECURITY_BIN" scan . \ --diff origin/main \ --output-dir /path/outside/repository/results \ --fail-on-severity high支持的阈值包括 critical、 high、 medium和 low。一个
阈值会包含该严重性及以上级别的发现。
扫描步骤使用以下退出码:
| 退出 | 含义 |
|---|---|
0 |
扫描已完成且覆盖范围完整,任何已配置策略均已通过。 |
1 |
已完成的扫描包含达到或超过阈值的发现。 |
2 |
该 CLI 发现输入或运行时错误,或已完成的扫描覆盖范围不完整。 |
130 |
Ctrl-C 中断了扫描。 |
143 |
SIGTERM 终止了扫描。 |
覆盖范围为 partial 或 unknown 的扫描会返回 2,即使没有严重性
策略也是如此。 CLI 仍会写入其可用发现和覆盖范围。请先审查
中的延期区域 coverage.json 再将检查视为结论性结果。
使用现有结果目录重试
Section titled “使用现有结果目录重试”为每个 CI 作业使用新的运行器目录。对于持久化或自托管的
运行器,请使用 --archive-existing保留较早的结果:
"$CODEX_SECURITY_BIN" scan . \ --diff origin/main \ --output-dir /path/outside/repository/results \ --archive-existing该命令会归档较早的结果,并从空的扫描目录开始。
排查 CI 扫描问题
Section titled “排查 CI 扫描问题”- 未知的 Git 引用或意外的差异: 获取基准和头部历史记录, 计算合并基点,并显式传入两个修订版本。
- 受保护或非空输出目录: 选择一个私有目录
位于外层 Git 工作区之外。使用
--archive-existing当 目录已包含结果时。 - 缺少凭据: 确认
CODEX_SECURITY_API_KEY可供 受信任的工作流或流水线使用,并直接映射到扫描进程的OPENAI_API_KEY环境变量。 - 扫描历史记录错误: 将
CODEX_SECURITY_STATE_DIR设置为可写的 仓库外目录。 - Python 设置错误: 确认运行器使用 Python 3.10 或更高版本。
- 覆盖范围不完整: 审查
coverage.json,包括延迟处理的表面 和开放问题,然后使用适当的目标或环境重新运行。 - SARIF 导出错误: 确认扫描已完成,并且完整扫描 目录可用。导出会先验证密封的工件,然后再写入 SARIF。
- SARIF 上传错误: 对于 GitHub Actions,确认你的组织
已为该仓库启用 GitHub Code Security,并且工作流授予
actions: read、contents: read和security-events: write。对于 GitLab CI/CD,确认项目使用 GitLab Ultimate 19.2 或更高版本,并且 作业通过 SARIF 2.1.0 上传一个artifacts:reports:sarif文件。
有关每个命令、标志、工件和输出字段,请参阅 CLI 参考。有关基于插件的交互式 CI 审查,请参阅 审查代码更改的安全性。