Политика выполнения пайплайна (PEP) добавляет задачи из CI/CD-файла другого проекта в каждый пайплайн покрытых ею проектов. Политика хранится в проекте политик безопасности — том же виде проекта, где хранятся и политики выполнения сканирования, — и покрытый проект не может убрать или изменить задачи, которые добавляет политика, ни из своего .gitlab-ci.yml, ни из настроек CI/CD.

Политика выполнения сканирования или политика выполнения пайплайна?

Политика выполнения сканированияПолитика выполнения пайплайна
Что выполняетОдин из встроенных сканеров (SAST, Trivy, поиск секретов, PT AI, CodeScoring), каждый со своими настройкамиЛюбую задачу, написанную обычным синтаксисом GitLab CI в выбранном вами файле
Кто определяет задачиСобственные шаблоны сканеров продукта; политика лишь заполняет их настройкиВы — content.include политики указывает на CI/CD-файл, который вы сами ведёте
Типичное применениеОбязать каждый покрытый проект использовать штатные сканерыДобавить задачи комплаенса, аудита или уведомлений, которые проект не может пропустить, либо полностью заменить конфигурацию пайплайна проекта

Предварительные условия

Прежде чем создавать политику выполнения пайплайна, убедитесь, что:

  • администратор включил для инстанса флаги функций fe_security_scan_policies и fe_pipeline_execution_policies так, как описано на странице Ранний доступ;
  • у инстанса есть лицензия Enterprise Edition;
  • к проекту или к группе выше него привязан проект политик безопасности. Если проект не привязан, он создаётся и привязывается при сохранении первой политики, поэтому этот шаг можно пропустить (см. «Где хранятся политики»);
  • у вас есть роль Maintainer или выше в проекте либо роль Owner в группе. Эта роль нужна, чтобы создавать, изменять и тестово запускать политики, а также чтобы привязать или изменить проект политик безопасности. Для группы откройте «Настройки» → «Политика безопасности». У проекта такого раздела нет: перейдите в «Безопасность» → «Политики» и нажмите «Редактировать проект политик».

Включение функциональности

Оба флага по умолчанию выключены. Администратор включает их для инстанса так, как описано на странице Ранний доступ.

Пока хотя бы один флаг выключен или у инстанса нет лицензии Enterprise Edition, карточки «Политика выполнения пайплайна» и «Политика выполнения пайплайна по расписанию» отсутствуют на экране выбора типа политики, список политик не показывает ни одной политики выполнения пайплайна, ни один пайплайн не получает задач политики, политики по расписанию не запускаются, а форма «Запустить новый пайплайн» не заполняется переменными политик. Настройки политик в настройках проекта и в области администратора тоже скрыты. Политика pipeline_execution_policy или pipeline_execution_schedule_policy, уже записанная в документ, остаётся валидной и просто игнорируется, пока оба флага не включат.

Где хранятся политики

Политика выполнения пайплайна, как и политика выполнения сканирования, хранится в файле .deckhouse_code/security-policies/policy.yml проекта политик безопасности, в списке pipeline_execution_policy (или pipeline_execution_schedule_policy для политики по расписанию, см. ниже).

Чтобы открыть редактор политики, перейдите в «Безопасность» → «Политики» проекта или группы и выберите «Новая политика», затем карточку «Политика выполнения пайплайна» — либо карточку «Политика выполнения пайплайна по расписанию», чтобы вместо этого создать политику, которая запускается по собственному расписанию (см. «Политики по расписанию» ниже). Обе предлагают форму («Режим правил») и представление YAML («Режим .yaml»), между которыми можно переключаться. Когда вы заполните проект, путь к файлу и ref включаемого CI/CD-файла, редактор проверит, существуют ли этот проект, ref и файл, используя ваши собственные права на чтение, и подсветит поле, если проверка не прошла, — сохранению политики это не мешает, кроме случая, когда пустым остаётся проект или файл.

Чтобы сохранить политику, нажмите «Настройка с запросом на слияние». Сохранение политики, как и её удаление, открывает merge request в проекте политик безопасности. Политика начинает действовать только после слияния этого merge request в основную ветку проекта политик безопасности. Если проект политик безопасности ещё не привязан, при сохранении он сначала создаётся и привязывается.

Список «Политики» показывает политики выполнения пайплайна вместе с политиками выполнения сканирования; в каждой строке указан её тип, а для политики по расписанию — ещё и ближайший запланированный запуск (см. «Политики по расписанию» ниже).

Политика добавляет задачи только в пайплайны с источником CI: отправка изменений, веб-интерфейс, расписание, API, триггер, команда чата, внешний сервис, пайплайн другого проекта, событие merge request и событие внешнего pull request. Дочерние и внутренние пайплайны (Web IDE, DAST по запросу, пайплайны политик по расписанию и другие пайплайны, которые продукт создаёт сам) не получают задач политики, как и проверка в CI Lint. Запуск по расписанию политики выполнения сканирования запускает только её сканеры и тоже не получает задач политики.

Проект политик безопасности не покрывается политиками, которые хранит сам. Политики, хранящиеся в других проектах политик безопасности, покрывают его как обычно.

Синтаксис

pipeline_execution_policy:
  - name: Compliance jobs                    # обязательное, 1-255 символов
    description: Runs the compliance check in every pipeline
    enabled: true                            # обязательное
    pipeline_config_strategy: inject_policy  # обязательное: inject_policy или override_project_ci
    suffix: on_conflict                      # необязательное: on_conflict (по умолчанию) или never
    skip_ci:                                 # необязательное
      allowed: false                         # обязательное в этом ключе; false: [skip ci], [ci skip] и ci.skip не пропускают эту политику
      allowlist:
        users:
          - id: 42                           # этот пользователь всё равно может пропустить
    no_pipeline:                             # необязательное, той же формы, что skip_ci; для опции ci.no_pipeline
      allowed: false
    content:
      include:
        - project: compliance/ci
          file: policy-ci.yml
          ref: main                          # необязательное, иначе ветка проекта по умолчанию
    variables_override:                      # необязательное
      allowed: false                         # проходят только имена из exceptions; true позволяет переменным пользователей перекрывать переменные политики
      exceptions:
        - DEPLOY_ENVIRONMENT
      dotenv: respect_policy                 # необязательное: respect_policy (по умолчанию) или allow_override
    policy_scope: {}                         # необязательное, то же определение, что у политики выполнения сканирования
    metadata:                                # необязательное, произвольные строковые аннотации
      owner: compliance-team

В списке pipeline_execution_policy одного документа допустимо не более 5 записей по умолчанию (администратор может задать от 1 до 20, см. Ограничения), а к одному пайплайну в сумме применяется столько же политик выполнения пайплайна — считая вместе проект и его группы, старшие уровни в первую очередь. Более младшая политика не может вытеснить более старшую.

Справочник полей

ПолеОписание
nameОбязательное. Имя политики, 1-255 символов.
descriptionПроизвольный текст, описывающий назначение политики.
enabledОбязательное. Активна ли политика.
content.includeОбязательное. Ровно одна запись: project (обязательно, проект, из которого читается CI/CD-файл), file (обязательно, путь к нему), ref (необязательно, ветка, тег или коммит; иначе ветка проекта по умолчанию).
pipeline_config_strategyОбязательное. inject_policy или override_project_ci (см. «Стратегии» ниже).
suffixon_conflict (по умолчанию) или never — что происходит, когда имя задачи этой политики совпадает с именем другой задачи (см. «Конфликты имён задач и suffix»).
skip_ciМожно ли пропустить задачи этой политики директивами [skip ci], [ci skip] и ci.skip: allowed (обязательно, если ключ задан) и список идентификаторов пользователей allowlist.users, которым пропуск всё же разрешён. Без ключа политика запрещает пропуск, как при allowed: false (см. «[skip ci] и отправка изменений без пайплайна»).
no_pipelineТой же формы, что skip_ci, — для опции отправки ci.no_pipeline (git push -o ci.no_pipeline).
variables_overrideКакие переменные, заданные пользователем, попадают в задачи политики: allowed (обязательно внутри этого ключа), exceptions (до 100 имён по 255 символов) и dotenv (respect_policy, по умолчанию, или allow_override). При allowed: true переменные, заданные пользователем, перекрывают собственные переменные политики (см. «Переменные»).
policy_scopeКакие проекты и группы покрывает политика: projects.including/excluding и groups.including/excluding, каждый — список {id: <ID>}. То же определение, что у политики выполнения сканирования. Пустой список including (including: []) означает то же, что отсутствие including: все проекты.
metadataПроизвольные строковые пары ключ-значение; самим движком политики не читаются.

Стратегии

pipeline_config_strategy определяет, что происходит с собственной конфигурацией CI/CD покрытого проекта:

  • inject_policy — собственный .gitlab-ci.yml проекта читается и обрабатывается как обычно, а задачи политики встраиваются в него: стадия, нужная политике, которой ещё нет у проекта, вставляется прямо перед ближайшей следующей стадией из порядка самой политики, которая у проекта уже есть, а если такой нет — перед .post. Политика без stages: использует порядок по умолчанию build, test, deploy, поэтому она тоже падает в проекте, порядок стадий которого ему противоречит, например stages: [test, build, deploy], даже если её единственная задача находится в test. Если порядок стадий политики противоречит порядку проекта (например, у проекта build идёт раньше deploy, а у политики — наоборот), вместо применения политика получает собственную падающую задачу (см. «Ошибки»). Сообщение об ошибке начинается словами «Cyclic dependencies detected when enforcing policies.» и затем называет стадии политики и пайплайна.

    Политика, все задачи которой находятся только в .pre и .post, не добавляет задач, как и любой пайплайн, в котором есть только эти стадии. Чтобы такие задачи выполнялись, добавьте политике хотя бы одну задачу в другой стадии, например в .pipeline-policy-pre.

  • override_project_ci — собственный .gitlab-ci.yml проекта не читается вовсе: проект получает пустую конфигурацию, и пайплайн наполняют только стадии .pre и .post, применяемые политики (как override_project_ci, так и inject_policy) и обязательные сканирования. Имя пайплайна берётся из workflow:name самой младшей политики с override_project_ci, у которой оно задано. Если политика отфильтрована собственными правилами (её workflow:rules или rules всех её задач), она всё равно заменяет CI проекта: .gitlab-ci.yml проекта не читается, а политика не добавляет задач. Если задач не добавляет и никакая другая политика, пайплайн не создаётся. Так workflow:rules политики решают за проект, например останавливают пайплайны в ветках. Чтобы вернуть собственные задачи проекта, укажите сам проект в content.include другой политики (например, project: $CI_PROJECT_PATH, ref: $CI_COMMIT_SHA) — тогда они станут задачами этой политики, внутри её стадий.

Политики в пайплайнах merge request

Задачи политики подчиняются обычным правилам CI. Если в CI/CD-файле политики нет workflow:rules, а у её задач нет rules, задачи получают значение по умолчанию only: [branches, tags], поэтому в пайплайнах merge request они не появляются, и там выполняются только собственные задачи проекта. Чтобы политика выполнялась и в пайплайнах merge request, задайте в её CI/CD-файле workflow:rules или rules у задач так, чтобы они срабатывали в пайплайнах merge request. Например:

workflow:
  rules:
    - when: always

policy-check:
  stage: .pipeline-policy-pre
  script:
    - ./check.sh

Здесь when: always заставляет политику выполняться в пайплайне с любым источником. Чтобы ограничить её пайплайнами merge request, используйте вместо этого более узкое правило, например if: $CI_PIPELINE_SOURCE == "merge_request_event".

Зарезервированные стадии и блокировка

Пайплайн, к которому применяется хотя бы одна политика выполнения пайплайна — пусть даже только с падающей задачей ошибки, — получает две дополнительные стадии: .pipeline-policy-pre первой и .pipeline-policy-post последней. Задача проекта, помещённая прямо в одну из этих стадий, отклоняется — так же, как задача в необъявленной стадии. Конфигурация пайплайна при этом признаётся недействительной с ошибкой «<job> job: chosen stage <stage> is reserved for pipeline execution policies». Проект может объявить .pipeline-policy-pre или .pipeline-policy-post в собственном .gitlab-ci.yml, пока к нему не применяется ни одна политика: тогда это обычные стадии, и блокировка не действует. Блокировка включается, только когда в стадии есть задачи политики, в том числе задача ошибки политики.

Каждая другая задача пайплайна ждёт завершения .pipeline-policy-pre, включая задачу с needs: []. Как только .pipeline-policy-pre завершается успешно (или с ошибкой при allow_failure: true), остальной пайплайн выполняется обычным образом. Если стадия падает или отменяется, все остальные задачи пропускаются — включая задачи с when: always и when: on_failure, — и пайплайн падает: задача проекта не может обойти упавшую блокировку, ожидая её с when: always. Блокировка так же останавливает остальной пайплайн, когда все её задачи политики пропущены, например когда единственная задача политики в ней имеет when: on_failure.

Ошибки

Политика, которую не удалось собрать — её CI/CD-файл или проект отсутствует либо недоступен, её CI невалиден, либо сборка упала по любой другой причине, — не останавливает создание пайплайна. Вместо этого задачи такой политики заменяются одной падающей задачей <slug политики>:policy_error, помещённой в .pipeline-policy-pre; при совпадении имени она становится <slug политики>-p<ID проекта политик>-<индекс>:policy_error. Если и это имя занято, добавляется счётчик: <slug политики>-p<ID проекта политик>-<индекс>-2:policy_error, затем -3 и так далее. Slug строится из латинских букв и цифр имени политики; остальные символы, в том числе кириллица, отбрасываются. Если ничего не остаётся, slug равен policy-<индекс>, где индекс — позиция политики в документе, начиная с 0. В логе задачи названы политика, её проект политик безопасности и сама ошибка, после чего задача падает. На остальные применимые политики и на собственные задачи проекта это не влияет.

У задачи ошибки нет tags и image: она не берёт их из default: и переменных проекта, поэтому проект не может сделать так, чтобы она прошла. Ей нужен раннер, который принимает задачи без тегов и запускает POSIX-оболочку, например shell executor или Docker executor, в образе по умолчанию которого есть sh. Без такого раннера задача остаётся в ожидании, и пайплайн блокируется, а не проходит.

Конфликты имён задач и suffix

Имена задач сравниваются без учёта маркера parallel (job 1/2, job: [a]). Имена задач проекта всегда считаются занятыми. Все политики обрабатываются за один проход в порядке слияния: собственные задачи проекта, политики проекта, затем политики его групп от ближайшей группы вверх, группа верхнего уровня последней. Внутри одного файла политик порядок совпадает с порядком в документе. Задача, которая первой заняла имя, сохраняет его независимо от значения suffix.

  • suffix: on_conflict (по умолчанию) — задача, имя которой уже занято проектом или более ранней политикой в порядке слияния, переименовывается в <имя>:policy-<ID проекта политик>-<индекс>, маркер parallel остаётся в конце. Если и переименованное имя занято задачей проекта или другой политики, добавляется счётчик: <имя>:policy-<ID проекта политик>-<индекс>-2, затем -3 и так далее. Ссылки на переименованную задачу внутри той же политики следуют за новым именем: needs и dependencies других задач политики, а также job в записи trigger:include:artifact задачи-триггера политики.
  • suffix: never — имя задачи не меняется. Если любое имя этой политики уже занято задачей проекта или более ранней политикой в порядке слияния, эта политика вместо применения получает падающую задачу ошибки (см. «Ошибки»). Ошибка называет только задачу, чьё имя занято, а не другую политику: «The job name X is already used in the pipeline, and the policy does not allow a suffix (suffix: never).»

Например, у группы, её подгруппы и проекта есть по политике с задачей dup, а в собственном пайплайне проекта такой задачи нет. Политика проекта сохраняет имя dup, а задачи политик подгруппы и группы получают имена dup:policy-<ID>-<индекс>.

Порядок политик внутри одного документа имеет значение. В документе группы с политиками [A (on_conflict), B (never)], у обеих из которых есть задача dup, A сохраняет dup, а B падает с задачей ошибки. При обратном порядке [B (never), A (on_conflict)] B сохраняет dup, а задача A получает суффикс.

Используйте suffix: never, только если на точное имя задачи ссылается что-то вне политики — например, needs другой задачи.

[skip ci] и отправка изменений без пайплайна

По умолчанию политика не позволяет пропустить свои задачи. Коммит, отправленный с [skip ci] или [ci skip] в сообщении либо с опцией отправки ci.skip, обычно вообще не создаёт пайплайн. Если какая-либо применимая политика запрещает пропуск, пайплайн всё равно создаётся полностью — вместе идут собственные задачи проекта, обязательные сканирования и задачи политики. Политика запрещает пропуск, когда её skip_ci.allowed равно false либо ключ не задан, а отправивший изменения пользователь не входит в её allowlist.users.

Ключ no_pipeline работает так же, но только для опции отправки ci.no_pipeline (git push -o ci.no_pipeline). Отправка без этой опции на него не влияет.

Проект без конфигурации CI/CD — отдельный случай. Политика выполнения пайплайна, которая к нему применяется, всё равно создаёт пайплайн с задачами политики, и никакая настройка для этого не нужна.

Политика, чей пайплайн отфильтрован её собственными правилами (её workflow:rules или rules всех её задач), ничего не выполняет, поэтому ничего не запрещает.

Укажите allowed: true либо перечислите пользователей в allowlist.users (по id), чтобы разрешить пропуск этой политики как обычно. Когда каждая применимая политика выполнения пайплайна разрешает пропуск, а отказывают только настройки самой политики выполнения сканирования, пайплайн сохраняет только обязательные сканирования, без задач этой политики.

Переменные

Внутри собственного CI/CD-файла политики переменные задачи по умолчанию побеждают: над любой переменной CI/CD, которую определяет пользователь (переменные инстанса, группы и проекта, а также переменные ручного запуска пайплайна, расписания, триггера и ручной задачи), и над dotenv-переменными из собственных зависимостей задачи, если не задано dotenv: allow_override (см. ниже). Исключение — variables_override с allowed: true, о нём ниже. Предопределённые переменные CI_* это не затрагивает.

variables_override определяет, какие пользовательские переменные вообще попадают в задачу политики, прежде чем поверх них добавляются переменные самой задачи. То же правило действует на пользовательские переменные, которые могут читать rules задач политики, её workflow:rules и include:rules:

variables_overrideЧто попадает в задачуПри совпадении имени с переменной политики
Не задано (по умолчанию для inject_policy и override_project_ci)Все переменные, заданные пользователемПобеждает переменная политики
allowed: falseТолько имена, перечисленные в exceptionsПобеждает переменная политики, в том числе над исключением
allowed: trueВсе переменные, заданные пользователем, кроме перечисленных в exceptionsПобеждает переменная, заданная пользователем

При allowed: true переменные, которые определяют пользователи и которых нет в exceptions, перекрывают собственные переменные политики с теми же именами. При allowed: false проходят только имена из exceptions, а переменные политики по-прежнему побеждают. rules задач политики видят те же переменные, что и сама задача.

Для политики по расписанию (pipeline_execution_schedule_policy) отсутствующий variables_override, напротив, по умолчанию означает allowed: false: пайплайн по расписанию создаёт бот политик безопасности, а не участник проекта, поэтому ни одна пользовательская переменная не попадает в его задачи, если её имя не указано в exceptions.

dotenv определяет, как обрабатываются dotenv-переменные из собственных зависимостей задачи политики: respect_policy (по умолчанию) пропускает их через то же правило, что и пользовательские переменные; allow_override передаёт их без фильтрации, и тогда они тоже перевешивают переменные самой политики. Без allow_override dotenv-переменные не перекрывают переменные политики, даже при allowed: true. Это относится и к dotenv-переменным из других задач того же пайплайна политики, переданным через dependencies или needs.

Без variables_override пользователь может отключить политику переменной, заданной при запуске пайплайна, если workflow:rules политики (или rules задачи) зависят от этой переменной. Чтобы закрыть эту возможность, задайте variables_override: {allowed: false} и укажите в exceptions только те имена, которые политике действительно нужны.

Переменные variables: верхнего уровня и default: собственного .gitlab-ci.yml покрытого проекта не попадают в задачи политики ни при каком значении variables_override: пайплайн политики собирается только из её собственного содержимого CI/CD.

На странице «Запустить новый пайплайн» форма также заполняется заранее переменными, которые CI/CD-файлы политик, применяемых к проекту, объявляют с description в variables: верхнего уровня. Подставляются только те переменные, которые значение из формы действительно может изменить: у политики задан variables_override с allowed: true, а имя не указано в exceptions. Без variables_override или при allowed: false побеждают собственные переменные политики, поэтому ни одна из них не подставляется.

Переменная собственного .gitlab-ci.yml проекта с тем же именем сохраняет значение и описание проекта. Форма отправляет все подставленные значения во весь пайплайн, поэтому переменная не подставляется, если политики, значения которых форма может переопределить, задают ей разные значения, в корне или в variables: задания, в том числе в задании той же политики со значением, отличным от корневого. Переменная с одинаковым значением везде подставляется.

CI-файл политики читается с правами пользователя, который открывает страницу, как и при создании пайплайна: файл, который пользователь не может прочитать, и некорректный файл ничего не добавляют. Это работает и для проекта без .gitlab-ci.yml. Список кешируется так же, как подстановка собственных переменных проекта, поэтому изменение политики появится после обновления кеша.

Для задачи, которую добавила политика, GitLab передаёт раннеру имя политики и её настройки variables_override (allowed и exceptions), а раннер, который их поддерживает, выводит их в начале лога задачи. Остальные раннеры их игнорируют. Если у встраиваемой или заменяющей политики нет variables_override, передаётся только имя политики; для политики по расписанию передаётся и allowed: false.

Доступ к CI-файлу и безопасность

Собственный content.include политики читает CI/CD-файл независимо от того, есть ли у автора пайплайна доступ к проекту, только если content.include.project — это сам проект политик безопасности. Разрешено ли это, определяет настройка spp_repository_pipeline_access, которая читается из самого проекта политик безопасности и разрешается в следующем порядке — побеждает первое заданное значение:

  1. заблокированное значение инстанса;
  2. значение ближайшей к корню заблокированной группы;
  3. собственное значение проекта политик безопасности;
  4. значение ближайшей группы над проектом политик безопасности, где оно задано;
  5. значение инстанса по умолчанию.

У нового проекта есть собственное значение, и оно включено. Доступ к проекту политик безопасности остаётся включённым, пока проект его не выключит или пока настройку не заблокирует инстанс либо группа. Значения группы и инстанса действуют только для проекта, у которого нет собственного значения.

Чтобы изменить значение проекта политик безопасности, откройте его «Настройки» → «Основные» → «Уровень доступа, доп. функции проекта, права», найдите раздел «Политики выполнения пайплайна» и используйте флажок «Предоставить доступ к настройкам CI/CD для проектов, связанных с этим проектом политики безопасности в качестве источника политик безопасности.» Флажок недоступен, если настройку заблокировал инстанс или группа.

Для CI/CD-файла из любого другого проекта, например compliance/ci из примера синтаксиса, этот доступ не действует. Пользователю, который создаёт пайплайн, нужен доступ на чтение к этому проекту, либо этот проект должен разрешить bot-доступ, как описано ниже.

CI/CD-файл политики может также подключить через include:project файл из проекта, отличного от её проекта политик безопасности, или получить шаблон CI/CD-компонента — без того, чтобы автор пайплайна имел туда доступ на чтение. Это работает, только если владелец этого другого проекта сам разрешил это в своём разделе «Настройки» → «Основные» → «Уровень доступа, доп. функции проекта, права», блок «Доступ политик выполнения пайплайна к файлам CI/CD», и выполняются эти условия:

  • включена настройка «Разрешить доступ к файлам конфигурации CI/CD в этом проекте.» (pipeline_execution_policy_bot_access_enabled);
  • запрошенный путь совпадает с одним из указанных там шаблонов (до 20 штук, по 255 символов каждый, pipeline_execution_policy_bot_access_file_patterns), например ci/**/*.yml. Поддерживаются подстановки *, **, ? и [...]. Фигурные скобки вида {a,b} не раскрываются и сопоставляются буквально. Путь с сегментом . или .. отклоняется;
  • покрытый проект входит в указанную там группу (pipeline_execution_policy_bot_access_group_id), а если группа не указана — входит в корневую группу этого другого проекта. Даже если группа указана, покрытый проект должен входить в ту же корневую группу, что и этот другой проект;
  • политика, которая применяется к покрытому проекту, называет этот другой проект в собственном content.include.

Последнее условие означает, что вложенный include:project или компонент из третьего проекта, который никакая политика не называет в собственном content.include, отклоняется.

Защитите основную ветку проекта политик безопасности и каждого проекта, чьи CI/CD-файлы подключает политика, так чтобы отправлять в неё изменения могли только доверенные мейнтейнеры: тот, кто может отправить CI/CD-файл политики, управляет задачами, которые выполняются во всех проектах, покрытых этой политикой, в обход их собственного ревью. Никогда не храните секреты в CI/CD-файле политики — вместо этого используйте защищённые или замаскированные переменные CI/CD.

Политики по расписанию

Политика pipeline_execution_schedule_policy не встраивает задачи в собственный пайплайн покрытого проекта: она создаёт свой пайплайн, собранный только из её содержимого CI/CD, от имени бота политик безопасности, по расписанию наподобие cron. У неё нет pipeline_config_strategy, suffix, skip_ci и no_pipeline, поскольку она никогда не сливается с пайплайном проекта.

Форма («Режим правил») карточки «Политика выполнения пайплайна по расписанию» раскладывает политику на разделы: «Конфигурация пайплайна» (включаемый CI/CD-файл), «Расписание», «Приостановить запланированные запуски» (настройки snooze), «Пользовательские переменные» (variables_override) и, для политики уровня группы, «Область действия политики». После того как политика сохранена, появляется ещё и раздел «Тестовый запуск» (см. «Тестовые запуски» ниже).

В разделе «Расписание» поле «Временное окно» принимает число и единицу измерения («Минуты», «Часы» или «Дней»). Значение вне допустимого диапазона сразу заменяется ближайшим допустимым, поэтому при вводе 5 минут поле показывает 10 минут. У политики без time_window поле пустое, с сообщением «Это поле обязательно к заполнению».

В документе допустимо не более 5 таких записей, и у каждой ровно одна запись schedules:

pipeline_execution_schedule_policy:
  - name: Nightly compliance audit
    enabled: true
    content:
      include:
        - project: compliance/ci
          file: scheduled-audit.yml
    schedules:
      - type: daily                 # daily, weekly или monthly
        start_time: '02:00'         # ЧЧ:ММ
        timezone: UTC                # необязательное, по умолчанию UTC
        time_window:                 # обязательное
          value: 3600                # обязательное, секунды, окно разброса
          distribution: random       # обязательное, допустим только random
        branches: [main, release]    # необязательное, до 5 явных имён; иначе ветка по умолчанию
        snooze:                      # необязательное
          until: '2026-11-01T00:00:00Z'
          reason: Paused during the migration
    policy_scope: {}
  • start_time нужно заключать в кавычки (start_time: "06:00"). YAML читает 06:00 без кавычек как число, и политика становится недействительной.
  • type задаёт каденцию: daily не требует ничего дополнительно; weekly требует days — список названий дней недели (Monday, …, Sunday); monthly требует days_of_month — список чисел от 1 до 31.
  • timezone по умолчанию — UTC, в отличие от расписаний самой политики выполнения сканирования, которые без явной зоны берут часовой пояс сервера. Это должно быть имя часового пояса IANA, например Europe/Moscow; имя часового пояса Rails, например Moscow, тоже принимается. Неизвестный часовой пояс делает политику недействительной.
  • time_window обязателен, в нём обязательны и value, и distribution. distribution допускает только random.
  • time_window.value случайно распределяет запуск пайплайнов всех покрытых проектов в пределах этого числа секунд (от 600 до 2 629 746, то есть примерно от десяти минут до месяца), вместо того чтобы запускать их все одновременно; реальный разброс также ограничен временем, оставшимся до следующего запланированного запуска.
  • branches явно называет до 5 веток — без шаблонов. Ветка, которой больше не существует, пропускается. Если ни одной из перечисленных веток в проекте нет либо список пуст или отсутствует, используется ветка проекта по умолчанию. Проект с пустым репозиторием пропускается.
  • Когда часы переводят назад при переходе на зимнее время, местное время слота может наступить дважды, поэтому расписание может сработать дважды за этот день.
  • snooze.until (дата и время в формате ISO 8601) и необязательный snooze.reason (до 256 символов) пропускают все запуски, которые должны были произойти до этого момента, не отключая саму политику; первый запуск после until происходит как обычно.

Когда политика изменяется, отключается, удаляется, либо покрытый проект выходит из policy_scope, каждый уже запущенный ею пайплайн, который ещё не завершился, отменяется. То же происходит, когда проект политик безопасности проекта или группы отвязывают или заменяют другим: незавершённые пайплайны, запущенные его политиками по расписанию для этого проекта или группы, отменяются.

Изменения расписания, приостановка и отмена уже запущенных пайплайнов вступают в силу при следующей синхронизации. Синхронизация выполняется каждые 5 минут. При отвязке проекта политик безопасности запущенные пайплайны отменяются сразу.

Для политики по расписанию variables_override по умолчанию означает allowed: false (см. «Переменные» выше): переменные, нужные запуску по расписанию, перечисляйте в exceptions явно. В разделе формы «Пользовательские переменные» выбор «Разрешить все пользовательские переменные» не просто оставляет поле пустым, как для встраиваемой или заменяющей политики: поскольку отсутствующий variables_override здесь запрещает все переменные, этот выбор вместо этого записывает в политику variables_override: {allowed: true}.

Список «Политики» показывает для политики по расписанию столбец «Следующий запуск».

Тестовые запуски

Откройте уже сохранённую политику по расписанию в редакторе, чтобы увидеть её раздел «Тестовый запуск» — у ещё ни разу не сохранённой политики тестировать пока нечего. Нажмите кнопку «Тестовый запуск», чтобы открыть диалог, выберите до 5 проектов (у политики уровня проекта выбирать не из чего — запускать можно только на её собственном проекте) и нажмите «Запустить»: это сразу же, не дожидаясь расписания, запускает пайплайн политики на каждом выбранном проекте. Включать политику для тестового запуска не обязательно.

Тестовый запуск отличается от запуска по расписанию так:

  • Он выполняется на ветке по умолчанию каждого выбранного проекта. Список branches игнорируется.
  • Он использует политику в том виде, в каком она сохранена в основной ветке проекта политик безопасности, а не версию, открытую в редакторе. Сначала сохраните политику и слейте её merge request.
  • Приостановка (snooze) игнорируется.
  • Каждый выбранный проект должен входить в область действия политики, и у вас должно быть право создавать там пайплайны. Иначе ничего не запускается, и вы получаете ошибку «Эту политику нельзя тестово запустить в проектах: <пути проектов>.»

Под кнопкой тот же раздел показывает последние 20 тестовых запусков политики. Столбцы: «Проект», «Статус пайплайна» (текущий статус созданного запуском пайплайна со ссылкой на него), «Запущен», «Кто запустил» и «Ошибка», где указана причина сбоя запуска. Запуск, который не завершился через сутки после старта, получает статус «Устарело», а его пайплайн отменяется, если ещё активен. Тестовые запуски старше 30 дней удаляются.

Список показывает только запуски в проектах, которые вы можете читать. Ссылка на пайплайн и сообщение об ошибке запуска показываются, только если вы можете просматривать пайплайны его проекта; иначе в столбце «Статус пайплайна» показывается собственный статус запуска («Создано», «Выполняется», «Завершено», «Неудачно» или «Устарело»), а в столбце «Ошибка» — прочерк.

Ограничения

ОграничениеЗначение
Записей pipeline_execution_policy в документе5 по умолчанию, настраивается от 1 до 20
Записей pipeline_execution_schedule_policy в документе5
Политик выполнения пайплайна, применяемых к одному пайплайну (проект и его группы вместе)5 по умолчанию, настраивается от 1 до 20
Записей content.includeРовно 1
Длина name1-255 символов
Записей variables_override.exceptions100, по 255 символов каждая
Записей schedules на политику по расписаниюРовно 1
time_window.valueОт 600 до 2 629 746 секунд
Записей branches (политика по расписанию)5
Значения days_of_monthОт 1 до 31
Длина snooze.reasonДо 256 символов
Шаблонов bot-доступа на проект20, по 255 символов каждый
Проектов на тестовый запуск5
Тестовых запусков в спискеПоследние 20 на политику, не старше 30 дней

Изменение лимита политик выполнения пайплайна

Лимит может изменить администратор:

  1. В области администратора перейдите в «Настройки» → «CI/CD».
  2. Разверните раздел «Политики выполнения пайплайна».
  3. Задайте «Максимум политик выполнения пайплайна».
  4. Нажмите «Сохранить изменения».

Лимит можно задать и через REST API. Отправьте PUT /api/v4/application/settings с параметром fe_application_settings_attributes[pipeline_execution_policy_limit], значение от 1 до 20:

curl --request PUT --header "PRIVATE-TOKEN: $ADMIN_TOKEN" \
  --header "Content-Type: application/json" \
  --data '{"fe_application_settings_attributes": {"pipeline_execution_policy_limit": 10}}' \
  "<INSTANCE_URL>/api/v4/application/settings"

GET /api/v4/application/settings возвращает текущее значение в fe_application_settings_attributes.

Раздел виден только при включённых политиках выполнения пайплайна. Одно значение действует и на число записей в документе, и на число политик, применяемых к одному пайплайну. Лимит политик по расписанию остаётся равным 5.

Каждая политика строится как отдельный пайплайн при создании каждого пайплайна охваченного проекта: продукт читает её CI/CD-файл и подключаемые файлы и разбирает YAML. Чем выше лимит, тем дольше каждая отправка изменений ждёт свой пайплайн и тем выше нагрузка на Gitaly и Sidekiq. Пайплайн, запущенный из интерфейса или через API, создаётся прямо в запросе, поэтому может не уложиться в таймаут запроса и не быть создан. Повышайте лимит только для лёгких политик и после этого проверяйте время создания пайплайна.

При уменьшении лимита лишние политики перестают применяться: сначала младшие уровни, а внутри документа — последние. Документ, сохранённый до уменьшения лимита, остаётся редактируемым: политики в нём можно править и удалять, но изменение, которое добавляет политики сверх лимита, отклоняется.

Лимит политик выполнения пайплайна в области администратора

Дополнительные ресурсы