Запуск Codex Security в CI
Сканируйте изменения в pull request и merge request, сохраняйте структурированные результаты, загружайте SARIF и задавайте политику уровней серьезности.
Запускайте CLI Codex Security в CI, чтобы проверять конкретные изменения в pull request или merge request, сохранять обнаруженные проблемы и данные о покрытии, а также при необходимости завершать проверку с ошибкой при выбранном уровне серьезности. Начните с результатов рекомендательного характера, оцените качество и время выполнения сканирования, а затем добавьте подходящую для вашего репозитория политику уровней серьезности.
В этом руководстве приведены примеры для GitHub Actions и GitLab CI/CD. Те же команды сканирования и экспорта работают и в других системах CI.
Подготовка рабочего процесса
Сохраните API key OpenAI в хранилище секретов вашего поставщика CI под именем
CODEX_SECURITY_API_KEY.
Напрямую сопоставьте этот секрет с переменной окружения OPENAI_API_KEY
на шаге сканирования. Ограничьте область действия учетных данных процессом сканирования и используйте
--auth api-key, чтобы явно выбрать их.
Запускайте рабочий процесс только для репозиториев и pull request, которым доверяете. При сканировании используются локальные разрешения агента, и запрос подтверждения не выполняется. Процессы сканирования могут наследовать окружение задания, поэтому не включайте в него посторонние токены и учетные данные облачных служб.
Агенту требуются:
- Node.js 22 (22.13.0 или новее), 24 либо 26.
- Python 3.10 или новее.
- Опубликованный пакет
@openai/codex-security, установленный вне рабочей копии репозитория. - История головной и базовой ветвей pull request или merge request, позволяющая Git вычислить базу слияния.
Добавление рабочего процесса GitHub Actions
Для частных или внутренних репозиториев включите GitHub Code Security, прежде чем загружать SARIF.
Создайте .github/workflows/codex-security.yml. Перед получением рабочей копии pull
request установите @openai/codex-security в
$RUNNER_TEMP/codex-security, чтобы доверенный исполняемый файл был доступен по пути
$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: 7Рабочий процесс получает головную версию pull request, вычисляет ее базу слияния и
сканирует зафиксированные изменения между этими версиями. Полная история обеспечивает точность
целевого диапазона. persist-credentials: false не позволяет сохранить токен репозитория
в конфигурации Git полученной рабочей копии. Установка CLI до получения рабочей копии и
его запуск по абсолютному пути не допускают исполняемые файлы, контролируемые репозиторием,
к учетным данным сканирования. --auth api-key явно выбирает API key с ограниченной областью действия.
Сканирование сохраняет свою историю в доступном для записи каталоге состояния за пределами
репозитория.
--json записывает в stdout один полный документ JSON, поэтому рабочий процесс может сохранить
его напрямую. Ход выполнения, итоговые сводки и ошибки остаются в stderr. Это
отличается от codex exec --json, который выводит поток событий JSON Lines.
Шаг экспорта считывает завершенное и запечатанное сканирование и записывает SARIF. Он не изменяет среду выполнения Codex и учетные данные. Артефакты сканирования могут содержать уязвимые фрагменты исходного кода, доказательства и сведения об устранении проблем. Выберите подходящие для вашего репозитория средства контроля доступа и короткий срок хранения.
Добавление конвейера GitLab CI/CD
Для рабочего процесса промышленного уровня со сканированием защищённой ветви по умолчанию, включаемым по желанию плановым глубоким сканированием, отдельным применением политик к SARIF и необязательными проверенными черновиками запросов на слияние используйте руководство Запуск Codex Security в GitLab CI/CD.
GitLab может принимать
отчеты SARIF 2.1.0
в GitLab Ultimate 19.2 или более поздней версии. Перед запуском конвейера добавьте маскируемую и скрытую
переменную CI/CD CODEX_SECURITY_API_KEY.
В следующем минимальном примере в корневой файл добавляется задание security, выполняющее только сканирование
.gitlab-ci.yml. Сохраните в файле все существующие этапы и задания. По умолчанию оно сканирует
изменения в запросах на слияние. Задайте для CODEX_SECURITY_FULL_SCAN_DEFAULT_BRANCH
значение "true", чтобы также сканировать всю ветвь по умолчанию:
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.sarifПо умолчанию задание выполняется только для merge request из ветвей того же
проекта, поэтому конвейеры форков не получают учетные данные сканирования. Задайте
для CODEX_SECURITY_FULL_SCAN_DEFAULT_BRANCH значение "true" на уровне группы, проекта или
конвейера, чтобы также выполнять обычное полное сканирование ветви по умолчанию. Полное
сканирование занимает больше времени и стоит дороже, чем сканирование различий.
GIT_DEPTH: "0" предоставляет историю, необходимую для вычисления базы слияния по
CI_MERGE_REQUEST_DIFF_BASE_SHA и CI_COMMIT_SHA при сканировании merge request.
Задание устанавливает CLI в /tmp, запускает его по абсолютному пути и предоставляет
API key только процессу сканирования. artifacts: when: always сохраняет отчет SARIF,
если сканирование завершается с ошибкой, а artifacts:access: maintainer ограничивает доступ
к подробным результатам сканирования.
Изменения в .gitlab-ci.yml могут раскрыть переменные CI/CD, поэтому проверяйте изменения
конвейера перед запуском задания. Если вы
защитите CODEX_SECURITY_API_KEY,
GitLab сделает ее доступной только для merge request внутри одного проекта между
защищенными ветвями и только в том случае, если у пользователя есть доступ к целевой ветви.
Специальное руководство по GitLab расширяет это минимальное задание до рабочего процесса промышленного уровня, ссылка на который приведена в начале этого раздела.
Выбор политики уровней серьезности
Оба примера только создают отчеты, поскольку в них отсутствует --fail-on-severity. Когда вы
будете готовы учитывать обнаруженные проблемы в результате проверки, добавьте пороговое значение в команду
сканирования:
"$CODEX_SECURITY_BIN" scan . \
--diff origin/main \
--output-dir /path/outside/repository/results \
--fail-on-severity highПоддерживаются пороговые значения critical, high, medium и low. Пороговое
значение охватывает проблемы текущего сканирования с указанным или более высоким уровнем серьезности.
Ранее обнаруженные открытые проблемы, показанные в сводке репозитория, не влияют на политику.
На шаге сканирования используются следующие коды выхода:
| Код | Значение |
|---|---|
0 |
Сканирование завершилось с полным покрытием, и настроенная политика, если она есть, выполнена. |
1 |
Завершенное сканирование содержит проблему с уровнем серьезности не ниже порогового. |
2 |
CLI обнаружил ошибку входных данных или среды выполнения либо завершенное сканирование имеет неполное покрытие. |
130 |
Сканирование прервано с помощью Ctrl-C. |
143 |
Сканирование завершено сигналом SIGTERM. |
Сканирование с покрытием partial или unknown возвращает 2 даже без политики
уровней серьезности. CLI все равно записывает доступные обнаруженные проблемы и данные о покрытии. Проверьте
отложенные области в coverage.json, прежде чем считать результат проверки окончательным.
Повторный запуск с существующим каталогом результатов
Используйте отдельный новый каталог агента для каждого задания CI. На постоянном или собственном
агенте сохраните предыдущий результат с помощью --archive-existing:
"$CODEX_SECURITY_BIN" scan . \
--diff origin/main \
--output-dir /path/outside/repository/results \
--archive-existingКоманда архивирует предыдущие результаты и начинает работу с пустым каталогом сканирования.
Устранение неполадок сканирования в CI
- Неизвестная ссылка Git или неожиданные различия: Получите историю базовой и головной версий, вычислите базу слияния и явно передайте обе версии.
- Защищенный или непустой каталог вывода: Выберите частный каталог
за пределами охватывающего рабочего дерева Git. Используйте
--archive-existing, если каталог уже содержит результаты. - Отсутствуют учетные данные: Убедитесь, что
CODEX_SECURITY_API_KEYдоступен доверенному рабочему процессу или конвейеру и напрямую сопоставлен с переменной окруженияOPENAI_API_KEYпроцесса сканирования. - Ошибка истории сканирования: Задайте для
CODEX_SECURITY_STATE_DIRдоступный для записи каталог за пределами репозитория. - Ошибка настройки Python: Убедитесь, что агент использует Python 3.10 или новее.
- Неполное покрытие: Проверьте
coverage.json, включая отложенные области и открытые вопросы, затем повторите сканирование с подходящей целью или средой. - Ошибка экспорта SARIF: Убедитесь, что сканирование завершилось и доступен полный каталог сканирования. Перед записью SARIF экспорт проверяет запечатанные артефакты.
- Ошибка загрузки SARIF: Для GitHub Actions убедитесь, что ваша организация
включила GitHub Code Security для репозитория, а рабочему процессу предоставлены
actions: read,contents: readиsecurity-events: write. Для GitLab CI/CD убедитесь, что проект использует GitLab Ultimate 19.2 или более поздней версии и что задание загружает файл SARIF 2.1.0 черезartifacts:reports:sarif.
Сведения обо всех командах, флагах, артефактах и полях вывода см. в справочнике по CLI. Сведения об интерактивной проверке CI на основе плагина см. в разделе Проверка изменений кода на наличие проблем безопасности.