在 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 的每一项更改。
这个最小示例有意省略了完整扫描和修复。
采用生产流水线
- 下载完整的 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 并配置明确的时间和成本
预算,以便在受保护的默认分支上启用定时深度扫描。
只有满足以下条件时,合并请求流水线才能访问受保护变量和运行器:
- 你在同一项目中保护了源分支和目标分支。
- 项目允许合并请求流水线访问受保护变量和 运行器。
- 启动流水线的用户可以推送到目标分支或合并至目标分支。
来自 fork 仓库的流水线和不受保护的合并请求不会收到扫描
凭据。运行包含密钥的作业前,请评审对 .gitlab-ci.yml 的每一项
更改。对变量进行掩码和隐藏并不能让不可信的 CI 代码
变得安全。
运行扫描并评审发现
创建一个符合条件的受保护合并请求,或在 受保护的默认分支上运行流水线。在运行需要付费的 完整仓库扫描前,先从较小的差异开始。
打开 codex-security 作业,并确认其构件包括:
scan-manifest.jsonfindings.jsoncoverage.jsonresults.sarifscan-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 作业中恢复扫描器的退出状态。
报告作业接受退出代码为 0 和 1 的发现。只有当扫描清单证明扫描已完成、覆盖范围明确为
partial,且存在非空的 SARIF 报告时,才接受退出
代码 2。其他运行时、
配置或导出失败仍会阻止流水线。
最终门控会保留以下扫描器退出代码:
| 退出代码 | 含义 |
|---|---|
0 |
扫描以完整覆盖范围完成,并通过了策略检查。 |
1 |
扫描完成,并发现了达到或超过所配置阈值的问题。 |
2 |
扫描覆盖范围不完整,或出现输入或运行时错误。 |
在校准部分覆盖范围期间,该示例暂时允许退出代码 2。
如果不完整的覆盖范围必须阻止流水线,请移除此允许项。
修复和发布会在最终策略门控之前运行。即使门控随后 导致流水线失败,符合条件的发现仍可生成经过验证的草稿合并请求。
启用经过验证的修复
自动修复为可选功能,并且仅针对受保护默认分支 流水线运行。Codex 修复进程和仓库控制的验证 命令不会收到 GitLab 项目访问令牌或运行器注入的 凭据。
安全契约包含三个部分:仓库控制的命令绝不会 收到 OpenAI 或 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 命令会收到进程作用域的
CODEX_API_KEY。仓库控制的设置和测试命令会以
单独的非特权用户身份,在已跟踪源文件的可写副本中运行。
该副本有意排除了 Git 元数据、子模块内容和
下载的构件。需要 .git 或
子模块的设置和测试命令必须在单独设计的无凭据作业中运行。
只有归 root 所有的 Codex 步骤可以访问规范检出目录或 GitLab 的
相邻文件变量目录。该副本的纯净环境仅包含
PATH、HOME、LANG、CI 和 CI_PROJECT_DIR。如果某个命令需要其他
非密钥值,请在评审该命令后将其添加到允许列表。如果你的
运行器无法切换用户,请先将验证移至单独的无凭据
作业,再启用修复。
发布草稿合并请求
创建一个 GitLab 项目访问
令牌,
使用 Developer 角色以及 api 和 write_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;允许范围为 1 到 20 |
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_BIN、CODEX_SECURITY_EFFORT、CODEX_SECURITY_MODE、
CODEX_SECURITY_STATE_DIR 和 CODEX_SECURITY_TARGET;不要将它们配置为
项目变量。对于差异扫描,CLI 会从规范化的基准修订和头部修订
派生规范目标标识。
调整执行策略和成本
为合并请求反馈使用聚焦的差异扫描,为默认分支使用
标准仓库扫描,并使用定时深度扫描获得更广泛的覆盖范围。两种
完整仓库配置默认均处于关闭状态。定时深度扫描还需要
CODEX_SECURITY_DEEP_MAX_TIME_HOURS 和 CODEX_SECURITY_DEEP_MAX_COST;请让
CLI 时间预算低于作业的八小时超时限制。设置预算前,请测量
有代表性的运行。请将 --max-cost 视为预估成本保护阈值,而不是
硬性账单上限。
先从仅报告扫描开始。等团队评审过
有代表性的发现、覆盖范围、成本和运行时间后,再添加 --fail-on-severity。有关严重性策略和退出代码
的详情,请参阅在 CI 中运行 Codex
Security。
当作业失败时:
- 缺少扫描构件说明存在配置或运行器问题。
- 已有构件但覆盖范围不完整时,需要检查
coverage.json。 - 缺少 GitLab 发现时,需要检查 SARIF 报告作业是否 成功,以及 GitLab 是否接受了报告。
- 修复被跳过时,需要检查受保护分支、完整 覆盖范围、发现严重性、验证命令和选择启用变量。
- 发布错误需要检查项目令牌的角色、作用域和 环境限制。
有关每个命令、标志和构件,请参阅 Codex Security CLI 参考。