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 cho bước kiểm tra thất bại tại một 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 một OpenAI API key trong kho bí mật của nhà cung cấp CI dưới tên
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 cho quy trình quét và dùng
--auth api-key để chọn rõ ràng thông tin đó.
Chỉ chạy quy trình làm việc cho những kho lưu trữ và pull request mà bạn tin cậy. Các lượt quét sử dụng quyền cục bộ của runner và không tạm dừng để xin phê duyệt. Quy trình quét có thể kế thừa môi trường của job, vì vậy đừng đưa các token và thông tin xác thực đám mây không liên quan vào môi trường đó.
Runner cần:
- Node.js 22 (22.13.0 trở lên), 24 hoặc 26.
- 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ử head và base của pull request hoặc merge request để Git có thể tính toán 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 head của pull request, tính toán merge base và
quét các thay đổi đã commit giữa những 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 tách các tệp thực thi do kho lưu trữ kiểm soát khỏi
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.
Lượt quét lưu lịch sử trong một thư mục trạng thái có thể ghi nằm bên ngoài
kho lưu trữ.
--json ghi một tài liệu JSON hoàn chỉnh vào stdout để 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 được ghi vào stderr. Cách này
khác với codex exec --json, vốn phát ra một luồng sự kiện JSON Lines.
Bước xuất đọc một lượt quét đã hoàn tất và được niêm phong rồi ghi SARIF. Bước này không tác động đến Codex runtime 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à thời hạn lưu giữ ngắn phù hợp với kho lưu trữ của bạn.
Thêm pipeline GitLab CI/CD
Để triển khai quy trình sản xuất có chức năng quét nhánh mặc định được bảo vệ, quét sâu theo lịch và yêu cầu chọn tham gia, kiểm soát chính sách SARIF riêng biệt cùng tùy chọn tạo yêu cầu hợp nhất nháp đã xác minh, hãy xem Chạy Codex Security trong GitLab CI/CD.
GitLab có thể nhập
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.
Ví dụ tối thiểu sau đây thêm một tác vụ security chỉ quét vào tệp
.gitlab-ci.yml ở thư mục gốc. Giữ nguyên mọi giai đoạn và tác vụ hiện có trong tệp. Theo mặc định, tác vụ này quét
các thay đổi của yêu cầu hợp nhất. Đặt CODEX_SECURITY_FULL_SCAN_DEFAULT_BRANCH
thành "true" để quét cả 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@0.1.20
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 một
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 đầy đủ tiêu chuẩn trên nhánh mặc định. Quét đầy đủ
mất nhiều thời gian và chi phí hơn quét phần thay đổi.
GIT_DEPTH: "0" cung cấp lịch sử cần thiết để tính toán 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 quy trình quét. artifacts: when: always lưu giữ báo cáo SARIF
khi lượt 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 thay đổi
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 đó cho merge request trong 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.
Hướng dẫn riêng về GitLab mở rộng tác vụ tối thiểu này thành quy trình sản xuất được liên kết ở đầu phần này.
Chọn chính sách mức độ nghiêm trọng
Cả hai ví dụ 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 từ lượt quét hiện tại ở mức độ nghiêm trọng đó trở lên.
Các phát hiện mở trước đó xuất hiện trong bản tóm tắt kho lưu trữ không ảnh hưởng đến chính sách.
Bước quét sử dụng các mã thoát sau:
| Mã thoát | Ý nghĩa |
|---|---|
0 |
Lượt 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 |
Lượt quét đã hoàn tất chứa một phát hiện ở mức ngưỡng hoặc cao hơn. |
2 |
CLI phát hiện lỗi đầu vào hoặc runtime, hoặc lượt quét đã hoàn tất có phạm vi bao phủ chưa đầy đủ. |
130 |
Ctrl-C đã ngắt lượt quét. |
143 |
SIGTERM đã chấm dứt lượt quét. |
Một lượt 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à dữ liệu 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 bằng 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ữ 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 phần thay đổi không như mong đợi: Tìm nạp lịch sử base và head, tính toán 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 quy 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 bên ngoài kho lưu trữ. - Lỗi thiết lập Python: Xác nhận rằng runner sử dụng Python 3.10 trở lên.
- Phạm vi bao phủ chưa đầy đủ: Xem xét
coverage.json, bao gồm các bề mặt bị hoãn và câu hỏi còn bỏ ngỏ, 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 lượt quét đã hoàn tất và có sẵn toàn bộ thư mục quét. 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 rằng 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 rằng 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. Để xem xét CI tương tác dựa trên plugin, hãy xem Xem xét các thay đổi mã nguồn về bảo mật.