Материал

Platform-native controls и отдельный decision layer: где заканчивается одно и начинается другое

Встроенных проверок платформы достаточно для стабильной разработки. Но когда AI-кодинг ускоряет темп изменений, проверки и решение о merge перестают быть одним и тем же

Введение: проблема, которую не видно на дашборде

Когда все лампочки зелёные, у команды возникает ощущение безопасности. CI прошёл. Ревью получено. Status checks — OK. Merge разрешён. Но вопрос "а это изменение действительно безопасно принять?" на зелёных лампочках не написан.

Это не теоретическая проблема. По данным отчёта Black Duck (540 специалистов по безопасности, 2025), 95% организаций уже используют AI-инструменты в разработке, но только 24% проводят комплексную проверку AI-генерированного кода по всем критериям: безопасность, качество, IP и лицензионные риски [4]. Остальные 76% проверяют что-то, но не всё.

Проблема не в отсутствии инструментов. Проблема в том, что набор сигналов ("все проверки прошли") и решение о принятии изменения — это разные вещи. Эту разницу и стоит разобрать.

Что такое platform-native controls и что они умеют

Изображение

GitHub: branch protection rules и rulesets

GitHub предоставляет два механизма: классические branch protection rules и более новые rulesets [5][6].

Branch protection rules позволяют:

  • требовать прохождения определённых status checks перед merge;
  • требовать ревью от заданного числа людей (включая code owners);
  • блокировать force push и удаление ветки;
  • требовать подписанных коммитов;
  • обязывать прохождения развёртывания в определённые среды.

Rulesets, появившиеся позже, дают ряд преимуществ [5]:

  • несколько rulesets могут применяться одновременно к одной ветке — правила агрегируются по принципу "наиболее строгое выигрывает";
  • статус enforcement можно переключать между evaluate и active — полезно при постепенном внедрении;
  • любой участник с read-доступом видит активные rulesets и понимает, почему PR заблокирован.

Важная деталь: по умолчанию ограничения branch protection rules не применяются к администраторам репозитория [7]. Это означает, что при определённой настройке именно те, у кого максимальные права, могут обойти проверки — и это не баг, а задокументированное поведение, которое часто становится неожиданностью для команд.

Организационный уровень (применение правил сразу ко всем репозиториям организации) доступен только на GitHub Enterprise — на более дешёвых планах каждый репозиторий настраивается отдельно [8]. Это создаёт операционную нагрузку и риск человеческой ошибки при масштабировании.

GitLab: merge request approval policies

GitLab предлагает более развитую модель безопасности как встроенную часть платформы, особенно на уровнях Premium и Ultimate [9].

Merge request approval policies (ранее — scan result policies, переименованы в GitLab 16.9) позволяют:

  • требовать одобрения при обнаружении уязвимостей определённой критичности сканерами (SAST, dependency scanning, container scanning и другими);
  • применять правила "четырёх глаз" для любых MR, независимо от результатов сканирования;
  • хранить политики в отдельном security policy project и распространять их на группы и подгруппы;
  • блокировать merge до завершения pipeline — изменение нельзя принять до того, как сканеры отработали [10].

Ограничения тоже есть: к каждой политике можно прикрепить не более пяти правил, к одному security policy project — не более пяти approval policies [9]. Для больших организаций с нестандартными требованиями это может оказаться недостаточно гибко.

Где platform-native controls хорошо справляются

Платформенные контроли эффективны в следующих задачах:

Защита от случайного merge без ревью. CODEOWNERS + required reviews на GitHub [11] или approval rules на GitLab [12] надёжно предотвращают ситуацию, когда критичный файл попадает в main без участия нужного человека. Это работает хорошо и стоит настроить в первую очередь.

Блокировка merge до завершения CI. Required status checks гарантируют, что тесты и сканеры отработали. Это базовая гигиена.

Политика-как-код с audit trail. GitLab хранит security policies в Git-репозитории — изменения политик сами проходят через MR-процесс, есть полная история изменений и accountability [9].

Progressive security gates по ветке. Разграничение требований для feature branches (быстро, без блокировки) и release branches (полное сканирование, hard gates) — задокументированная практика [13].

Базовый compliance. Для многих команд с невысоким профилем риска встроенных механизмов достаточно для выполнения требований внутреннего аудита.

Где platform-native controls упираются в ограничения

Статические правила, динамические изменения

Platform-native checks оперируют заранее определёнными условиями. Они отвечают на вопрос: "выполнено ли правило X?". Но они не знают контекст. PR, который касается нескольких несвязанных файлов — конфига nginx, миграции БД и бизнес-логики — проходит те же проверки, что и PR из одной строки в тесте. С точки зрения branch protection rules они неотличимы.

Проблема усиливается в AI-кодинге. Исследование Veracode по 100+ LLM показало, что 45% AI-генерированного кода содержит уязвимости [3]. Академическое исследование 576 000 кодовых образцов зафиксировало: почти 20% рекомендованных AI пакетов не существует ни в одном публичном реестре [14] — так называемые hallucinated dependencies, которые открывают дверь для атак типа slopsquatting. Статический набор правил про это ничего не знает.

Сигналы без единого enforcement point

На типичной команде работают: SAST, SCA, linter, тесты, code review, возможно IaC scanner. Каждый инструмент генерирует свой сигнал. В сумме это коллекция независимых результатов, а не единое решение [15]. Если три сканера нашли одну уязвимость, это три тикета — без единого места, где принимается решение "блокировать или нет".

Codacy в своём обзоре (2026) формулирует это так: даже когда сигналы агрегированы в branch protection rules, они "остаются набором сигналов, а не единым слоем принятия решения с общим контекстом" [15].

Административные обходы

По умолчанию администраторы GitHub-репозитория не обязаны следовать branch protection rules [7]. Даже с rulesets можно создать bypass list — и это часто делается из операционной необходимости (боты для релизов, автоматические апдейты зависимостей). Каждое такое исключение — потенциальная точка риска, которую нужно отдельно мониторить.

Контекст релиза

Platform-native checks работают на уровне конкретного PR. Но решение о релизе — это другой вопрос: все ли изменения в этом цикле безопасны в совокупности? Влияет ли новая зависимость на что-то уже развёрнутое? Есть ли в этом релизе регрессия по секретам? Встроенные механизмы платформы на эти вопросы не отвечают.

Что такое decision layer и зачем он нужен отдельно

Decision layer — это не замена SAST/SCA/CI, не конкурент platform-native controls и не ещё один сканер. Это слой, который:

  1. агрегирует сигналы от существующих инструментов;
  2. оценивает конкретное изменение (diff, зависимости, конфиги, служебные файлы) в его контексте;
  3. формулирует единственный ответ: можно ли безопасно принять это изменение прямо сейчас?

Принципиальное различие: platform-native checks отвечают на "выполнено ли правило?", decision layer — на "каков риск принятия этого изменения с учётом всего, что мы знаем?".

Policy-as-code как декларативный decision layer

Один из подходов — Open Policy Agent (OPA, CNCF graduated project). OPA полностью разделяет принятие решений и их исполнение: сервис запрашивает OPA с данными об изменении, OPA возвращает allow/deny с объяснением [16][17]. Политики написаны на Rego, хранятся в Git, тестируются через unit tests, изменяются через PR — это policy-as-code в чистом виде [16].

OPA хорошо подходит для инфраструктурного слоя (Kubernetes admission control, Terraform, CI/CD gates), но его применение к оценке семантики конкретного изменения кода требует значительной разработки и сопровождения кастомных политик.

Независимый verification layer для AI-кодинга

Более узкая, но всё более актуальная задача — verification именно для AI-генерированного кода. Codacy [15] описывает это как "independent quality gate": слой между генерацией и принятием изменения, который применяет детерминированные проверки (static analysis, security rules, test execution) и возвращает единое pass/fail решение.

Ключевое свойство — детерминизм: одни и те же данные должны давать одинаковое решение при одинаковых правилах. AI-системы (code review боты, LLM-помощники) могут давать контекст и объяснения, но не могут служить единственным enforcement layer для изменений, уходящих в production [15].

Практические сценарии: что что делает

Сценарий 1: конфиг с широкими правами попал в PR вместе с фичей

Platform-native checks: если в CODEOWNERS есть владелец конфигурационного файла, он получит нотификацию и должен одобрить. Если владельца нет или он занят — проверка проходит автоматически. Required status checks смотрят на CI-тесты и сканеры, но не на семантику того, что именно изменилось в конфиге.

Decision layer: оценивает конкретный diff и видит: изменён CORS-header с restrictive на wildcard, или добавлен токен с излишне широкими правами. Это сигнал для эскалации независимо от того, есть ли CODEOWNER и прошёл ли CI.

Сценарий 2: новая транзитивная зависимость с активной advisory

Platform-native checks: Dependabot и GitLab dependency scanning могут обнаружить известную CVE и создать блокирующий check. Это работает для прямых зависимостей с известными advisory.

Decision layer: оценивает, что именно попало в lock-файл, есть ли новые транзитивные зависимости, не был ли пакет добавлен AI как hallucinated package, каков контекст использования. Это более глубокий анализ, чем сопоставление с базой CVE.

Сценарий 3: AI-генерированный код в migration файле

Platform-native checks: если в CODEOWNERS не прописан владелец миграций, или владелец одобрил не читая — PR проходит. Status checks проверяют синтаксис и, возможно, прогоняют тесты.

Decision layer: специализируется на файлах с высоким риском (миграции, конфиги, CI/CD-файлы, internal tools) — именно то, что читают хуже всего при ревью под давлением дедлайна.

Модель принятия решений: как совместить оба слоя

Разумная архитектура не выбирает между platform-native controls и decision layer — она использует оба:

Первый слой — platform controls (базовая защита):

  • Required status checks (CI, SAST, SCA) на защищённых ветках.
  • CODEOWNERS для критичных директорий.
  • Approval policies с trigger по severity для security-critical findings (GitLab Ultimate или аналог).
  • Запрет force push и удаления целевых веток.

Второй слой — decision layer (контекстное решение):

  • Оценка конкретного diff с учётом контекста: что изменилось, как изменилось, в каком файле, в какой момент цикла.
  • Агрегация сигналов от нескольких инструментов в единый ответ.
  • Объяснение: почему это изменение требует внимания, что именно вызывает вопрос.
  • Приоритизация: что из обнаруженного действительно блокирует merge/release, а что — информационный шум.

Что не нужно дублировать: если SAST уже сканирует весь репозиторий и выдаёт результат в CI, decision layer не должен повторять тот же scan — он должен использовать его результат как один из входных сигналов.

Где граница: platform-native controls — это enforcement механизм ("merge физически невозможен без X"). Decision layer — это advisory и gate по смыслу ("вот что именно вызывает вопрос и почему это важно именно сейчас").

Частые ошибки при настройке контроля изменений

Ошибка 1: считать, что "CI зелёный" = "безопасно принять"

CI проверяет функциональность и, возможно, запускает сканеры. Но CI не знает, читал ли кто-то diff полностью, не оценивает контекст изменения и не понимает, что именно изменилось в конфиге за пределами синтаксических ошибок. Kiuwan описывает это прямо: "настройте сканер так, чтобы он падал только на новых уязвимостях в текущем PR, а не на всём унаследованном долге" [13] — хорошая практика, но она же означает, что "прошёл" относится к дельте, а не ко всему изменению целиком.

Ошибка 2: слишком агрессивные gates убивают доверие к инструменту

Если каждый medium-severity finding блокирует merge, команда начинает искать способы обойти проверки. Wiz формулирует это принципом progressive security: feature branches — быстро и не блокирующе, release branches — полное сканирование и hard gates [13]. Decision layer должен различать "предупреждение для команды" и "реальный стоп".

Ошибка 3: не документировать bypasses

Каждый bypass branch protection (будь то admin-флаг или bypass list) должен логироваться и регулярно ревьюиться. Это не просто best practice — без этого любой security incident становится расследованием в темноте.

Ошибка 4: не учитывать конфиги, IaC-файлы, CI/CD-манифесты

По опыту команд, работающих с AI-кодингом, именно вспомогательные файлы — .github/workflows/, Dockerfile, terraform/, db/migrations/ — читаются хуже всего при ревью под нагрузкой. Platform-native checks применяют к ним те же правила, что и к бизнес-логике. Decision layer должен давать этим файлам повышенный приоритет.

Ошибка 5: ожидать, что встроенные security policies GitLab полностью заменяют отдельный decision layer

GitLab merge request approval policies мощны и хорошо интегрированы. Но они работают на основе результатов scan jobs из pipeline — то есть их качество ограничено качеством настроенных сканеров. Они не оценивают семантику изменения за пределами того, что нашли сканеры.

Что произошло с ростом AI-кодинга: структура риска изменилась

В апреле 2025 года Satya Nadella на LlamaCon сообщил, что 20–30% кода в Microsoft пишется AI [1]. Sundar Pichai примерно тогда же назвал схожую цифру для Google [2]. Это не просто маркетинговые заявления — это изменение характера потока изменений.

Когда объём изменений растёт быстрее, чем количество людей, способных их проверить, традиционная модель ревью — "один разработчик читает diff другого" — начинает сбоить. AI-генерированный код в отличие от человеческого может быть синтаксически безупречным и при этом содержать паттерны, которые не бросаются в глаза при беглом чтении: избыточные права, слабая валидация, hardcoded секреты в нестандартном формате.

По данным Stack Overflow (2025), AI-generated pull requests ждут review pickup в 4,6 раза дольше, чем написанные человеком [3]. Это создаёт тихий риск: PR висит долго, потом его одобряют "потому что давно лежит", не потому что тщательно проверили.

Исследование по hallucinated dependencies добавляет специфический вектор: 43% несуществующих пакетов, которые предлагают LLM, появляются стабильно в разных промптах [14] — это означает, что атакующий может заранее зарегистрировать эти имена в публичном реестре. Dependabot не поймает пакет, у которого нет advisory — он просто существует и выглядит легитимно.

Практический чек-лист: до merge, до релиза

До merge (платформенный слой):

  • все required status checks зелёные (CI, SAST, SCA);
  • CODEOWNERS-ревью получено для затронутых директорий;
  • stale approvals сброшены после новых коммитов;
  • нет новых критических advisory для добавленных зависимостей.

До merge (decision layer):

  • diff просмотрен на предмет изменений в конфигах, CI/CD-манифестах, миграциях, lock-файлах;
  • новые зависимости — только те, что явно добавлены, без неожиданных транзитивных;
  • нет паттернов hardcoded секретов, избыточных прав, слабых CORS-настроек;
  • изменение понятно объяснено — особенно если автором является AI.

До релиза:

  • все изменения в цикле проверены в совокупности, не только последний PR;
  • нет изменений в служебных файлах, которые прошли без явного ревью;
  • понятно, что конкретно блокирует выпуск, а что является техническим долгом.

HighVibe как пример decision layer

Именно этот зазор — между набором сигналов от CI/CD и platform checks, и решением "безопасно ли принять это изменение" — закрывает HighVibe. Это не замена SAST, SCA или встроенных механизмов платформы, а дополнительный слой контроля до merge и релиза.

HighVibe анализирует конкретное изменение: код, конфиги, служебные файлы, зависимости и контекст релиза. Он помогает заметить риск до того, как изменение ушло в main, объясняет проблему на понятном языке и предлагает следующий шаг — исправить, перепроверить или остановить merge. Принципиально: HighVibe останавливает только действительно критичные изменения, а не генерирует длинный список для разбора.

Это полезно не потому, что platform-native controls плохи, а потому что они отвечают на другой вопрос. Два слоя закрывают разные задачи.

Заключение: не "что лучше", а "что для чего"

Правильный вопрос — не "platform-native controls или decision layer?". Правильный вопрос: "что именно мне нужно контролировать, и на каком уровне?".

Platform-native controls — это фундамент. Они обеспечивают enforcement, без них любой другой слой бессмысленен. Их нужно настроить корректно: branch protection rules или rulesets на GitHub, merge request approval policies на GitLab, progressive security gates по ветке.

Decision layer — это следующий шаг, необходимый тогда, когда объём изменений, сложность кодовой базы или темп AI-кодинга превышают то, что команда может надёжно ревьювить вручную. Он не дублирует платформу — он добавляет контекст и единую точку принятия решения.

Сигналы — это данные. Решение — это суждение. Когда суждений нужно делать всё больше, а времени всё меньше, наличие отдельного слоя, который формулирует "вот что конкретно важно в этом изменении прямо сейчас" — это не избыточность, а архитектурная необходимость.

Источники

[1] TechCrunch — "Microsoft CEO says up to 30% of the company's code was written by AI" — https://techcrunch.com/2025/04/29/microsoft-ceo-says-up-to-30-of-the-companys-code-was-written-by-ai/

[2] Entrepreneur — "AI Is Already Writing About 30% of Code at Microsoft and Google" — https://www.entrepreneur.com/business-news/ai-is-taking-over-coding-at-microsoft-google-and-meta/490896

[3] CodeAnt AI / codeant.ai — "Best Pull Request Automation Platforms 2026" — https://www.codeant.ai/blogs/top-pull-request-automation-tools

[4] Black Duck Blog — "AI Coding Security Gap: 76% Expose Software Supply Chain to Risk" — https://www.blackduck.com/blog/ai-coding-security-gap-software-supply-chain-risk.html

[5] GitHub Docs — "About rulesets" — https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/about-rulesets

[6] GitHub Docs — "Available rules for rulesets" — https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/available-rules-for-rulesets

[7] GitHub Docs — "About protected branches" — https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-protected-branches/about-protected-branches

[8] GitHub Community — "Branch Protection Rules at Organization level applying to all repos" — https://github.com/orgs/community/discussions/16007

[9] GitLab Docs — "Merge request approval policies" — https://docs.gitlab.com/user/application_security/policies/merge_request_approval_policies/

[10] GitLab Docs — "Merge request approval rules" — https://docs.gitlab.com/user/project/merge_requests/approvals/rules/

[11] GitHub Docs — "About code owners" — https://docs.github.com/articles/about-code-owners

[12] GitLab Docs — "Merge request approvals" — https://docs.gitlab.com/user/project/merge_requests/approvals/

[13] Wiz Academy — "CI/CD Security Scanning: Definition and Best Practices" — https://www.wiz.io/academy/application-security/ci-cd-security-scanning

[14] ActiveState — "Is AI-Generated Code Poisoning Your Software Supply Chain?" — https://www.activestate.com/blog/is-ai-generated-code-poisoning-your-software-supply-chain/

[15] Codacy Blog — "Why Coding Agents Need Independent Quality Gates to Work at Scale" — https://blog.codacy.com/why-coding-agents-need-independent-quality-gates

[16] GoCodeo — "Writing Rego Policies with OPA: Enforcing Governance and Compliance" — https://www.gocodeo.com/post/writing-rego-policies-with-opa-enforcing-governance-and-compliance

[17] Wiz Academy — "What is Open Policy Agent (OPA)?" — https://www.wiz.io/academy/application-security/open-policy-agent-opa

[18] DEV Community / mvtavares — "Why Every Pull Request Needs an Explainable Merge Decision" — https://dev.to/mvtavares/why-every-pull-request-needs-an-explainable-merge-decision-48g5

[19] NoOps School — "What is Merge gates? Meaning, Architecture, Examples, Use Cases" — https://noopsschool.com/blog/merge-gates/

[20] GitGuardian Blog — "Three Mechanisms to Protect Your Git Repositories" — https://blog.gitguardian.com/three-mechanisms-to-protect-your-git-repositories/

Нужен такой же контроль в ваших изменениях и релизах?

Покажем пример такого замечания на вашем сценарии и соберём пилотный контур без лишней суеты.

Запросить пилот Все статьи
Дальше по теме

Ещё материалы

Все статьи
24 июня 2026 18 мин

Политика использования ИИ в команде разработки: как не опоздать, когда всё уже идёт

Если разработчики уже пишут код с ИИ ассистентами, политика нужна сегодня — а не после первого инцидента TL;DR Более 84% разработчиков уже используют или планируют использовать ИИ инструменты 1 , и большинство делают эт…

Открыть материал
23 июня 2026 16 мин

Регистрация и онбординг пользователей: где появляются первые уязвимости

Форма регистрации выглядит просто. За ней скрывается один из наиболее атакуемых периметров приложения. TL;DR Форма регистрации и онбординг флоу — это первая поверхность атаки, которую видит злоумышленник. Большинство уя…

Открыть материал
23 июня 2026 15 мин

Бизнес-логика и мошенничество в продукте: что проверять до запуска

Ваш продукт работает правильно. Но это не значит, что он работает безопасно. TL;DR Уязвимости бизнес логики — это не сломанный код, а сломанные правила: приложение делает именно то, что написано, но не то, что задумывал…

Открыть материал