中文

在 GitLab CI/CD 中运行 Codex Security

在 GitLab CI/CD 中运行 Codex Security,以扫描已提交的更改和受保护 分支、将发现发布到 GitLab Security,并可选择在草稿合并请求中提出经过验证的 修复。

该工作流将扫描凭据与仓库写入权限分离。 生成的更改在合并前始终需要人工评审。

先从仅扫描报告开始。只有在检查项目的 运行器、发现和凭据边界后,才启用修复。

开始之前

你需要:

  • 一个配有可信运行器的 GitLab 项目,该运行器需支持 Codex 沙箱的 用户命名空间。
  • GitLab 项目的 Maintainer 或 Owner 角色,以便配置 项目 CI/CD 变量和受保护 资源。
  • 一个拥有 Codex Security 访问权限的 OpenAI API key。使用 Platform API key 的组织可以申请 Cyber 的 Trusted Access。 使用 ChatGPT 身份验证的个人可以使用个人 Trusted Access 流程。某些账户或仓库需要此 权限才能执行完整仓库扫描。
  • GitLab Ultimate 19.2 或更高版本,用于摄取 SARIF 2.1.0
  • 完整的 Git 历史记录,以便合并请求作业计算合并基点。

流水线镜像会安装 Node.js 26、Python 3、Git、rg 和固定版本的 Codex Security CLI。自动修复还需要一个现有的 回归测试,以及一个无需受保护凭据即可运行仓库所控制命令的运行器。

从仅扫描流水线开始

创建一个名为 CODEX_SECURITY_API_KEY 的已掩码、隐藏且受保护的 GitLab CI/CD 变量。使用具有 Codex Security 访问权限的 OpenAI Platform API key,并将其环境作用域设为 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:
    - npm install --prefix /tmp/codex-security-cli --ignore-scripts --no-audit --no-fund @openai/codex-security@0.1.20
  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" \
          --json
      scan_exit="$?"
      set -e
      unset codex_security_api_key

      case "$scan_exit" in
        0|1|2) ;;
        *) 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 的每一项更改。 这个最小示例有意省略了完整扫描和修复。

采用生产流水线

  1. 下载完整的 GitLab 流水线, 并将其保存为仓库根目录中的 .gitlab-ci.yml。如果仓库 已有流水线,请将示例中的阶段、隐藏模板和 作业合并到现有文件中。
  2. 保留现有的构建、测试和部署阶段。如果项目使用 workflow: rules,请确认它允许你要扫描的流水线事件。

该示例添加了 security_scansecurity_remediationsecurity_publishsecurity_gate 阶段。仅扫描报告只需要 CODEX_SECURITY_API_KEY

默认情况下,扫描作业仅针对受保护分支之间同一项目内的合并请求运行。 设置 CODEX_SECURITY_FULL_SCAN_DEFAULT_BRANCH=true,以扫描 受保护默认分支的推送和手动流水线。设置 CODEX_SECURITY_SCHEDULED_DEEP_SCAN=true 并配置明确的时间和成本 预算,以便在受保护的默认分支上启用定时深度扫描。

只有满足以下条件时,合并请求流水线才能访问受保护变量和运行器:

来自 fork 仓库的流水线和不受保护的合并请求不会收到扫描 凭据。运行包含密钥的作业前,请评审对 .gitlab-ci.yml 的每一项 更改。对变量进行掩码和隐藏并不能让不可信的 CI 代码 变得安全。

运行扫描并评审发现

创建一个符合条件的受保护合并请求,或在 受保护的默认分支上运行流水线。在运行需要付费的 完整仓库扫描前,先从较小的差异开始。

打开 codex-security 作业,并确认其构件包括:

  • scan-manifest.json
  • findings.json
  • coverage.json
  • results.sarif
  • scan-exit-code.txt

然后打开流水线的 Security 选项卡,查看摄取警告,并确认 发现标识符、严重性级别和源代码位置。默认分支扫描 还会创建项目漏洞记录。合并请求发现会显示在 流水线的 Security 选项卡或合并请求安全小组件中,但不会创建 项目级漏洞记录。

请限制构件访问权限,因为扫描结果可能包含易受攻击的源代码 片段、证据和修复详情。

选择扫描配置

流水线会根据触发方式选择配置:

触发方式 目标 模式 工作量
受保护的同项目合并请求 已提交的差异 standard low
选择启用的受保护默认分支推送或手动流水线 完整仓库 standard high
受保护默认分支上选择启用的计划任务 完整仓库 deep xhigh

合并请求扫描将反馈聚焦于已提交的更改。 默认分支扫描检查已集成的仓库。定时深度扫描 提供更广泛的周期性覆盖。完成一次差异扫描只适用于该项 更改,并不表示整个仓库没有问题。

工作流会将 CLI 安装在仓库外,并通过绝对 路径运行。其试运行预检会使用进程作用域的 API key,但不会启动 付费扫描,也不会验证 API 身份验证、Codex Security 访问权限、配额或模型 可用性。

工作流会将扫描状态和结果写入工作树外部,并将 OPENAI_API_KEY 限定在扫描进程内。CLI 接收一组精简且明确的 环境变量,而不会继承每一个 GitLab 变量。对于差异扫描, 工作流会计算合并基点,并将扫描绑定到已评审的基准修订和 头部修订。

该示例将 @openai/codex-security 固定为 0.1.20。更改固定版本前,请重新测试身份验证、 构件、SARIF 摄取和策略门控。

将报告与策略执行分离

GitLab 从成功的报告作业中摄取 SARIF。流水线会先发布 报告,然后在单独的 codex-security-gate 作业中恢复扫描器的退出状态。

报告作业接受退出代码为 01 的发现。只有当扫描清单证明扫描已完成、覆盖范围明确为 partial,且存在非空的 SARIF 报告时,才接受退出 代码 2。其他运行时、 配置或导出失败仍会阻止流水线。

最终门控会保留以下扫描器退出代码:

退出代码 含义
0 扫描以完整覆盖范围完成,并通过了策略检查。
1 扫描完成,并发现了达到或超过所配置阈值的问题。
2 扫描覆盖范围不完整,或出现输入或运行时错误。

在校准部分覆盖范围期间,该示例暂时允许退出代码 2。 如果不完整的覆盖范围必须阻止流水线,请移除此允许项。

修复和发布会在最终策略门控之前运行。即使门控随后 导致流水线失败,符合条件的发现仍可生成经过验证的草稿合并请求。

启用经过验证的修复

自动修复为可选功能,并且仅针对受保护默认分支 流水线运行。Codex 修复进程和仓库控制的验证 命令不会收到 GitLab 项目访问令牌或运行器注入的 凭据。

安全契约包含三个部分:仓库控制的命令绝不会 收到 OpenAI 或 GitLab 凭据;只有发布作业会获得 仓库写入权限;每一项生成的更改都会保持草稿状态,直到 人工评审并合并。

该工作流:

  1. 要求扫描覆盖完整,并存在严重性为 highcritical 的 发现。
  2. 确认所配置的回归测试在修补前失败。
  3. 生成聚焦的补丁,并拒绝对 CI、凭据、二进制文件或 其他受保护文件的更改。
  4. 在没有 OpenAI、GitLab、注册表、部署或 作业令牌凭据的情况下运行回归测试。
  5. 使用 verify-fix 返回 fixedstill_vulnerableinconclusive。 只有当 verify-fix 返回 fixed,且 验证进程未更改补丁时,作业才会发布补丁。

设置以下受保护变量以启用修复:

  • CODEX_SECURITY_ENABLE_REMEDIATION 设为 true
  • CODEX_SECURITY_VERIFICATION_COMMAND 设为一个现有的回归测试,该测试 在修复前以 1 退出,修复后以 0 退出。
  • 可选择将 CODEX_SECURITY_SETUP_COMMAND 设为非交互式依赖项 设置命令。

请选择用于验证底层安全不变量的回归测试,而不是 某种特定实现。对生成的测试和 源代码更改应用同等严格的评审。

高级:仓库命令隔离

validatepatchverify-fix 命令会收到进程作用域的 CODEX_API_KEY。仓库控制的设置和测试命令会以 单独的非特权用户身份,在已跟踪源文件的可写副本中运行。 该副本有意排除了 Git 元数据、子模块内容和 下载的构件。需要 .git 或 子模块的设置和测试命令必须在单独设计的无凭据作业中运行。

只有归 root 所有的 Codex 步骤可以访问规范检出目录或 GitLab 的 相邻文件变量目录。该副本的纯净环境仅包含 PATHHOMELANGCICI_PROJECT_DIR。如果某个命令需要其他 非密钥值,请在评审该命令后将其添加到允许列表。如果你的 运行器无法切换用户,请先将验证移至单独的无凭据 作业,再启用修复。

发布草稿合并请求

创建一个 GitLab 项目访问 令牌, 使用 Developer 角色以及 apiwrite_repository 作用域。将其存储为 仅限 codex-security/publish 环境作用域的 受保护、已掩码且隐藏的 GITLAB_REMEDIATION_TOKEN

设置 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.1.20;更改前请重新测试
CODEX_SECURITY_FULL_SCAN_DEFAULT_BRANCH 默认分支完整扫描 明确选择启用;默认关闭
CODEX_SECURITY_SCHEDULED_DEEP_SCAN 定时深度扫描 明确选择启用;默认关闭
CODEX_SECURITY_DEEP_MAX_TIME_HOURS 定时深度扫描 所需时间预算必须大于 0 且小于 8
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;允许范围为 120
CODEX_SECURITY_CREATE_MR 创建草稿合并请求 受保护的选择启用项;默认关闭
GITLAB_REMEDIATION_TOKEN 创建草稿合并请求 作用域限定为 codex-security/publish 的 Developer 项目令牌
CODEX_SECURITY_GITLAB_INTERNAL_URL 可选的自托管发布 运行器可以访问 GitLab 源站
CODEX_SECURITY_MR_TEST_COMMAND 发布草稿合并请求 必需的非密钥、项目专用回归测试
CODEX_SECURITY_MR_SETUP_COMMAND 可选的修复分支设置 非密钥依赖项设置

GitLab 提供 CI_* 变量。流水线会管理 CODEX_SECURITY_BINCODEX_SECURITY_EFFORTCODEX_SECURITY_MODECODEX_SECURITY_STATE_DIRCODEX_SECURITY_TARGET;不要将它们配置为 项目变量。对于差异扫描,CLI 会从规范化的基准修订和头部修订 派生规范目标标识。

调整执行策略和成本

为合并请求反馈使用聚焦的差异扫描,为默认分支使用 标准仓库扫描,并使用定时深度扫描获得更广泛的覆盖范围。两种 完整仓库配置默认均处于关闭状态。定时深度扫描还需要 CODEX_SECURITY_DEEP_MAX_TIME_HOURSCODEX_SECURITY_DEEP_MAX_COST;请让 CLI 时间预算低于作业的八小时超时限制。设置预算前,请测量 有代表性的运行。请将 --max-cost 视为预估成本保护阈值,而不是 硬性账单上限。

先从仅报告扫描开始。等团队评审过 有代表性的发现、覆盖范围、成本和运行时间后,再添加 --fail-on-severity。有关严重性策略和退出代码 的详情,请参阅在 CI 中运行 Codex Security

当作业失败时:

  • 缺少扫描构件说明存在配置或运行器问题。
  • 已有构件但覆盖范围不完整时,需要检查 coverage.json
  • 缺少 GitLab 发现时,需要检查 SARIF 报告作业是否 成功,以及 GitLab 是否接受了报告。
  • 修复被跳过时,需要检查受保护分支、完整 覆盖范围、发现严重性、验证命令和选择启用变量。
  • 发布错误需要检查项目令牌的角色、作用域和 环境限制。

有关每个命令、标志和构件,请参阅 Codex Security CLI 参考