2 2
3> For the complete documentation index, see [llms.txt](https://learn.chatgpt.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to the page URL.3> For the complete documentation index, see [llms.txt](https://learn.chatgpt.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to the page URL.
4 4
5Run the Codex Security CLI in CI to review the exact changes in a pull request,5Run the Codex Security CLI in CI to review the exact changes in a pull request
6keep findings and coverage, and optionally fail the check at a chosen6or merge request, keep findings and coverage, and optionally fail the check at
7severity. Start with advisory results, review scan quality and runtime, then7a chosen severity. Start with advisory results, review scan quality and
8add a severity policy that fits your repository.8runtime, then add a severity policy that fits your repository.
9 9
10Install the public `@openai/codex-security` package. Running scans still10Install the public `@openai/codex-security` package. Running scans still
11 requires Codex Security access.11 requires Codex Security access.
12 12
13This guide uses GitHub Actions. The same scan and export commands work in other13This guide includes examples for GitHub Actions and GitLab CI/CD. The same scan
14CI systems.14and export commands work in other CI systems.
15 15
16## Prepare the workflow16## Prepare the workflow
17 17
18Store an OpenAI API key as a repository or organization secret named18Store an OpenAI API key in your CI provider's secret store as
19`CODEX_SECURITY_API_KEY`.19`CODEX_SECURITY_API_KEY`.
20 20
21Map this secret directly to the scan step's `OPENAI_API_KEY` environment21Map this secret directly to the scan step's `OPENAI_API_KEY` environment
28- Python 3.10 or later.28- Python 3.10 or later.
29- The published `@openai/codex-security` package, installed outside the29- The published `@openai/codex-security` package, installed outside the
30 repository checkout.30 repository checkout.
31- The pull-request head and base history so Git can calculate the merge base.31- The pull-request or merge-request head and base history so Git can calculate
32- [GitHub Code Security](https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/uploading-a-sarif-file-to-github)32 the merge base.
33 enabled for private or internal repositories when you upload SARIF.
34 33
35## Add the GitHub Actions workflow34## Add the GitHub Actions workflow
36 35
36For private or internal repositories, enable
37[GitHub Code Security](https://docs.github.com/en/code-security/code-scanning/integrating-with-code-scanning/uploading-a-sarif-file-to-github)
38before you upload SARIF.
39
37Create `.github/workflows/codex-security.yml`. Before checking out the pull40Create `.github/workflows/codex-security.yml`. Before checking out the pull
38request, install `@openai/codex-security@0.1.3` under41request, install `@openai/codex-security` under
39`$RUNNER_TEMP/codex-security` so the trusted executable is available at42`$RUNNER_TEMP/codex-security` so the trusted executable is available at
40`$RUNNER_TEMP/codex-security/node_modules/.bin/codex-security`:43`$RUNNER_TEMP/codex-security/node_modules/.bin/codex-security`:
41 44
72 --ignore-scripts \75 --ignore-scripts \
73 --no-audit \76 --no-audit \
74 --no-fund \77 --no-fund \
75 @openai/codex-security@0.1.378 @openai/codex-security
76 79
77 - name: Verify Codex Security80 - name: Verify Codex Security
78 env:81 env:
163source snippets, evidence, and remediation details. Choose access controls and a166source snippets, evidence, and remediation details. Choose access controls and a
164short retention window appropriate for your repository.167short retention window appropriate for your repository.
165 168
169## Add the GitLab CI/CD pipeline
170
171GitLab can ingest
172[SARIF 2.1.0 reports](https://docs.gitlab.com/ci/yaml/artifacts_reports/#artifactsreportssarif)
173on GitLab Ultimate 19.2 or later. Add a masked and hidden
174`CODEX_SECURITY_API_KEY` CI/CD variable before you run the pipeline.
175
176Add the `security` stage and Codex Security job to the root `.gitlab-ci.yml`.
177Keep any existing stages and jobs in the file. The example scans merge-request
178changes by default. Set `CODEX_SECURITY_FULL_SCAN_DEFAULT_BRANCH` to `"true"`
179to also scan the complete default branch:
180
181```yaml
182variables:
183 CODEX_SECURITY_FULL_SCAN_DEFAULT_BRANCH: "false"
184
185stages:
186 - test
187 - security
188
189codex-security:
190 stage: security
191 image: node:26-bookworm-slim
192 rules:
193 - if: '$CI_PIPELINE_SOURCE == "merge_request_event" && $CI_MERGE_REQUEST_SOURCE_PROJECT_ID == $CI_PROJECT_ID'
194 variables:
195 CODEX_SECURITY_SCAN_SCOPE: "diff"
196 - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CODEX_SECURITY_FULL_SCAN_DEFAULT_BRANCH == "true"'
197 variables:
198 CODEX_SECURITY_SCAN_SCOPE: "full"
199 variables:
200 GIT_DEPTH: "0"
201 CODEX_SECURITY_CLI_DIR: "/tmp/codex-security-cli"
202 before_script:
203 - |
204 set -eu
205 apt-get update -qq
206 apt-get install -y -qq --no-install-recommends \
207 ca-certificates \
208 git \
209 python3 \
210 ripgrep
211 npm install \
212 --prefix "$CODEX_SECURITY_CLI_DIR" \
213 --ignore-scripts \
214 --no-audit \
215 --no-fund \
216 @openai/codex-security
217 export CODEX_SECURITY_BIN="$CODEX_SECURITY_CLI_DIR/node_modules/.bin/codex-security"
218 test -x "$CODEX_SECURITY_BIN"
219 "$CODEX_SECURITY_BIN" --version
220 script:
221 - |
222 set -eu
223 if test -z "${CODEX_SECURITY_API_KEY:-}"; then
224 echo "Set the CODEX_SECURITY_API_KEY CI/CD variable." >&2
225 exit 2
226 fi
227
228 codex_security_api_key="$CODEX_SECURITY_API_KEY"
229 unset CODEX_SECURITY_API_KEY
230
231 case "${CODEX_SECURITY_SCAN_SCOPE:-}" in
232 diff)
233 BASE_SHA="$CI_MERGE_REQUEST_DIFF_BASE_SHA"
234 HEAD_SHA="$CI_COMMIT_SHA"
235 BASE_REVISION="$(git merge-base "$BASE_SHA" "$HEAD_SHA")"
236 set -- --diff "$BASE_REVISION" --head "$HEAD_SHA"
237 echo "Scanning committed changes from $BASE_REVISION to $HEAD_SHA."
238 ;;
239 full)
240 set -- --mode standard
241 echo "Scanning the complete default branch at $CI_COMMIT_SHA."
242 ;;
243 *)
244 echo "Unsupported Codex Security scan scope: ${CODEX_SECURITY_SCAN_SCOPE:-unset}" >&2
245 exit 2
246 ;;
247 esac
248
249 export CODEX_SECURITY_STATE_DIR="/tmp/codex-security-state-$CI_JOB_ID"
250 SCAN_DIR="/tmp/codex-security-results-$CI_JOB_ID"
251 JSON_FILE="/tmp/codex-security-$CI_JOB_ID.json"
252 SARIF_FILE="/tmp/codex-security-$CI_JOB_ID.sarif"
253
254 install -d -m 700 "$CODEX_SECURITY_STATE_DIR" "$SCAN_DIR"
255
256 set +e
257 OPENAI_API_KEY="$codex_security_api_key" \
258 "$CODEX_SECURITY_BIN" scan . \
259 "$@" \
260 --auth api-key \
261 --output-dir "$SCAN_DIR" \
262 --json > "$JSON_FILE"
263 scan_exit="$?"
264 set -e
265 unset codex_security_api_key
266
267 install -d -m 700 codex-security-artifacts/results
268 cp -R "$SCAN_DIR"/. codex-security-artifacts/results/
269 if test -s "$JSON_FILE"; then
270 cp "$JSON_FILE" codex-security-artifacts/codex-security.json
271 fi
272 printf '%s\n' "$scan_exit" > codex-security-artifacts/scan-exit-code.txt
273
274 export_exit=0
275 if test -f "$SCAN_DIR/scan-manifest.json"; then
276 set +e
277 "$CODEX_SECURITY_BIN" export "$SCAN_DIR" \
278 --export-format sarif \
279 --source-root "$CI_PROJECT_DIR" \
280 --output "$SARIF_FILE"
281 export_exit="$?"
282 set -e
283 if test -s "$SARIF_FILE"; then
284 cp "$SARIF_FILE" codex-security-artifacts/codex-security.sarif
285 fi
286 fi
287
288 if test "$scan_exit" -ne 0; then
289 exit "$scan_exit"
290 fi
291 exit "$export_exit"
292 artifacts:
293 when: always
294 access: maintainer
295 expire_in: 7 days
296 paths:
297 - codex-security-artifacts/
298 reports:
299 sarif: codex-security-artifacts/codex-security.sarif
300```
301
302By default, the job runs only for merge requests from branches in the same
303project, so fork pipelines don't receive the scan credential. Set
304`CODEX_SECURITY_FULL_SCAN_DEFAULT_BRANCH` to `"true"` at the group, project, or
305pipeline level to also run a standard full scan on the default branch. Full
306scans take longer and cost more than diff scans.
307
308`GIT_DEPTH: "0"` provides the history needed to calculate the merge base from
309`CI_MERGE_REQUEST_DIFF_BASE_SHA` and `CI_COMMIT_SHA` for merge-request scans.
310
311The job installs the CLI under `/tmp`, runs it by absolute path, and exposes the
312API key only to the scan process. `artifacts: when: always` preserves the SARIF
313report when the scan fails, while `artifacts:access: maintainer` limits access
314to detailed scan results.
315
316Changes to `.gitlab-ci.yml` can expose CI/CD variables, so review pipeline
317changes before running the job. If you
318[protect `CODEX_SECURITY_API_KEY`](https://docs.gitlab.com/ci/pipelines/merge_request_pipelines/#control-access-to-protected-variables-and-runners),
319GitLab makes it available only for same-project merge requests between
320protected branches and only when the user can access the target branch.
321
166## Choose a severity policy322## Choose a severity policy
167 323
168The above workflow is report-only because it omits `--fail-on-severity`.324Both examples are report-only because they omit `--fail-on-severity`. Once you
169Once you are ready to make findings affect the check, add a threshold to the325are ready to make findings affect the check, add a threshold to the scan
170scan command:326command:
171 327
172```bash328```bash
173"$CODEX_SECURITY_BIN" scan . \329"$CODEX_SECURITY_BIN" scan . \
214- **Protected or non-empty output directory:** Choose a private directory370- **Protected or non-empty output directory:** Choose a private directory
215 outside the enclosing Git worktree. Use `--archive-existing` when the371 outside the enclosing Git worktree. Use `--archive-existing` when the
216 directory already contains results.372 directory already contains results.
217- **Missing credentials:** Confirm the `CODEX_SECURITY_API_KEY` repository373- **Missing credentials:** Confirm that `CODEX_SECURITY_API_KEY` is available to
218 secret is available to the trusted workflow and mapped directly to the scan374 the trusted workflow or pipeline and mapped directly to the scan process's
219 step's `OPENAI_API_KEY` environment variable.375 `OPENAI_API_KEY` environment variable.
220- **Scan history error:** Set `CODEX_SECURITY_STATE_DIR` to a writable376- **Scan history error:** Set `CODEX_SECURITY_STATE_DIR` to a writable
221 directory outside the repository.377 directory outside the repository.
222- **Python setup error:** Confirm that the runner uses Python 3.10 or later.378- **Python setup error:** Confirm that the runner uses Python 3.10 or later.
225- **SARIF export error:** Confirm that the scan completed and the full scan381- **SARIF export error:** Confirm that the scan completed and the full scan
226 directory is available. Export validates the sealed artifacts before writing382 directory is available. Export validates the sealed artifacts before writing
227 SARIF.383 SARIF.
228- **SARIF upload error:** For a private or internal repository, confirm that384- **SARIF upload error:** For GitHub Actions, confirm that your organization
229 your organization turned on GitHub Code Security for the repository and the385 turned on GitHub Code Security for the repository and the workflow grants
230 workflow grants `actions: read`, `contents: read`, and386 `actions: read`, `contents: read`, and `security-events: write`. For GitLab
231 `security-events: write`.387 CI/CD, confirm that the project uses GitLab Ultimate 19.2 or later and that
388 the job uploads a SARIF 2.1.0 file through `artifacts:reports:sarif`.
232 389
233For every command, flag, artifact, and output field, see the [CLI390For every command, flag, artifact, and output field, see the [CLI
234reference](https://learn.chatgpt.com/docs/security/cli/reference). For an interactive plugin-based CI391reference](https://learn.chatgpt.com/docs/security/cli/reference). For an interactive plugin-based CI