Chạy Codex Security trong CI
Quét các thay đổi trong pull request và merge request, lưu giữ kết quả có cấu trúc, tải SARIF lên và thiết lập chính sách mức độ nghiêm trọng.
Chạy Codex Security CLI trong CI để xem xét chính xác các thay đổi trong một pull request hoặc merge request, lưu giữ các phát hiện và phạm vi bao phủ, đồng thời tùy chọn làm bước kiểm tra thất bại ở mức độ nghiêm trọng đã chọn. Hãy bắt đầu với kết quả mang tính tư vấn, xem xét chất lượng quét và thời gian chạy, sau đó thêm chính sách mức độ nghiêm trọng phù hợp với kho lưu trữ của bạn.
Hướng dẫn này bao gồm các ví dụ cho GitHub Actions và GitLab CI/CD. Các lệnh quét và xuất tương tự cũng hoạt động trong những hệ thống CI khác.
Chuẩn bị quy trình làm việc
Lưu API key của OpenAI trong kho bí mật của nhà cung cấp CI dưới dạng
CODEX_SECURITY_API_KEY.
Ánh xạ trực tiếp bí mật này tới biến môi trường OPENAI_API_KEY của bước quét.
Chỉ cấp thông tin xác thực trong phạm vi tiến trình quét và dùng
--auth api-key để chọn thông tin đó một cách rõ ràng.
Runner cần có:
- Node.js 22 trở lên.
- Python 3.10 trở lên.
- Gói
@openai/codex-securityđã phát hành, được cài đặt bên ngoài bản checkout của kho lưu trữ. - Lịch sử của phần đầu và phần gốc của pull request hoặc merge request để Git có thể tính merge base.
Thêm quy trình làm việc GitHub Actions
Đối với kho lưu trữ riêng tư hoặc nội bộ, hãy bật GitHub Code Security trước khi tải SARIF lên.
Tạo .github/workflows/codex-security.yml. Trước khi checkout pull
request, hãy cài đặt @openai/codex-security trong
$RUNNER_TEMP/codex-security để tệp thực thi đáng tin cậy có sẵn tại
$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: 7Quy trình làm việc checkout phần đầu của pull request, tính merge base của nó và
quét các thay đổi đã commit giữa các bản sửa đổi đó. Lịch sử đầy đủ giúp xác định chính xác
mục tiêu. persist-credentials: false ngăn token của kho lưu trữ xuất hiện trong
cấu hình Git đã checkout. Việc cài đặt CLI trước khi checkout và
chạy CLI bằng đường dẫn tuyệt đối giúp các tệp thực thi do kho lưu trữ kiểm soát không tiếp cận
thông tin xác thực dùng để quét. --auth api-key chọn rõ ràng API key đã được giới hạn phạm vi.
Quá trình quét lưu lịch sử trong một thư mục trạng thái có thể ghi nằm ngoài
kho lưu trữ.
--json ghi một tài liệu JSON hoàn chỉnh vào stdout, vì vậy quy trình làm việc có thể lưu
tài liệu đó trực tiếp. Tiến trình, bản tóm tắt hoàn tất và lỗi vẫn nằm trên stderr. Điều này
khác với codex exec --json, vốn phát luồng sự kiện JSON Lines.
Bước xuất đọc một bản quét đã hoàn tất và được niêm phong rồi ghi SARIF. Bước này không thay đổi môi trường chạy Codex và thông tin xác thực. Các artifact quét có thể chứa đoạn mã nguồn dễ bị tấn công, bằng chứng và chi tiết khắc phục. Hãy chọn biện pháp kiểm soát truy cập và khoảng thời gian lưu giữ ngắn phù hợp với kho lưu trữ của bạn.
Thêm pipeline GitLab CI/CD
GitLab có thể tiếp nhận
báo cáo SARIF 2.1.0
trên GitLab Ultimate 19.2 trở lên. Hãy thêm một biến CI/CD
CODEX_SECURITY_API_KEY được che và ẩn trước khi chạy pipeline.
Thêm giai đoạn security và job Codex Security vào .gitlab-ci.yml ở thư mục gốc.
Giữ nguyên mọi giai đoạn và job hiện có trong tệp. Theo mặc định, ví dụ này quét các thay đổi
của merge request. Đặt CODEX_SECURITY_FULL_SCAN_DEFAULT_BRANCH thành "true"
để cũng quét toàn bộ nhánh mặc định:
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.sarifTheo mặc định, job chỉ chạy cho merge request từ các nhánh trong cùng
dự án, vì vậy pipeline của fork không nhận được thông tin xác thực dùng để quét. Đặt
CODEX_SECURITY_FULL_SCAN_DEFAULT_BRANCH thành "true" ở cấp nhóm, dự án hoặc
pipeline để cũng chạy một lượt quét toàn phần tiêu chuẩn trên nhánh mặc định. Quét toàn phần
mất nhiều thời gian và chi phí hơn quét diff.
GIT_DEPTH: "0" cung cấp lịch sử cần thiết để tính merge base từ
CI_MERGE_REQUEST_DIFF_BASE_SHA và CI_COMMIT_SHA cho các lượt quét merge request.
Job cài đặt CLI trong /tmp, chạy CLI bằng đường dẫn tuyệt đối và chỉ cung cấp
API key cho tiến trình quét. artifacts: when: always giữ lại báo cáo SARIF
khi quá trình quét thất bại, còn artifacts:access: maintainer giới hạn quyền truy cập
vào kết quả quét chi tiết.
Các thay đổi đối với .gitlab-ci.yml có thể làm lộ biến CI/CD, vì vậy hãy xem xét các thay đổi
của pipeline trước khi chạy job. Nếu bạn
bảo vệ CODEX_SECURITY_API_KEY,
GitLab chỉ cung cấp biến này cho các merge request cùng dự án giữa
các nhánh được bảo vệ và chỉ khi người dùng có thể truy cập nhánh đích.
Chọn chính sách mức độ nghiêm trọng
Cả hai ví dụ đều chỉ tạo báo cáo vì chúng bỏ qua --fail-on-severity. Khi bạn
đã sẵn sàng để các phát hiện ảnh hưởng đến bước kiểm tra, hãy thêm một ngưỡng vào lệnh
quét:
"$CODEX_SECURITY_BIN" scan . \
--diff origin/main \
--output-dir /path/outside/repository/results \
--fail-on-severity highCác ngưỡng được hỗ trợ là critical, high, medium và low. Một
ngưỡng bao gồm các phát hiện ở mức độ nghiêm trọng đó trở lên.
Bước quét sử dụng các mã thoát sau:
| Mã thoát | Ý nghĩa |
|---|---|
0 |
Quá trình quét hoàn tất với phạm vi bao phủ đầy đủ và mọi chính sách đã cấu hình đều đạt yêu cầu. |
1 |
Bản quét đã hoàn tất chứa một phát hiện ở ngưỡng hoặc cao hơn. |
2 |
CLI phát hiện lỗi đầu vào hoặc lỗi khi chạy, hoặc bản quét đã hoàn tất có phạm vi bao phủ không đầy đủ. |
130 |
Ctrl-C đã ngắt quá trình quét. |
143 |
SIGTERM đã chấm dứt quá trình quét. |
Một bản quét có phạm vi bao phủ partial hoặc unknown sẽ trả về 2, ngay cả khi không có chính sách
mức độ nghiêm trọng. CLI vẫn ghi các phát hiện và thông tin phạm vi bao phủ hiện có. Hãy xem xét
các khu vực bị hoãn trong coverage.json trước khi coi bước kiểm tra là có tính kết luận.
Thử lại với thư mục kết quả hiện có
Sử dụng một thư mục runner mới cho mỗi job CI. Đối với runner lâu dài hoặc tự lưu trữ,
hãy lưu giữ kết quả trước đó bằng --archive-existing:
"$CODEX_SECURITY_BIN" scan . \
--diff origin/main \
--output-dir /path/outside/repository/results \
--archive-existingLệnh này lưu trữ các kết quả trước đó và bắt đầu với một thư mục quét trống.
Khắc phục sự cố quét CI
- Git ref không xác định hoặc diff không mong đợi: Tải lịch sử của phần gốc và phần đầu, tính merge base rồi truyền rõ ràng cả hai bản sửa đổi.
- Thư mục đầu ra được bảo vệ hoặc không trống: Chọn một thư mục riêng tư
bên ngoài Git worktree bao quanh. Dùng
--archive-existingkhi thư mục đã chứa kết quả. - Thiếu thông tin xác thực: Xác nhận rằng
CODEX_SECURITY_API_KEYcó sẵn cho quy trình làm việc hoặc pipeline đáng tin cậy và được ánh xạ trực tiếp tới biến môi trườngOPENAI_API_KEYcủa tiến trình quét. - Lỗi lịch sử quét: Đặt
CODEX_SECURITY_STATE_DIRthành một thư mục có thể ghi nằm ngoài kho lưu trữ. - Lỗi thiết lập Python: Xác nhận runner sử dụng Python 3.10 trở lên.
- Phạm vi bao phủ không đầy đủ: Xem xét
coverage.json, bao gồm các khu vực bị hoãn và câu hỏi chưa giải quyết, sau đó chạy lại với mục tiêu hoặc môi trường phù hợp. - Lỗi xuất SARIF: Xác nhận rằng quá trình quét đã hoàn tất và toàn bộ thư mục quét đang có sẵn. Quá trình xuất xác thực các artifact đã niêm phong trước khi ghi SARIF.
- Lỗi tải SARIF lên: Đối với GitHub Actions, hãy xác nhận tổ chức của bạn
đã bật GitHub Code Security cho kho lưu trữ và quy trình làm việc cấp
actions: read,contents: readvàsecurity-events: write. Đối với GitLab CI/CD, hãy xác nhận dự án sử dụng GitLab Ultimate 19.2 trở lên và job tải lên một tệp SARIF 2.1.0 thông quaartifacts:reports:sarif.
Để biết mọi lệnh, cờ, artifact và trường đầu ra, hãy xem tài liệu tham chiếu CLI. Để thực hiện quy trình xem xét CI tương tác dựa trên plugin, hãy xem Xem xét các thay đổi mã về bảo mật.