Статический анализ кода (SAST, Static Application Security Testing) в Deckhouse Code ищет уязвимости в исходном коде проекта. За ним стоит сканер Semgrep, а само сканирование называется sast.
Сканирование обязательное: его подмешивает в пайплайн проекта политика исполнения сканирования, которая лежит в отдельном проекте политик безопасности. Что сканируется и что приводит к ошибке пайплайна, решает политика — то есть команда безопасности. Файл .gitlab-ci.yml и настройки CI/CD проверяемого проекта на это решение не влияют.
Сканирование безопасности включается функциональным флагом уровня инстанса fe_security_scan_policies, который по умолчанию отключён. Пока он выключен, страницы политик и страницы настроек интеграций сканеров скрыты, а задачи сканирования в пайплайны не подмешиваются. Попросите администратора инстанса включить флаг.
Что делает сканирование
Сканирование sast добавляет в пайплайн задачи semgrep_sast_scan и semgrep_sast_junit, обе на стадии fe-security-scanner:
| Задача | Что делает |
|---|---|
semgrep_sast_scan | Запускает сканер по репозиторию и публикует его собственный JSON-вывод как артефакт. |
semgrep_sast_junit | Читает этот JSON, строит из него отчёт для сводки тестов и отчёт безопасности и решает исход: задача завершается успешно, если ни одна находка не достигла порога блокировки, и с ошибкой в противном случае. Выполняется в образе Ruby. |
Обе задачи выгружают артефакты с when: always, поэтому заблокированный пайплайн сохраняет находки, которые его заблокировали.
Находки попадают туда же, куда и находки остальных сканеров политики:
| Отчёт | Где смотреть |
|---|---|
| Тесты (JUnit) | Вкладка «Tests» пайплайна и сводка тестов в merge request |
| Отчёт безопасности (SAST) | Страница отчёта об уязвимостях |
| Находки, переданные в DefectDojo | DefectDojo, если эта интеграция настроена |
Предварительные требования
Чтобы сканирование могло запуститься, убедитесь, что:
- администратор инстанса включил функциональный флаг
fe_security_scan_policies; - проект политик безопасности привязан к проекту или к группе выше него;
- доступен GitLab Runner с executor
docker, и он может загрузить оба образа, которые использует сканирование: образ сканера (раздел «Откуда берётся образ сканера») и образ Ruby, в котором выполняется вторая задача, — по умолчаниюruby:3.3.10-slim, его можно перенаправить переменной инстансаFE_SCANS_REPORT_CONVERTER_IMAGE.
Включение сканирования
Добавьте действие sast в файл .gitlab/security-policies/policy.yml проекта политик безопасности:
scan_execution_policy:
- name: SAST everywhere
enabled: true
rules:
- type: pipeline
branches: ["*"]
actions:
- scan: sastЗатем привяжите проект политик к нужному проекту или группе в разделе «Настройки» → «Политика безопасности». После этого каждый пайплайн, попадающий под правила политики, получает две задачи, описанные выше.
Параметры сканирования можно задавать и в редакторе политик — он формирует форму, описанную ниже.
Что задаёт политика
Форма действия sast собрана из групп «Образ сканера», «Правила», «Исключаемые категории», «Блокировка», «Пути», «Уровни правил» и «Дополнительные параметры». Все параметры принадлежат политике: значения записываются в задачу сервером при формировании пайплайна, поэтому собственные переменные CI/CD проверяемого проекта их не меняют.
Каждая группа раскрывается и сворачивается по своему заголовку, и все они изначально свёрнуты. Свёрнутое состояние само по себе содержательно: свёрнутая группа означает, что политика в неё ничего не записала, поэтому эта часть сканирования остаётся с тем ответом, который сервер даёт без политики: для образа сканера — тот, который называет интеграция Semgrep, если она его называет, и поставочное значение во всём остальном. Раскройте группу и заполните поле — и политика забирает это решение себе для всех проектов, которые она покрывает. Сохраните политику и откройте её заново — группы, в которых что-то задано, откроются сами, поэтому сохранённая политика показывает всё, что задаёт.
Группа названа по тому выбору, вокруг которого собрана, и этот выбор нарисован без повторения собственного названия внутри группы: «Образ сканера» раскрывается прямо на источниках образа, «Правила» — на источниках правил, «Пути» — на источниках фильтров, «Блокировка» — на пороге, «Уровни правил» — на трёх уровнях. Поля, которые открывает выбранный вариант, сохраняют свои названия под ним, а подсказка ведущего выбора («?») стоит рядом с заголовком группы.
То, что решила свёрнутая группа, написано в конце строки её заголовка. Именно это делает свёрнутую форму читаемой: порог и источник правил видно, ничего не раскрывая.
| Группа | Что написано в её свёрнутой строке |
|---|---|
| «Образ сканера» | Какой из трёх источников даёт образ — «Образ из интеграции», если интеграция называет образ, и «Образ из поставки продукта» во всех остальных случаях |
| «Правила» | Откуда берутся правила — «Набор из поставки продукта», пока политика не выберет другой источник |
| «Исключаемые категории» | Ничего. В группе стоят флажки, а строка подводит выбор из списка |
| «Блокировка» | Порог — «Высокий и выше», пока политика не выберет другой |
| «Пути» | Откуда берутся фильтры путей — «Без фильтров», пока политика не выберет другое |
| «Уровни правил» | Уровни, включённые политикой, например «Высокий, Средний». Пока политика не задала ни одного, строка пуста |
| «Дополнительные параметры» | Ничего. В свободном тексте выбора из списка нет, поэтому подводить нечего |
Строки «Образ сканера», «Правила», «Блокировка» и «Пути» всегда содержат значение: их элемент управления — набор переключателей, а тот всегда показывает ответ, заданный политикой либо тот, который дал бы сервер, пока политика молчит. Строка и элемент управления поэтому согласованы. «Уровни правил» — набор из нескольких значений, и пока политика ничего не задала, называть нечего: вместо этого все три флажка стоят установленными, а это то же самое состояние.
Ни у одной здешней группы нет флажка рядом с заголовком. Там, где флажок есть у группы другого сканера, эта группа — модуль, который можно выключить; здешние группы — само сканирование. Выключает его удаление действия sast из политики. Флажки внутри групп «Исключаемые категории» и «Пути» несут каждый своё отдельное значение.
Поле, которое отвечает одному варианту выбора, показывается под этим вариантом и больше нигде. Выбранный источник правил «Файл в проекте политик безопасности» помещает путь к файлу правил прямо под этим вариантом; выбор другого источника убирает поле с экрана.

Образ сканера
Группа задаёт, в каком образе выполняется сканирование. Она раскрывается на поле «Источник образа» — выборе из трёх вариантов:

| Источник | Какой образ выполняет сканирование |
|---|---|
| «Образ из поставки продукта» | Образ, который фиксирует этот релиз, либо тот, что администратор задал для всей установки переменной инстанса FE_SCANS_SEMGREP_IMAGE. Образ несёт свою версию, поэтому поля версии у этого источника нет. |
| «Образ из интеграции» | Реестр, в который интеграция Semgrep зеркалирует сканер, либо единственный подготовленный образ, который она называет (раздел «Интеграция Semgrep»). |
| «Образ анализатора от GitLab» | registry.gitlab.com/security-products/semgrep на теге, который называет политика. Нужна установка, у которой есть доступ к этому реестру. |
| Поле | Что задаёт |
|---|---|
| «Версия образа» | Тег, по которому загружается образ анализатора, — так, как его указывает реестр: три числа, например 6.25.0, либо дайджест. Показывается только под вариантом «Образ анализатора от GitLab», потому что два остальных источника несут свою версию. Если поле пустое, используется тег из поставки этого релиза. |
Тег образа и версия semgrep — разные нумерации, и больший тег образа означал более старый semgrep. Подсказка поля «Версия образа» называет версию semgrep из поставки продукта и тег образа, который её несёт, а список подсказок в поле называет то же самое для каждого тега, известного этому релизу. Подсказка рядом с заголовком группы сообщает, какой образ выполнит эта установка: подготовленный образ, названный интеграцией, реестр, в который она зеркалирует сканер, либо образ, заданный для самой установки.
Рядом с вариантом «Образ из интеграции» стоит ссылка на страницу интеграции Semgrep — в любом состоянии этого варианта и только для политики, которой владеет группа. Политику, которой владеет проект, настраивает группа выше него, а доступа к её настройкам у мейнтейнера проекта может не быть, поэтому там у этого варианта ссылки нет.
«Образ из интеграции» — единственный источник, который может быть недоступен, и причина у этого одна: интеграция не называет образ, который сканированию забирать. Так выходит, если для группы не настроена интеграция Semgrep либо если она настроена, но не называет ни реестр, ни подготовленный образ. Вариант при этом остаётся в списке, но серым, и причина написана на самом варианте. Два остальных источника доступны всегда.
Политика, в которой источник не указан, показывает тот ответ, который сервер дал бы без неё: «Образ из интеграции», если интеграция называет образ, и «Образ из поставки продукта» во всех остальных случаях (раздел «Откуда берётся образ сканера»).
Правила
Группа задаёт, какие правила выполняет сканирование.

| Поле | Что задаёт |
|---|---|
| «Набор правил» | Откуда берутся правила. Источники перечислены ниже. По умолчанию — «Набор из поставки продукта». |
| «Путь к набору правил в образе» | Какой из наборов, лежащих в образе сканера, выполнять (раздел «Наборы правил в образе»). По умолчанию — /rules/lgpl. Если по этому пути набора нет, сканирование останавливается. |
| «Правила» | Сами правила, в YAML сканера. Показывается, когда источник — «Правила, заданные в политике». |
| «Путь к файлу правил» | Путь к файлу правил внутри проекта, из которого они читаются. По умолчанию — .semgrep.yml. |
| «Заменить поставленный набор» | По умолчанию выключено: ваши правила выполняются вместе с поставленным набором. Если установить флажок, они выполняются вместо него, и всё, что покрывал поставленный набор, перестаёт проверяться. |
У каждого поля есть подсказка за знаком «?» рядом с названием; подсказка поля «Набор правил», по которому названа группа, стоит рядом с её заголовком.
Источники правил отличаются тем, кто владеет файлом:
| Источник | Где лежат правила | Кто ими распоряжается |
|---|---|---|
| «Набор из поставки продукта» | В образе сканера, по пути, указанному выше | Поставка продукта |
| «Файл в проекте политик безопасности» | Проект, где лежит политика, на его ветке по умолчанию | Команда безопасности |
| «Файл в проверяемом проекте» | Сканируемый репозиторий, на строящемся коммите | Проверяемый проект |
| «Правила, заданные в политике» | Сама политика | Автор политики |
Источники «Набор из поставки продукта», «Файл в проекте политик безопасности» и «Правила, заданные в политике» читает сервер и записывает в задачу. «Файл в проверяемом проекте» читает сама задача, из своей рабочей копии, на строящемся коммите. Это же единственный источник, который пишет проверяемая сторона: коммит, переписывающий этот файл, переписывает правила сканирования, которое проверяет этот же проект. Снятый флажок «Заменить поставленный набор» сохраняет базовую линию даже тогда, когда файл в проекте опустошён.
Файл правил, названный политикой, но не доставленный сканированию, останавливает задачу: она печатает причину и завершается с ошибкой, а поставленный набор пропавший файл не подменяет.
Исключаемые категории
Группа задаёт, какие категории поставленного набора сканирование не выполняет.
| Поле | Что задаёт |
|---|---|
| «Исключить правила для секретов» | По умолчанию выключено. Если установить флажок, правила, которые ищут учётные данные, попавшие в репозиторий, в прогон не идут. |
| «Исключить правила для конфигурации» | По умолчанию выключено. Если установить флажок, правила, которые читают конфигурацию и инфраструктурный код — Terraform, Dockerfile, манифесты Kubernetes, конфигурацию CI, — в прогон не идут. |
| «Исключить правила для вредоносного кода» | По умолчанию выключено. Если установить флажок, правила, которые ищут признаки намеренно скрытого кода, в прогон не идут. |
Флажки показываются, пока правила берутся из поставленного набора: у своих правил категорий нет. Установленный флажок исключает категорию, снятый оставляет её в прогоне — и так же продолжает вести себя политика, написанная до появления этих полей. Подсказка группы говорит, зачем этот выбор нужен: если одну из этих категорий уже покрывает другое обязательное сканирование, о ней сообщат оба, и одна и та же строка станет находкой дважды.
Что лежит в каждой категории и какой набор правил нужен для исключения — в разделе «Категории внутри поставленного набора».
Блокировка
Группа задаёт, что находка делает с пайплайном.
| Поле | Что задаёт |
|---|---|
| «Порог блокировки» | Что приводит к ошибке пайплайна. Находки ниже порога всё равно попадают в отчёт и в отчёт об уязвимостях: порог решает только исход пайплайна. По умолчанию — «Высокий и выше». |
Значения порога:
| Значение | Что приводит к ошибке пайплайна |
|---|---|
| «Высокий и выше» (по умолчанию) | Находка высокого уровня серьёзности. Средний и информационный уровни только попадают в отчёт. |
| «Средний и выше» | Средний и высокий уровни серьёзности. Информационный только попадает в отчёт. |
| «Любая находка» | Любая находка, какого бы уровня серьёзности она ни была. |
| «Только сообщать, ничего не блокировать» | Ничто. Находки всё равно попадают в отчёт, в отчёт об уязвимостях и в DefectDojo. |
Semgrep сообщает об уровнях ERROR, WARNING и INFO, которые сканирование показывает как высокий, средний и информационный. Критического и низкого у него нет, поэтому порога с таким именем не достигала бы ни одна находка: «критический» блокировал бы ничто, выглядя при этом строгим, а «низкий» повторял бы «средний». Значение «Только сообщать, ничего не блокировать» вносит отказ от блокировки в политику отдельным значением.
Пути
Группа задаёт, что сканирование осматривает и что оставляет за рамками.
| Поле | Что задаёт |
|---|---|
| «Фильтры путей» | Откуда берутся списки путей, которые не нужно осматривать. По умолчанию — «Без фильтров». |
| «Путь к файлу фильтров» | Путь к файлу фильтров внутри проекта, из которого они читаются. По умолчанию — .semgrepignore. |
| «Исключить пути» | По одному пути или шаблону в строке: сторонний код, фикстуры, сгенерированные файлы. |
| «Только эти пути» | По одному пути или шаблону в строке. Всё остальное в сканирование не попадает. |
| «Учитывать .gitignore репозитория» | По умолчанию выключено. |
При любом источнике фильтров задача добавляет к тому, что задала политика, свои встроенные исключения — node_modules/, vendor/, dist/, build/, .venv/ и .git/, — поэтому деревья зависимостей остаются вне сканирования и тогда, когда фильтры политики о них молчат.
У фильтров тот же выбор источника, что и у правил:
| Источник | Где лежит список | Кто им распоряжается |
|---|---|---|
| «Без фильтров» | — | — |
| «Файл в проекте политик безопасности» | Рядом с политикой, применяется ко всем проектам, которые она покрывает | Команда безопасности |
| «Файл в проверяемом проекте» | Сканируемый репозиторий | Проверяемый проект |
| «Списки, заданные в политике» | Два списка в форме | Автор политики |
По умолчанию задача убирает любой .semgrepignore, найденный в сканируемом репозитории, — включая вложенные в подкаталогах, — перед началом сканирования. Выбор «Файл в проверяемом проекте» это отключает:
«Файл в проверяемом проекте» и «Учитывать .gitignore репозитория» одинаково отдают проверяемому проекту право решать, что осматривает обязательное сканирование. После этого коммит в проверяемом проекте может сузить сканирование, которое его же и проверяет, и в политике это сужение не видно. Команда безопасности вполне может решить, что каждый проект лучше знает свои каталоги стороннего кода; тогда делегирование фиксируется в политике, потому что оба варианта остаются выключенными, пока эту группу не раскроют и один из них не выберут.
Ещё про эти списки:
- «Только эти пути» сильнее, чем «Исключить пути». Исключение убирает то, что названо; включение убирает всё остальное. Один шаблон
src/**незаметно исключает из сканирования иlib, иconfig, и миграции. - Применяются они в этом же порядке — сначала включения, потом исключения, — поэтому исключение действует и внутри того, что пропустило включение.
Шаблон, не совпавший ни с чем, проходит проверку формы. Ловит его задача: она печатает, сколько файлов сканер прочитал, и завершается с ошибкой, когда это число равно нулю.
Уровни правил
Группа задаёт, правила каких уровней вообще выполняются.
| Поле | Что задаёт |
|---|---|
| «Уровни правил» | «Высокий» (ERROR), «Средний» (WARNING), «Информационный» (INFO). Все три флажка изначально установлены — именно это сканирование и выполняет, пока политика не задала своих уровней. |
Уровень — это ровно те правила, которые сканер помечает им: «Высокий» — правила ERROR, «Средний» — WARNING, «Информационный» — INFO; находка попадает в отчёт с уровнем сработавшего правила. Снятый флажок убирает из прогона ровно правила этого уровня.
Последний оставшийся установленный флажок снять нельзя: опустевший список удаляется из политики, а политика, которая не называет уровней, — это то состояние, в котором выполняются все уровни.
«Уровни правил» и «Порог блокировки» выглядят одинаково, а делают разное:
| Поле | На что влияет | Находка ниже уровня |
|---|---|---|
| «Уровни правил» | Какие правила выполняются | Её не существует: правило не выполнялось |
| «Порог блокировки» | Какие находки приводят к ошибке пайплайна | Она есть в отчёте, но не блокирует |
Порог покрывает свой уровень и все уровни выше — это и означает «и выше»; уровень правил покрывает правила, помеченные сканером этим уровнем, и никакие другие.
Поэтому исключённый уровень убирает свои находки и из отчёта: отчёт об уязвимостях и DefectDojo становятся меньше, и в логе задачи об этом ничего не сказано. Порог, которого не достигает ни один установленный уровень, не сработает никогда; форма говорит об этом, когда так получилось.
Дополнительные параметры
Группа задаёт флаги, которых в остальной форме нет.
| Поле | Что задаёт |
|---|---|
| «Дополнительные параметры» | Флаги, передаваемые сканированию как есть. |
«Дополнительные параметры» настраивают ресурсы запуска: таймауты, лимиты памяти, максимальный размер файла. Флаги, перенаправляющие или подавляющие отчёт, отклоняются, как и флаги, которыми форма распоряжается сама: форматы вывода и отчётов (--json, --sarif, --junit-xml, --gitlab-sast, --gitlab-secrets, --output, --text и парные к ним *-output), а также --config, --metrics и --baseline-commit.
Подсказка этого поля сообщает и то, куда попадают находки сканирования: они публикуются как отчёт безопасности, а значит, доходят до отчёта об уязвимостях и до всего, что администратор к нему подключил.
Наборы правил в образе
По умолчанию сканирование выполняет набор правил, лежащий внутри образа сканера, по пути /rules/lgpl. В образе лежит несколько наборов, и поле «Путь к набору правил в образе» выбирает между ними:
| Путь в образе | Правил | Правил по языкам |
|---|---|---|
/rules/lgpl (по умолчанию) | 152 | javascript 83, kotlin 58, swift 5, java 4, typescript 4, generic 2 |
/rules/lgpl-cc | 97 | ruby 40, java 39, php 9, python 6, javascript 1, typescript 1, generic 1, yaml 1 |
/rules/gitlab | 5 | java 2, generic 1, javascript 1, kotlin 1 |
/rules | 592 | наборы выше плюс файлы правил, лежащие рядом с ними: scala 86, python 79, c 62, cpp 62, go 27, csharp 22 и другие |
Правило может называть несколько языков, поэтому суммы по языкам больше числа правил. Строка /rules — это каталог целиком: если направить сканирование на него, загрузятся и все наборы внутри, и файлы рядом с ними.
Значения измерены в образе registry.gitlab.com/security-products/semgrep:6.25.0 и относятся к нему; в более новом образе состав может быть другим. У каждого каталога в образе свой файл лицензии, а выполняемый набор называют в поле «Путь к набору правил в образе».
Набор по умолчанию покрывает javascript, kotlin, swift, java, typescript и generic. Python, Go, Ruby, PHP, C, C++, C# и Scala остаются за его пределами. Репозиторий на одном из этих языков, просканированный по пути по умолчанию, завершится успешно и без находок: ни одно правило к нему не подошло. Покрытия SAST у такого репозитория нет, и зелёный пайплайн здесь означает только то, что сканеру нечего было применить.
Укажите в поле «Путь к набору правил в образе» набор, покрывающий его язык, добавьте собственные правила через поле «Набор правил» или попросите администратора указать в интеграции Semgrep образ с подходящим набором и выберите в политике источник «Образ из интеграции». Тот, кто приносит свой набор, отвечает за его состав и за условия, на которых тот распространяется.
Собственные правила задаются полем «Набор правил» и, если флажок «Заменить поставленный набор» остался снятым, выполняются вместе с тем набором, который даёт образ.
Категории внутри поставленного набора
Правила в наборе размечены по категориям: категория говорит о том, о чём судит правило. Измерено на наборе из 2826 правил:
| Категория | Правил | О чём судят её правила |
|---|---|---|
| Код | 1988 | Код самой программы |
| Конфигурация | 522 | Конфигурация и инфраструктурный код: Terraform, Dockerfile, манифесты Kubernetes, конфигурация CI |
| Секреты | 225 | Учётные данные, попавшие в репозиторий |
| Вредоносный код | 91 | Признаки намеренно скрытого кода: обфускация, код, собираемый во время выполнения, вызовы через промежуточные слои |
В более новом образе состав может быть другим. Конфигурацию, секреты и вредоносный код политика может исключить — в группе «Исключаемые категории»; правила о коде выполняются в каждом сканировании.
Для исключения нужен набор правил, который несёт индекс своих категорий. У набора из образа, публикуемого GitLab, такого индекса нет, поэтому установленный флажок останавливает задачу: она называет категории, которые её просили исключить, и набор правил, у которого нет индекса для этого; это сообщение разобрано в разделе «Диагностика». У правил, заданных в политике, категорий тоже нет, поэтому при таком источнике флажки скрыты.
Правила для секретов и сканирование secret_detection смотрят на одно и то же, и тогда одна и та же строка приезжает двумя находками на двух уровнях. Измерено на одном прогоне: semgrep положил попавший в репозиторий токен в SAST-отчёт с уровнем Info, а secret_detection — тот же токен в свой отчёт с уровнем Critical. При этом наборы находок не вложены друг в друга: ключ AWS нашёл только semgrep, а URL вебхука Slack — только secret_detection, поэтому исключение правил для секретов передаёт категорию целиком secret_detection и вместе с ней убирает из SAST-отчёта те находки, которые были только там.
То же рассуждение годится для правил конфигурации, если инфраструктуру уже проверяет отдельный сканер, и для правил вредоносного кода: они читают намерение, поэтому репозиторий, который обфусцирует или собирает код во время выполнения по своим причинам, увидит их срабатывания.
Откуда берётся образ сканера
Образ, в котором выполняется сканирование, разрешается сервером один раз, до старта задачи, и записывается в неё готовым значением. Переменной CI/CD он не становится, поэтому настройки проверяемого проекта не могут направить сканирование на другой сканер.
Какой это образ, следует из источника, названного политикой в группе «Образ сканера»:
| Источник в политике | Что загружает сканирование |
|---|---|
| «Образ из поставки продукта» | Образ, заданный администратором для всей установки переменной окружения инстанса FE_SCANS_SEMGREP_IMAGE, либо образ, зафиксированный этим релизом, если переменная не задана. |
| «Образ из интеграции» | Подготовленный образ, названный интеграцией Semgrep, — ровно так, как он указан; если интеграция называет реестр, то сканер из этого реестра, в версии, которую несёт политика, либо в той, которая задана для этой установки. |
| «Образ анализатора от GitLab» | registry.gitlab.com/security-products/semgrep в версии из поля «Версия образа», а пока это поле пустое — в версии из поставки этого релиза. |
Подготовленный образ, названный в интеграции, отвечает за один источник и ни за какой другой: администратор, который его указал, задал то, что загружает вариант «Образ из интеграции», вместе с версией, поэтому версия из политики к нему не применяется. Политика, которая запрашивает образ из поставки продукта или образ анализатора от GitLab, получает запрошенный образ.
Политика, в которой источник не указан вовсе, написана до появления этого поля и сохраняет прежнее поведение: образ, названный интеграцией, затем образ, заданный для инстанса, затем образ из поставки релиза. Версия, которую несёт такая политика, по-прежнему применяется — кроме случая, когда интеграция называет подготовленный образ.
Запись интеграции самого проверяемого проекта в расчёт не идёт: образ приходит со стороны, которая обязывает к сканированию.
Интеграция Semgrep
Интеграция хранит то, откуда читается образ сканера. Настраивается она на группе, поэтому установка называет реестр один раз для всех политик под этой группой. В проекте интеграция видна без полей — так читатель узнаёт, что сканирование настраивается выше него.
Откройте на группе «Настройки» → «Интеграции» → «Semgrep» и заполните любое из полей — оба необязательны:
| Поле | Что задаёт |
|---|---|
| «Реестр» | Реестр, куда скопирован образ сканера, без тега. Например, registry.example.com или registry.example.com/mirror. Сканирование, политика которого берёт образ из интеграции, загружает его отсюда — в версии, которую несёт политика, либо в той, которая задана для этой установки. |
| «Подготовленный образ» | Один образ, указанный полностью и с тегом или дайджестом, — для установки, которая собирает его сама. Например, registry.example.com/ci-images/semgrep:6.25.0. Сканирование, политика которого берёт образ из интеграции, выполняется в нём ровно так, как он написан, поэтому версия из политики не применяется. Имеет приоритет над полем «Реестр». |
Если оба поля пусты, интеграция не называет образ: вариант «Образ из интеграции» в политике выбрать нельзя, и сканирование выполняется в образе из поставки продукта. То, что сканирование ищет, задаётся в политике.

Версия из поставки продукта
Этот релиз поставляет registry.gitlab.com/security-products/semgrep:6.25.0, зафиксированный на этой версии. Один тег фиксирует сразу обе половины сканера — движок и наборы правил, вложенные в образ, — потому что обе лежат в одном образе.
Поле «Версия образа» в политике принимает обе формы фиксации версии:
- номер версии, например
6.25.0, — его читает человек и с ним можно сравнивать; - дайджест, например
sha256:aafbcaff…, — он называет одну сборку, и подменить её нельзя.
Плавающие теги (latest, stable, тег из одного мажорного номера — например, 6) и ссылки с адресом реестра отклоняются: реестр называет интеграция, а политика называет только версию.
Версия, поставляемая с релизом, пересматривается при обновлении Deckhouse Code.
Закрытый контур
Установка без доступа в интернет обеспечивает оба образа, которые использует сканирование:
| Образ | По умолчанию | Чем перенаправляется |
|---|---|---|
| Сканер | registry.gitlab.com/security-products/semgrep:6.25.0 | Переменная инстанса FE_SCANS_SEMGREP_IMAGE — она перенаправляет вариант «Образ из поставки продукта»; либо поле «Реестр» или «Подготовленный образ» интеграции Semgrep — для политики, которая берёт образ из интеграции |
| Сборщик отчётов | ruby:3.3.10-slim, с Docker Hub | Переменная инстанса FE_SCANS_REPORT_CONVERTER_IMAGE |
Скопируйте оба образа в свой реестр — так, как предписывает офлайн-инструкция GitLab для его аналитических образов, — а затем укажите этот реестр в соответствующей настройке. Deckhouse Code называет оба образа и загружает их извне.
Образ сканера остаётся вне досягаемости dependency proxy. Прокси кеширует образы, лежащие на Docker Hub, а образ сканера публикуется в registry.gitlab.com, поэтому из двух образов прокси кеширует образ Ruby. Установка, которая хочет перестать загружать образ сканера извне при каждом запуске — в закрытом контуре или нет, — копирует образ в свой реестр и указывает эту копию в переменной FE_SCANS_SEMGREP_IMAGE или в поле «Реестр».
Платные возможности Semgrep
Всё описанное на этой странице работает на открытой версии сканера. Возможности Semgrep, остающиеся за её пределами:
| Возможность | В открытой версии | Чем закрывается в Deckhouse Code |
|---|---|---|
| Анализ потока данных между файлами | Нет, только внутри одного файла | Ничем; ограничение принимается |
| Правила Pro | Нет | Собственными правилами, через поле «Набор правил» |
| Анализ зависимостей (Supply Chain) | Нет | Интеграцией CodeScoring или сканированием dependency_scanning |
| Проверка валидности найденных секретов | Нет | Ничем |
Платные возможности работают через облако вендора. Их включение означает, что сканирование выгружает находки — и контекст кода вокруг них — на серверы Semgrep, за пределы вашей установки. В закрытом контуре до облака вендора нет сети, поэтому платные возможности там недоступны.
Обязательное сканирование оставляет всё внутри задачи. Оно выполняет semgrep scan с флагами --metrics=off и --disable-version-check, поэтому находки и телеметрия использования остаются там, куда их положила задача. Прежде чем сканер вообще будет найден, задача очищает все унаследованные переменные SEMGREP_* и PYTHON*: SEMGREP_RULES и SEMGREP_BASELINE_COMMIT среди них документированы как эквиваленты --config и --baseline-commit, и оставленные на месте они позволили бы настройкам CI/CD проверяемого проекта подменить набор правил или базу сравнения того сканирования, которое его проверяет.
Диагностика
Сканирование не появляется в пайплайне
Проверьте, что:
- функциональный флаг
fe_security_scan_policiesвключён на инстансе; - проект политик безопасности привязан к проекту, а
policy.ymlсодержит действие- scan: sast; - правила политики совпадают с пайплайном (ветка, тип пайплайна);
- доступен GitLab Runner с executor
docker.
Задача завершается с ошибкой «no rule set at … in this image»
Пути, указанного в поле «Путь к набору правил в образе», в разрешённом образе нет. Сверьте путь с таблицей выше и проверьте, какой образ используется на самом деле: если выбран источник «Образ из интеграции», у «Подготовленного образа», заданного на интеграции, раскладка может быть другой.
Задача завершается с ошибкой «carries no class index to switch them off by»
В группе «Исключаемые категории» установлен флажок, а разрешённый набор правил не несёт индекса своих категорий — у набора из образа, публикуемого GitLab, его нет. Снимите флажки или направьте сканирование на набор правил с индексом. В логе задачи напечатаны категории, которые её просили исключить, и прочитанный набор правил.
Соседнее сообщение, о том что индекс не содержит ни одного правила ни в одной из названных категорий, лечится так же.
Задача завершается с ошибкой «semgrep read no files at all»
Сканирование не осмотрело ничего и поэтому отказывается отчитываться об успехе. Обычные причины — шаблон в поле «Только эти пути», не совпавший ни с чем; фильтры, убравшие весь репозиторий; либо пустая рабочая копия. В логе задачи напечатано, сколько файлов она обработала и сколько из них убрали фильтры.
Сканирование завершается успешно, но ничего не находит
Чаще всего набор правил не покрывает язык репозитория, об этом предупреждает раздел «Наборы правил в образе». Посмотрите лог задачи: в нём напечатан используемый путь к набору правил и число загруженных правил. Тот же результат по другой причине даёт сужение поля «Уровни правил»: уровень, у которого политика сняла флажок, не выполняется, поэтому его находок в отчёте нет.