Как читать авторский курс и нормативные материалы
Это учебные материалы, а не заключение о соответствии конкретного продукта. Организационные модели курса отделяйте от терминов стандарта: ППК в опубликованном проекте — машиночитаемый перечень, а живой реестр его версий является практикой сопровождения. Термин OSA в разных материалах имеет разный охват. Статус и обязательность нормативного документа проверяются отдельно; проект КАПО опубликован как проект первой редакции.
П16. GitLab CI security gate
Контекст практики Цель CI security gate — не «прогнать сканер», а остановить pipeline на заранее оговорённом пороге: критичность уязвимостей и запрещённые лицензии. Здесь вы соберёте gate из трёх шагов: генерация SBOM (Syft) → сканирование (Grype с
--fail-on) → отдельный fail по лицензиям. Ключевая идея — gate валит сборку кодом возврата задачи, а не текстом в логе, который никто не читает.
Цель
Получить .gitlab-ci.yml, в котором:
- стадия sca падает (job статус failed), если в зависимостях есть уязвимость уровня High или Critical с известным фиксом;
- стадия license падает, если встречена лицензия из стоп-листа (например, GPL-3.0-only);
- артефакты (SBOM, отчёт сканера) сохраняются и доступны на вкладке Job artifacts.
Проверяемый результат: один намеренно уязвимый коммит → pipeline красный; после фикса версии → зелёный.
Команда или действие
.gitlab-ci.yml (раннер с Docker executor):
stages:
- sca
variables:
SYFT_VERSION: "v1.18.1"
GRYPE_VERSION: "v0.85.0"
sca_scan:
stage: sca
image: alpine:3.20
before_script:
- apk add --no-cache curl
- curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin "${SYFT_VERSION}"
- curl -sSfL https://raw.githubusercontent.com/anchore/grype/main/install.sh | sh -s -- -b /usr/local/bin "${GRYPE_VERSION}"
script:
# 1. SBOM из исходников проекта
- syft dir:. -o cyclonedx-json=sbom.cdx.json
# 2. Gate по критичности: задача падает на High/Critical
- grype sbom:sbom.cdx.json --fail-on high --only-fixed -o table | tee grype-report.txt
artifacts:
when: always
paths:
- sbom.cdx.json
- grype-report.txt
expire_in: 1 week
Стоп-лист лицензий — отдельный шаг (CycloneDX кладёт лицензии в components[].licenses):
# license gate: падаем, если в SBOM есть запрещённая лицензия
FORBIDDEN='GPL-3.0-only|AGPL-3.0|GPL-2.0-only'
if jq -r '.components[].licenses[]?.license.id // .components[].licenses[]?.expression' sbom.cdx.json \
| grep -E "$FORBIDDEN"; then
echo "FORBIDDEN LICENSE FOUND"; exit 1
fi
Что вы должны увидеть
Лог grype при срабатывании gate (флаг --only-fixed оставляет только уязвимости с доступным исправлением):
NAME INSTALLED FIXED-IN TYPE VULNERABILITY SEVERITY
lodash 4.17.15 4.17.21 npm GHSA-p6mc-m468 High
minimist 1.2.0 1.2.6 npm GHSA-xvch-5gv4 Critical
1 error occurred:
* discovered vulnerabilities at or above the severity threshold
Статус задачи в GitLab — failed, exit code 1. На вкладке Job artifacts лежат sbom.cdx.json и grype-report.txt. После обновления lodash/minimist до фикс-версий повторный pipeline — зелёный, grype выводит No vulnerabilities found, exit code 0.
Сначала visibility, потом блокировка На первом проходе по репозиторию запустите gate в режиме
allow_failure: true(илиgrypeбез--fail-on), соберите статистику и согласуйте порог. Жёсткий--fail-on highвключают, когда команда уже разобрала текущий долг — иначе первый же pipeline встанет колом и gate отключат административно.
Если не получилось
- Pipeline зелёный, хотя уязвимости есть. Скорее всего,
grypeнашёл их, но gate не сработал: проверьте, что--fail-onдействительно стоит (low|medium|high|critical), а не забыт. Либо все находки — без фикса, и их отсёк--only-fixed; уберите флаг, чтобы увидеть полный список. syft: not found/grype: not found. Установочный скрипт не положил бинарь в PATH. На alpine нуженcurl(вbefore_script), а путь установки-b /usr/local/binдолжен быть в PATH раннера.- License gate всегда падает или всегда зелёный.
jqмолчит, если поля называются иначе: лицензия может лежать какlicense.id(SPDX-идентификатор), какlicense.name(текст) или какexpression(SPDX-выражение). Проверьте структуру:jq '.components[0].licenses' sbom.cdx.json. - Job завис на скачивании баз Grype. На офлайн-раннере нет доступа к фидам. Используйте
grype db updateзаранее и переменнуюGRYPE_DB_CACHE_DIRс примонтированным кэшем; см. П18. OSA Proxy режимы и ограничения про офлайн-контур.
Критерий зачёта
Показать преподавателю: (1) .gitlab-ci.yml с двумя gate-условиями (критичность + лицензии); (2) скриншот/лог красного pipeline на уязвимом коммите с видимым exit code 1 и строкой Grype; (3) скриншот зелёного pipeline после фикса; (4) сохранённые артефакты SBOM и отчёта. Устно — почему gate валит по коду возврата, а не по тексту лога, и зачем нужен этап allow_failure перед жёсткой блокировкой.
Нормативная связка
- М08. Защита цепочки поставки и OSA — родительский модуль.
- П06. Grype поверх готового SBOM · П34. SBOM quality gate · П18. OSA Proxy режимы и ограничения · П12. ORT и license policy
- Требования к CI security gate — поля регламента gate (область, ответственный, решение, evidence).
- NIST SP 800-218 SSDF — PW.4 (повторно используемые компоненты), RV.1 (выявление уязвимостей); ГОСТ Р 56939-2024 — управляемость работ и контроль сторонних компонентов.