Перейти к содержанию
zoryn/ maintainer-assistant

Конфигурация

zoryn читает конфигурацию из трёх мест, по возрастанию специфичности:

ФайлНазначение
~/.zorynГлобальный пользовательский конфиг (TOML). Необходим для работы zoryn.
~/.config/zoryn/builders.d/*.confОдин .conf на каждый билдер — локальную или удалённую hasher-машину.
.gear/version-upПереопределения для конкретного пакета: маппинг upstream-версий, источники CVE, подсказки для merge.

Запустите zoryn gen environment для быстрого bootstrap ~/.zoryn плюс SSH, hasher и GPG-конфигов одним вызовом.

~/.zoryn

Минимальный пример — zoryn работает даже с такой конфигурацией:

[gitery]
remote = "gitery"

У всех остальных секций есть разумные значения по умолчанию. Переопределяйте только то, что действительно отличается.

Полный пример

[build]
command = "hsh -v --number={hasher_number} --mountpoint=/proc,/dev/pts,/dev/kvm --lazy-cleanup {hasher_dir}"
log_filename = "build.{batch}.{builder}.log"

[builders]
default = "local"
default_arch = "x86_64"
parallel = "off"
results_download_dir = "{git_root}/hasher_out"
batch_repo = "~/zoryn-batch-repo"

[gitery]
host = "gitery"
remote = "gitery"
login = "rider"

[gitoskop]
url = "https://git.altlinux.org/gitoskop/api"

[gyle]
host = "gyle"

[sources]
srpms_path = "/mnt/ftp/pub/distributions/ALTLinux/Sisyphus/files/SRPMS/"

[rebuild]
command = "hsh -v --mountpoint=/proc,/dev/pts,/dev/kvm --lazy-cleanup"
log_dir = "/tmp/rebuild-logs"

[add_changelog]
up_template = "- {old_version} -> {new_version} {cves}"

[ssh]
multiplexing = true   # повторное использование TCP через ControlMaster (по умолчанию: true)
persist = "10m"       # время жизни master-соединения (по умолчанию: 10m)

[notify]
enabled = true        # уведомления рабочего стола для долгих команд (по умолчанию: true)

[commands]
# Опционально: переопределение путей и аргументов для внешних команд
# git = "/usr/local/bin/git"
# git.fetch = "{git} fetch --prune"
# ssh = "ssh -o ConnectTimeout=10"
# ssh.gitery = "{ssh} -p 2222 -i ~/.ssh/alt_key"

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

[build]

  • command — команда hsh для локальной сборки. zoryn gen environment записывает hsh -v --packager={packager} --mountpoint=/proc,/dev/pts,/dev/kvm --lazy-cleanup {hasher_dir}. Аргумент {hasher_dir} направляет сборку и остальные операции локального билдера в один каталог (по умолчанию ~/hasher). Используйте hsh, а не gear-hsh — тарболл создаётся отдельно через gear --commit. Для параллельной сборки несколькими локальными hasher также используйте {hasher_number}.
  • log_filename — шаблон имени лог-файла (по умолчанию: build.{batch}.{builder}.log). Плейсхолдеры: {builder}, {batch}, {pkgname}.
  • packager — строка packager (Имя <email>), передаётся в hsh --packager= при локальной сборке (по умолчанию: не задано — hsh использует свой настроенный packager).

[builders]

  • default — билдер(ы) по умолчанию, когда --builder не указан и нет настроек для ветки. Строка через запятую или TOML-массив ("local" или ["local", "arm-server"]).
  • default_arch — архитектура(ы) по умолчанию для multi-builder режима. Строка через запятую или TOML-массив. При указании нескольких архитектур автоматически включается multi-builder.
  • parallel — параллельный режим для multi-builder сборок (on или off, по умолчанию: off). Переопределяется флагами --parallel / --sequential.
  • results_download_dir — каталог для скачивания результатов удалённой сборки (по умолчанию: {git_root}/hasher_out). Поддерживает {git_root}.
  • batch_repo — каталог для накопления RPM при batch-сборке. Используется download_rpms / upload_rpms.
  • repo_workdir — корневой каталог, в котором zoryn task mkrepo собирает репозитории задач (<repo_workdir>/<task_id>/repo). Можно задать как здесь глобально, так и для отдельного билдера.

[builders.<ветка>] — настройки по веткам

[builders]
default = "sis-x86, sis-arm"
default_arch = "x86_64"

[builders.p11]
default = "p11-x86"
default_arch = "x86_64"

[gitery]

  • host — SSH-алиас для gitery. Должен соответствовать записи в ~/.ssh/config.
  • remote — имя git remote, указывающего на gitery. Используется для push.
  • login — логин gitery/ALT Linux, используется zoryn gitery для резолва короткого имени репозитория в people/<login>/packages/<name>. Обязателен для резолва коротких имён; не нужен при полном пути или заданном -n/--namespace. Если ключ не задан, логин выводится из git user.email, когда это адрес в домене @altlinux.org: логином становится локальная часть адреса (до @).

[gitoskop]

  • url — базовый URL HTTP API gitoskop, используется командами чтения zoryn gitery и как база встроенного MCP-сервера gitoskop в zoryn agent mcp (по умолчанию: https://git.altlinux.org/gitoskop/api). Завершающий слэш отбрасывается.

[gyle]

  • host — SSH-алиас для системы сборки gyle.

[sources]

  • srpms_path — локальное зеркало SRPMS (требуется для zoryn task rebuild).

[rebuild]

  • command — команда hasher для пересборки пакетов (по умолчанию: hsh -v --mountpoint=/proc,/dev/pts,/dev/kvm --lazy-cleanup).
  • log_dir — базовый каталог для логов сборки (по умолчанию: /tmp/rebuild-logs).

[tasks]

  • api_url — базовый URL Tasks API (по умолчанию: https://git.altlinux.org/tasks/api).
  • user — имя пользователя girar для API-запросов (по умолчанию: извлекается из email %packager в ~/.rpmmacros).

[rdb]

  • api_url — базовый URL RDB API (по умолчанию: https://rdb.altlinux.org/api).

[clone]

  • api_url — endpoint API, возвращающий URL git-репозитория пакета, используется zoryn clone (по умолчанию: {[rdb] api_url}/package/clone_url). Завершающий слэш отбрасывается.

[repoteka]

  • url — базовый URL Repoteka для запросов пакетов/архитектур (по умолчанию: https://rdb.altlinux.org/repoteka). Завершающий слэш отбрасывается.

[hosts] — лимиты мониторинга хостов-билдеров

Пороги нагрузки, проверяемые перед отправкой сборки на хост. Задаются глобально в [hosts] или для конкретного хоста в [hosts."<hostname>"] (значение для хоста имеет приоритет над глобальным).

  • min_free_ram — минимум свободной RAM, ниже которого хост считается занятым (по умолчанию: 2G). Принимает суффиксы вроде 2G, 512M.
  • max_load_avg — максимальная 1-минутная средняя загрузка (по умолчанию: 8.0).
  • max_io_wait — максимальный процент ожидания I/O (по умолчанию: 50).

[add_changelog]

  • up_template — шаблон записи changelog для zoryn up (по умолчанию: - updated from {old_version} to {new_version} {cves}).
    • {old_version}, {new_version}, {cves} (последнее — (Fixes: CVE-...) или пустая строка).
    • Секция [add_changelog] в .gear/version-up имеет приоритет над ~/.zoryn.
    • Пробелы в конце обрезаются автоматически.

[submit]

  • run — запускать ли задание после создания/изменения (по умолчанию: false).
  • test_only — помечать ли задание как тестовое (по умолчанию: true).

Для восстановления старого поведения (run с --commit по умолчанию):

[submit]
run = true
test_only = false

[ssh]

  • multiplexing — включить мультиплексирование SSH через OpenSSH ControlMaster (по умолчанию: true). Повторно использует TCP-соединения, снижая задержки при многошаговых операциях сборки.
  • persist — время жизни master-соединения (по умолчанию: 10m). Формат — как ControlPersist в ssh_config(5).
  • alive_intervalServerAliveInterval для мультиплексированного соединения, в секундах (по умолчанию: 15).
  • alive_count_maxServerAliveCountMax для мультиплексированного соединения (по умолчанию: 3).
  • Сокеты хранятся в $XDG_RUNTIME_DIR/zoryn/ (или $TMPDIR) и автоматически очищаются при выходе.

[notify]

  • enabled — включить уведомления рабочего стола для долгих команд (по умолчанию: true). Отправляет OSC 99 escape-коды (протокол kitty) + BEL в stderr. Kitty, WezTerm и foot показывают всплывающее уведомление; другие терминалы только BEL. Срабатывают при завершении: build, up, task rebuild, task test-rebuild, task batch.

[commands]

  • Переопределение путей и глобальных аргументов для внешних команд (git, ssh, gear-*, rpm и др.).
  • Подкоманды наследуют базовую: git.fetch = "{git} fetch --prune" — если git переопределён, git.fetch использует переопределение.
  • ~/ и $HOME раскрываются в абсолютные пути.
  • Shell-метасимволы (;, |, `, $()) отклоняются при запуске.

[devenv]

  • backend — бэкенд по умолчанию для zoryn devenv: bwrap или podman. Если не задан, используется podman (когда установлен), иначе bwrap.
  • packages — дополнительные пакеты для установки в окружение разработки поверх BuildRequires: из spec-файла (отладчики, редакторы, профайлеры).
  • image — базовый образ для podman-бэкенда (по умолчанию: registry.altlinux.org/<ветка>/alt:latest). Задайте, если образ по умолчанию недоступен на текущем хосте (локальное зеркало, приватный реестр); zoryn devenv --image IMAGE переопределяет на один запуск. Не читается из .gear/devenv.
  • build — массив shell-команд, выполняемых как шаги RUN при сборке образа podman, от root. Ваши шаги попадают в проектный «хвост» образа, после общих слоёв фич (см. фичи). Только машинная конфигурация — не читается из .gear/devenv.
  • build_user — как build, но от пользователя хоста (per-user установщики, напр. curl … | bash в ~/.local/bin); для root-шагов используйте sudo. Только машинная конфигурация.
  • mounts — массив путей хоста / спецификаций host:container[:opts], монтируемых в контейнер podman (каждый — флаг -v при создании контейнера, в дополнение к всегда монтируемому каталогу проекта). Чистый путь монтируется по тому же пути. Запись вида tmpfs:<путь>[:<опции>] — это вообще не bind: она превращается в --tmpfs <путь>[:<опции>], то есть в свежую tmpfs внутри контейнера с обычными ядерными опциями монтирования (size=8g,mode=1777). Монтирование происходит при создании контейнера, поэтому каталогу, в который должен писать непривилегированный пользователь, нужен mode=1777 среди опций — сменить владельца потом уже некому. Только бэкенд podman; только машинная конфигурация — не читается из .gear/devenv. В спецификации можно ссылаться на {devenv} (имя контейнера окружения, как в zoryn devenv list; в bwrap, где контейнера нет, — hostname devenv-<project>), {project} (basename каталога проекта), {branch} (действующая ветка ALT) и {profile} (активный профиль; default, если не задан): mounts = ["~/.config/herdr/sessions/{devenv}"] даёт каждому окружению собственный каталог на хосте. В имя контейнера входит хэш конфигурации, так что изменение, пересоздающее контейнер, направит {devenv} в новый каталог; каталог, переживающий пересоздания, делайте через {project}. Неизвестные {токены} остаются как написаны.
  • pids_limit — целочисленный лимит pid для контейнера podman (--pids-limit; по умолчанию 4096, 0 или отрицательное значение — без лимита). То же значение выставляется как --ulimit nproc=<n>:<n>, поэтому ulimit -u внутри контейнера совпадает с лимитом cgroup, а не с гораздо меньшим значением по умолчанию в podman (около 512) — увеличьте этот ключ, если параллельная сборка падает с posix_spawnp: Resource temporarily unavailable. Мягкий лимит не опускается ниже хостового и не поднимается выше жёсткого лимита хоста. Контейнер также запускается с --init, чтобы пожинались зомби-подпроцессы (например, фоновый авто-git gc). Только бэкенд podman; только машинная конфигурация.
  • prompt — строка bash PS1, встраиваемая в ~/.bashrc пользователя образа podman, чтобы интерактивная оболочка использовала её. Стандартные escape-последовательности приглашения (\u, \h, \w, цвет \[\e[…m\]…\[\e[0m\]) интерпретируются в момент вывода. Изменение пересобирает образ. Только бэкенд podman; только машинная конфигурация — не читается из .gear/devenv.
  • outbound_interface — имя сетевого интерфейса хоста (например, eth1). Если задан, контейнер podman переключается с --network host на rootless-сеть pasta в отдельном сетевом пространстве имён, исходящий трафик которой (IPv4/IPv6) привязан к этому интерфейсу, поэтому исходящие соединения контейнера выходят с хоста через него (а сервисы на хостовом localhost больше не разделяются). Изменение пересоздаёт контейнер из закэшированного образа (как и mounts, в тег образа он не входит). Только бэкенд podman; только машинная конфигурация — не читается из .gear/devenv.
  • dns, dns_search, dns_option — три поля /etc/resolv.conf, передаваемые podman через --dns (адреса серверов имён, IPv4/IPv6 либо литерал none), --dns-search (домены поиска либо ., чтобы очистить список) и --dns-option (опции резолвера, например ndots:2). Каждый ключ — массив; все они применяются и при сборке образа, и к контейнеру, чтобы apt разрешал имена в том числе на этапе сборки. Задавайте, когда резолверы хоста из контейнера недоступны, — обычно вместе с outbound_interface, чья привязка pasta уводит DNS в этот интерфейс. zoryn devenv --dns АДРЕС / --dns-search ДОМЕН / --dns-option ОПЦИЯ задают их на один запуск. Слой выбирается по каждому ключу отдельно (как у apt_sources, в отличие от mounts): флаг > проектный projects.d/<проект>.toml > глобальный ~/.zoryn, победивший слой заменяет остальные — порядок записей значим, и проект должен уметь поставить свой резолвер первым. В ключ кэша не входят: изменение пересоздаёт контейнер (слои образа переиспользуются). Только бэкенд podman; только машинная конфигурация — не читается из .gear/devenv.
  • forward_ssh_agent — если true, пробрасывает SSH-агента хоста в контейнер podman (хостовый $SSH_AUTH_SOCK монтируется на /run/ssh-agent.sock), чтобы инструменты внутри пользовались ключами вашего агента; zoryn devenv --ssh-agent/-A включает на один запуск. Только бэкенд podman; только машинная конфигурация.
  • ports — массив портов, публикуемых из контейнера на хост: "8080" пробрасывает один и тот же порт с обеих сторон, "18080:8080" — порт хоста 18080 на порт контейнера 8080, так что dev-сервер внутри доступен по http://localhost:18080. Перед записью можно указать интерфейс или адрес хоста, чтобы опубликовать порт шире loopback: "eth0:8080", "192.0.2.10:18080:8080", "*:3000" — на всех интерфейсах; без префикса привязка идёт к 127.0.0.1. Имена интерфейсов разрешаются в первый IPv4-адрес при каждом запуске; смена адреса пересоздаёт контейнер. Пересекающиеся привязки ("8080" вместе с "*:8080" или две записи, разрешающиеся в один адрес с разными гостевыми портами) отклоняются; два написания одного проброса публикуются один раз. Контейнер видит каждого клиента как адрес tap-интерфейса, а не реального пира. В отличие от настроек резолвера, этот ключ объединяется между слоями: список проекта добавляется к глобальному (запись, встречающаяся в обоих, публикуется один раз; выключателя на уровне проекта нет). Игнорируется, если outbound_interface не задан, — с --network host контейнер и так делит порты с хостом. Изменение списка пересоздаёт контейнер. Только бэкенд podman; только машинная конфигурация (~/.zoryn и ~/.config/zoryn/projects.d/<проект>.toml, но не .gear/devenv).
  • timezone — имя зоны IANA (например, "Asia/Almaty"), передаваемое в podman run --tz, который выставляет TZ и /etc/localtime внутри контейнера. Если не задано, контейнер использует зону образа по умолчанию (UTC). zoryn devenv --timezone переопределяет на один запуск; смена действующей зоны пересоздаёт контейнер. Только бэкенд podman — bwrap наследует TZ хоста; только машинная конфигурация — не читается из .gear/devenv.
  • env — массив записей окружения вида NAME=value, которые попадают в оболочку окружения, например env = ["GOFLAGS=-mod=vendor", "EDITOR=vim"]. В podman они передаются как --env при создании контейнера, так что их наследует и интерактивная оболочка, и zoryn devenv install; изменение списка пересоздаёт контейнер (слои образа переиспользуются). В bwrap они становятся --setenv в момент входа. Как и ports, ключ конкатенируется по слоям: сначала глобальный ~/.zoryn, затем пер-проектный список — а поскольку побеждает последнее присваивание имени, проектная запись перекрывает глобальную, и обе перекрывают запись, добавленную выбранной фичей. Каждая запись обязана быть корректной парой NAME=value без управляющих символов, без пробела в конце и без фигурных скобок, кроме плейсхолдеров {devenv}/{project}/{branch}/{profile} — они раскрываются в значениях env так же, как в mounts: env = ["HERDR_SESSION=~/.config/herdr/sessions/{devenv}"] сообщает инструменту внутри контейнера его собственный каталог окружения. При включённом forward_ssh_agent проброшенный SSH_AUTH_SOCK перекрывает одноимённую запись env. Записи попадают только в оболочку окружения — сборка образа podman (шаги build/build_user, установщики фич, apt) их не видит, так что прокси для сборки задаётся шагами build или конфигурацией apt, а не здесь. Только машинная конфигурация — никогда не читается из .gear/devenv, чтобы репозиторий пакета не мог подсунуть вам в оболочку LD_PRELOAD и подобное.
  • branch — целевая ветка ALT (по умолчанию sisyphus); из неё также выводится базовый образ podman, когда image не задан. zoryn devenv --branch/-B переопределяет на один запуск.
  • apt_config — путь к apt-конфигу хоста: файл в формате apt.conf, файл sources.list или каталог с любым из них. Для бэкенда bwrap: нормализуется в файл apt.conf для hsh --apt-config (sources.list оборачивается в сгенерированный apt.conf), чтобы chroot наполнялся из выбранных репозиториев. Для бэкенда podman: задаёт источники apt для образа контейнера (заменяет sources.list базового образа); если репозитории относятся к другой ветке ALT, нежели действующая ветка окружения, источник отбрасывается с предупреждением и остаются собственные источники базового образа. Раскрывает тильду; должен существовать. Только машинная конфигурация.
  • apt_builder — имя билдера, чей apt-конфиг используется как sources.list контейнера podman (например, "local"). Только бэкенд podman; только машинная конфигурация.
  • apt_sources — массив строк источников apt, записываемых дословно в sources.list контейнера podman (например, ["rpm file:///mnt/alt x86_64 classic"]). Локальные репозитории file: монтируются внутрь контейнера только для чтения по тому же пути; если путь не существует на хосте — это ошибка. Только бэкенд podman; только машинная конфигурация.
  • default_profile — имя профиля [devenv.profiles.<имя>], применяемого, когда --profile не задан. Только в базовой секции — не читается внутри профиля.

  • [devenv.features.<id>] — выбрать фичу devenv <id> (переиспользуемый набор пакетов + шагов установки + монтирований); ключи таблицы — опции фичи. Локальное определение (~/.config/zoryn/devenv/features/<id>.toml либо <id>/feature.toml) имеет приоритет над встроенным. Только podman; только машинная конфигурация.

  • [devenv.lan] — фильтрованный доступ в LAN для podman-контейнера: interface (LAN-интерфейс хоста, до которого контейнеру разрешено достучаться) и allow (массив IP-адресов/CIDR, маршрутизируемых в этот интерфейс; всё остальное идёт по маршруту по умолчанию и в LAN не попадает). Голый адрес означает хост-маршрут /32; имена хостов не принимаются — DNS по-прежнему уходит в туннель, это осознанное решение. Требует заданный outbound_interface, отличный от interface. Записи, пересекающиеся с link-local (169.254.0.0/16, fe80::/10), накрывающие маршрут по умолчанию или совпадающие с собственным адресом хоста, отклоняются. Список allow управляет только соединениями, которые контейнер устанавливает сам: TCP-клиент из разрешённой подсети по-прежнему достучится до опубликованных портов контейнера — ответы уходят с собственного адреса контейнера и идут обычным путём (случаи UDP и привязанного сокета описаны в ограничениях). Правка allow не пересоздаёт контейнер — маршруты подгоняются в работающем контейнере при следующем zoryn devenv; актуальные маршруты показывает zoryn devenv inspect. Только машинная конфигурация — из .gear/devenv не читается никогда, так что пакет не может открыть дыру в вашу LAN. Как и каждый ключ профиля, при активном профиле читается собственная секция [devenv.profiles.<имя>.lan]; базовая таблица не наследуется.

    Ограничения, заложенные намеренно:

    • Сборка образа идёт в собственном пространстве имён на каждый шаг, поэтому LAN-зеркало apt на этапе сборки недоступно.
    • Фильтрация по адресу назначения: все порты разрешённого адреса доступны.
    • Никакого разрешения имён через LAN-путь — DNS уходит в туннель.
    • Один хостовой интерфейс.

Начиная с zoryn 0.49.0 (после перехода на парсер otoml) обе субтаблицы можно записывать и inline-таблицами TOML: features = { vim = {}, claude = {} } и lan = { interface = "eth0", allow = ["192.168.50.0/24"] } равнозначны записи через заголовки секций. Такие inline-ключи ставьте внутри блока [devenv] до первого заголовка [devenv.*] — в TOML голая строка ключ = значение относится к ближайшему заголовку секции над ней.

Профиль — именованная, полностью независимая конфигурация [devenv], задаётся как [devenv.profiles.<имя>]. Когда он активен, каждый ключ [devenv] читается только из профиля; базовая секция [devenv] не наследуется и не объединяется с ним (база применяется только когда профиль не активен). Собственные BuildRequires пакета и пакеты из .gear/devenv устанавливаются всегда, независимо от профиля. Выбирается через zoryn devenv --profile <имя>. См. zoryn devenv.

[devenv]
backend = "bwrap"
packages = ["gdb", "vim", "strace"]
# image = "registry.example.com/alt/sisyphus"
# mounts = ["/srv/sources:/srv/sources:ro"]
# prompt = "\\[\\e[32m\\]\\u@\\h\\[\\e[0m\\]:\\w\\$ "
# outbound_interface = "eth1"
# timezone = "Asia/Almaty"
# dns = ["8.8.8.8"]
# dns_search = ["corp.example.com"]
# ports = ["18080:8080", "eth0:8080"]
# env = ["GOFLAGS=-mod=vendor"]
# default_profile = "sisyphus"

# [devenv.lan]
# interface = "eth0"
# allow = ["192.168.50.10", "192.168.50.0/24"]

# [devenv.profiles.p11]
# branch = "p11"

Полный порядок разрешения зависимостей и переопределения для конкретных проектов описаны в zoryn devenv.

[flows] и [flows.<имя>] — сценарии для zoryn flow

  • [flows] default — имя сценария, который выполнит zoryn flow, если он не выбран ни аргументом NAME, ни ключом [flow] name из .gear/version-up.
  • [flows.<имя>] steps — массив inline-таблиц, по одной на шаг; шаги выполняются по порядку. У каждого есть ключ run (up, build, submit, batch, bash, ssh, devenv, zoryn, agent) и собственные ключи этого типа, а также необязательные name, if, on-failure и max-retries. Шаги up, build и submit принимают типизированные ключи-опции (например, commit, builder, skip-check), которые ложатся на флаги команды; незаданный ключ означает конфиг-зависимое умолчание голой команды, и каждый ключ доступен ещё и как флаг у zoryn flow <ИМЯ>. См. zoryn flow › Опции шага.

Только машинная конфигурация: читается из ~/.zoryn и ~/.config/zoryn/projects.d/<проект>.toml (файл проекта приоритетнее для одноимённого сценария) и никогда из репозитория пакета — в шаге лежат shell-команды и ssh-хосты, поэтому склонированный репозиторий не должен уметь его задать. Репозиторию доступен только выбор сценария по имени — через [flow] в .gear/version-up.

[flows]
default = "update"

[flows.update]
steps = [
  { run = "up", on-failure = "fix-build", max-retries = 3 },
  { run = "devenv", cmd = "make smoke" },
  { run = "submit", branch = "sisyphus", task-run = true },
]

[flows.fix-build]
steps = [ { run = "agent" } ]

Все типы шагов, подставляемые переменные ({pkg}, {old_version}, {new_version}, {tasks}, {task}) и правила повторов описаны в zoryn flow.

[agent]

  • cli — ИИ-CLI, который использует шаг agent в сценарии (по умолчанию claude). Значение служит одновременно фичей devenv, включаемой для шага, и командой, запускаемой внутри окружения. Шаг agent знает неинтерактивную форму для claude, codex и opencode; при другом значении шаг падает.
  • flow_steps — задайте true, чтобы разрешить выполнение шагов agent (по умолчанию false). По умолчанию они выключены, потому что агент работает в devenv, где ваши реальные ~/.claude (и аналоги) смонтированы на запись для аутентификации, так что указание «правь только репозиторий» песочницей не навязывается; включайте только для сценариев и репозиториев, которым доверяете. См. zoryn flow › Починка ИИ-агентом.

~/.config/zoryn/builders.d/

Каждый .conf файл определяет один билдер — локальную или удалённую hasher-машину.

# ~/.config/zoryn/builders.d/arm-server.conf
[builder]
name = "arm-server"
type = "remote"
arch = "aarch64"
branch = "sisyphus"
host = "builder-arm.internal"
hasher_dir = "~/hasher"
remote_dir = "~/build"
# hasher_number = 1  # для параллельных сборок (требует hasher-useradd --number=N)

[commands]
upload = "rsync -av {tarball} {host}:{remote_dir}/"
build = "hsh -v --lazy-cleanup --apt-config=$HOME/hasher_{hasher_number}.env/{branch}/apt.conf {hasher_dir} {remote_dir}/{tarball_name}"
# download использует умную загрузку по умолчанию (только новые пакеты)
cleanup = "ssh {host} \"rm -rf {remote_dir}/*\""
shell = "hsh-shell {hasher_dir}"
install = "hsh-install {hasher_dir} {packages}"

[builder]

  • name — имя билдера (используется в --builder).
  • typelocal или remote.
  • arch — целевая архитектура (x86_64, aarch64, i586, …).
  • branch — целевая ветка (sisyphus, p11, …).
  • host — SSH-хост для remote.
  • hasher_dir — рабочий каталог hasher (по умолчанию: ~/hasher).
  • remote_dir — рабочий каталог на удалённом хосте.
  • hasher_number — номер субконфига hasher для параллельных сборок.
  • repo_workdir — корневой каталог, в котором zoryn task mkrepo собирает репозитории задач (<repo_workdir>/<task_id>/repo). Переопределяет глобальный [builders] repo_workdir.

[commands]

  • upload — загрузка тарболла (выполняется локально).
  • build — команда сборки (оборачивается в SSH для remote builders). Ключ необязательный: если его не задать, zoryn возьмёт ровно ту команду, которую для этого билдера написал бы zoryn builder addhsh … --lazy-cleanup --apt-config=<путь>, где путь равен {apt_tmpdir}/apt.conf при заданном repo и $HOME/hasher_{hasher_number}.env/{branch}/apt.conf в остальных случаях. Второй файл создаёт сам builder add; конфигу в builders.d, написанному руками, он должен быть подготовлен заранее — либо здесь задаётся явный build. Как только в команде встречается {apt_tmpdir}, zoryn перед каждой сборкой раскладывает собственный apt-конфиг билдера во временный каталог: на удалённом билдере это один mktemp и один rsync на сборку. Какая команда выполнится на самом деле — с ключом или без — показывает zoryn builder config.
  • download — скачивание результатов (выполняется локально). По умолчанию — умная загрузка: только новые пакеты через rsync --files-from. Старые конфиги с полным скачиванием автоматически мигрируются.
  • list_rpms — список RPM с mtime в репозитории hasher (по умолчанию: find {hasher_dir}/repo -name '*.rpm' -printf '%P\t%T@\n'). Используется умной загрузкой.
  • cleanup — очистка после сборки.
  • shell — для zoryn builder shell.
  • install — для zoryn builder install.
  • check_busy, download_rpms, upload_rpms — генерируются автоматически, если не указаны.

Чтобы настроить --mountpoint=... — например, убрать /dev/kvm на общих хостах без виртуализации — переопределите build и rebuild здесь. zoryn валидирует mountpoints по эффективной команде, а не по дефолту. См. Билдер без /dev/kvm.

Переменные в шаблонах:

{host}, {hasher_dir}, {remote_dir}, {tarball}, {tarball_name}, {results_download_dir}, {git_root}, {packages}, {batch_repo}, {arch}, {name}, {hasher_number}, {branch}.

См. zoryn builder add для интерактивного и массового создания.

[build]

  • timeout — сколько минут zoryn ждёт освобождения билдера перед тем как сдаться.
  • inactivity_timeout — сколько минут активная сборка может не писать в лог прежде чем быть убитой как зависшая (по умолчанию: 60). Значение 0 отключает проверку. Отсчёт начинается только после первой записи в лог, поэтому долгая тихая фаза подготовки (например, настройка chroot) не воспринимается как зависание — как следствие, сборка, зависшая до первой записи в лог, этой проверкой не ловится. На медленных билдерах, где одна огромная единица трансляции или LTO-линковка легитимно молчит дольше часа, поднимите значение (или поставьте 0).
  • max_log_mb — максимальный размер лога сборки в МиБ, при превышении которого сборка убивается как зависшая (по умолчанию: 1024). Значение 0 отключает проверку. Ловит сборки, застрявшие в бесконечном выводе, где лог продолжает расти, но реальной работы не происходит.

Все три ключа [build] можно также задать один раз в глобальном ~/.zoryn, секция [build]; значение в собственном builders.d/*.conf билдера всегда имеет приоритет над глобальным.

Только параллельная сборка

Stall watchdog (inactivity_timeout / max_log_mb) работает только в параллельном диспетчере — то есть при сборке на 2+ билдерах без --sequential, либо в интерактивном TUI --top (он всегда использует диспетчер). Запуск с одним билдером без --top и с --sequential выполняет каждую сборку в том же процессе без мониторинга, поэтому эти ключи там не действуют (zoryn печатает предупреждение, если они заданы, а запуск последовательный).

Удалённые билдеры: только локальный слот

На удалённом билдере kill завершает локальный процесс ssh, но сигнал не пересекает границу SSH, поэтому зависший удалённый hsh напрямую не убивается — он продолжает удерживать hasher-workdir билдера, пока не завершится сам. Watchdog сразу освобождает локальный слот, так что следующая задача может быть отправлена на тот же удалённый билдер. Lock workdir'а у hasher не даёт им испортить данные друг друга, но новая сборка тогда блокируется на этом локе, не выдавая вывода в лог, а inactivity-watchdog не запускает отсчёт, пока лог пуст — поэтому билдер может «зависнуть» до завершения orphan'а (а при мёртвом orphan'е — до конца всего прогона). На локальных билдерах завершается вся process-group сборки.

Убитые сборки оставляют состояние hasher

Kill от watchdog (или Ctrl+C) шлёт SIGTERM, ждёт короткую паузу, затем SIGKILL. Сборка, убитая SIGKILL, не успевает выполнить cleanup hasher'а, поэтому bind-mount'ы и грязный workdir могут остаться на билдере и накапливаться за прогон. Если билдер начинает падать после серии зависаний — очистите его hasher-workdir (например, hsh --initroot / размонтируйте остатки) перед переиспользованием.

.gear/version-up

Переопределения для пакета: как конвертировать upstream-тэги в RPM-версии, откуда брать CVE, подсказки для merge. TOML.

[version]
pattern = "{major:+}.{minor:+}.{patch:+}"
template = "{major}.{minor}.{patch}"
strip-prefix = "v"
create-alias = true
filter = "minor=4"

[changelog]
file = "CHANGELOG.md"
# или удалённый URL:
# url = "https://curl.se/docs/vuln.json"
# parser = "osv-json"
# cve-format = "extended"
# или OSV API для проектов без changelog-файлов (например, Wireshark):
# parser = "osv-api"
# osv-package = "gitlab.com/wireshark/wireshark"
# osv-ecosystem = "GIT"

[merge]
use-theirs = ["meson.build", "configure.ac"]
# scheme = "git-merge"  # переопределить авто-детекцию: "git-merge" или "tarball"

[tarball]
gear-update-opts = "--all"

Для HTML release notes (пример Wireshark):

[changelog]
parser            = "web_regex"
url               = "https://www.wireshark.org/docs/relnotes/wireshark-{new_version}.html"
web-regex-pattern = 'wnpa-sec-\S+\s+(?<desc>(?:[^.]|\.\d)+?)\.\s+Issue\s+\d+(?:\s*,\s*Issue\s+\d+)*\s*\.\s+(?<id>CVE-\d{4}-\d+)'
web-regex-stop-at = "Prior Versions"

Проверить конфиг — zoryn check version-up.

[version] — маппинг тэг → RPM-версия

Пара pattern/template используется везде, где upstream-теги превращаются в версии: zoryn up (и поиск тегов в git-merge, и git-tags фолбэк tarball-схемы без watch-файла) и zoryn check version. Без паттерна эвристика «последнего тега» может выбрать мусорный нерелизный тег (например, у llama.cpp 9794052 оказывался «новее» b10103). На путях с удалёнными тегами паттерн, не подошедший ни одному тегу, считается ошибкой конфига (код выхода 1 / прерванное обновление), а не молчаливым «уже актуально»; в git-merge схеме опечатка в паттерне остаётся нефатальной.

Формат плейсхолдера: {name:length}

  • name — имя группы захвата (major, minor, patch, year, month, day).
  • length — спецификатор количества цифр:
    • + или * — одна или более цифр (regex [0-9]+).
    • N (число) — ровно N цифр (regex [0-9]{N}).
    • x — одна или более шестнадцатеричных цифр (regex [0-9a-fA-F]+) — для суффиксов-хэшей в стиле git describe (например, теги passt 2026_07_28.f8df3f1).

Литеральные символы: . — точка, -, _ — дефис/подчёркивание; остальные символы попадают в регулярное выражение как есть, поэтому метасимволы сохраняют своё regex-значение. (?:…)? задаёт необязательную часть, а перечисление вида (mysql|redis)-{major:+}.{minor:+} работает как написано: группу, которую вы пишете сами, zoryn делает незахватывающей, поэтому она не сбивает нумерацию плейсхолдеров. (?:…) — единственная поддерживаемая конструкция вида (?…): именованные группы, lookaround и инлайновые флаги отвергаются с сообщением unsupported group in [version] pattern, незакрытая скобка — с invalid [version] pattern.

Пререлизы: теги с пометкой пререлиза (alpha, beta, rc, pre, dev, snapshot, nightly, -alt) пропускаются: шаблон обычно отбрасывает пререлизный сегмент, поэтому выбор 2.0.0-rc1 объявил бы версию 2.0.0, которой upstream не выпускал. Пометка ищется только в той части тега, которую захватывает паттерн, а не во всём теге, поэтому пакеты, в имени которых она встречается (orc, mercurial, libevdev), не страдают. Если под паттерн подходят только пререлизы, кандидат не выбирается и вызывающая команда сообщает об этом как об обычном состоянии. Это касается только случая с заданным паттерном: без [version] общая эвристика лишь предпочитает стабильные теги и всё-таки возьмёт пререлизный, если ничего другого upstream не выпускал.

Поле template: имена групп без спецификатора длины — {major}, {minor}, … У группы может быть значение по умолчанию: {patch:0} подставляет захваченное значение либо 0, если группа в тэге отсутствовала.

Примеры pattern

Upstream-тэгpatterntemplateRPM-версия
v1.2.3v{major:+}.{minor:+}.{patch:+}{major}.{minor}.{patch}1.2.3
release-1.2release-{major:+}.{minor:+}{major}.{minor}1.2
20240115{year:4}{month:2}{day:2}{year}.{month}.{day}2024.01.15
2.0.0-rc1{major:+}.{minor:+}.{patch:+}-rc{pre:+}{major}.{minor}.{patch}2.0.0
camlidl113camlidl{major:1}{minor:2}{major}.{minor}1.13
RELEASE_8_4_5RELEASE_{major:+}_{minor:+}_{patch:+}{major}.{minor}.{patch}8.4.5
4.18 / 4.18_02{major:+}.{minor:+}(?:_{patch:+})?{major}.{minor}(?:.{patch})?4.18 / 4.18.02
v5.8-505 / v5.8.1-506v{major:+}.{minor:+}(?:.{patch:+})?-{build:+}v{major}.{minor}.{patch:0}.{build}5.8.0.505 / 5.8.1.506
2026_07_28.f8df3f1{major:+}_{minor:+}_{patch:+}.{build:x}{major}.{minor}.{patch}2026.07.28

Опциональные группы — через стандартный regex (?:...)?. Если опциональная часть отсутствует в тэге, соответствующий сегмент template пропускается. Значение по умолчанию {name:default} действует только для плейсхолдеров вне опциональной секции — внутри (?:...)? вся секция отбрасывается при отсутствии группы, и значение по умолчанию не срабатывает.

Когда апстрим иногда выкидывает компонент (например v5.8-505 без patch, а затем v5.8.1-506 с ним), простой пропуск сегмента даёт более короткую версию, где следующий компонент попадает не в свой разряд: 5.8.505 тогда отсортируется выше 5.8.1.506 и заблокирует обновление. Сделайте компонент опциональным в pattern, но задайте значение по умолчанию в template ({patch:0}) — раскладка разрядов фиксируется, а версии остаются монотонными: 5.8.0.505 < 5.8.1.506.

Фильтрация тэгов

filter ограничивает, какие тэги рассматриваются. filter = "minor=4" — только тэги с minor == 4. Несколько фильтров: filter = "major=8, minor=4".

Ограничение кандидатов веткой апстрима

upstream-branch = "stable/linux-6.18.y" ограничивает кандидатов на обновление тегами, достижимыми из этой ветки; имя сопоставляется с настроенными remote (сначала upstream). Это тот же механизм, что и файл .gear/upstream-branch из соглашения kernel-team, и ключ имеет приоритет над файлом — полная семантика описана в разделе про репозитории ядра.

[changelog] — источник CVE

Распознаются форматы CVE-YYYY-NNNNN и CVE:YYYY-NNNNN (ISC), оба нормализуются в CVE-YYYY-NNNNN. Поддерживаются заголовки Product X.Y.Z (status) released on Date (ISC Kea/BIND).

  • file — локальный changelog (CHANGELOG.md, NEWS, ChangeLog).
  • url — URL с security advisory (например, https://curl.se/docs/vuln.json).
  • parser — тип парсера:
    • auto (по умолчанию) — автоопределение.
    • osv-json / json — OSV JSON (curl и др.).
    • markdown / md — стандартный markdown changelog.
    • html / html-table — HTML-таблица с CVE.
    • osv-api — запрос OSV API напрямую (требует osv-package).
    • oracle-csaf — Oracle CSAF JSON (для продуктов Oracle, например MySQL).
    • mozilla — advisory безопасности Mozilla, собираемые с сайта security-advisories mozilla.org. Для firefox, firefox-esr, thunderbird.
    • web_regex — универсальный HTML-парсер на PCRE-регулярке с именованными группами (?<id>...) и (?<desc>...). Для апстримов, публикующих CVE в HTML release notes (например Wireshark) и отсутствующих в OSV. Требует web-regex-pattern; поддерживает необязательный маркер web-regex-stop-at.
  • osv-package — имя пакета(ов) в OSV. Принимает одно имя, список через запятую или TOML-массив.
  • osv-ecosystem — экосистема OSV (по умолчанию: GIT; также PyPI, npm, crates.io, Go, Maven).
  • oracle-advisory-product — имя продукта Oracle для фильтрации (например, MySQL Server). Автоопределение по имени SRPM, если не указано.
  • oracle-advisory-max-body-size — макс. размер ответа при скачивании CSAF в байтах (по умолчанию: ~4 МБ).
  • mozilla-product — имя продукта Mozilla для сопоставления с записями <product> <version> в индексе advisory (например, Firefox, Firefox ESR, Thunderbird). Если не указано, определяется по имени SRPM: firefoxFirefox, firefox-esrFirefox ESR, thunderbirdThunderbird.
  • web-regex-pattern — PCRE для parser = web_regex. Должна содержать именованные группы (?<id>CVE-...) и (?<desc>...). Матчи, в которых id не является валидным CVE, молча отбрасываются. Проверяется командой zoryn check version-up ещё до HTTP-запроса.
  • web-regex-stop-at — регистрозависимая подстрока для parser = web_regex. Контент начиная с первого вхождения и до конца документа игнорируется. Полезно, чтобы пропустить секцию «Prior Versions» / описание предыдущих релизов на кумулятивных HTML-страницах. Если маркер не найден, парсер обрабатывает весь документ и выдаёт предупреждение. Пустое значение отвергается.
  • cve_format — формат записей CVE в changelog пакета:
    • compact (по умолчанию) — в одну строку: (Fixes: CVE-..., CVE-...).
    • compact_continuation — строки продолжения, 4 CVE на строку: + (fixes: CVE-..., …).
    • extended — многострочный с описаниями из OSV: - Fixes: / * CVE-...: описание.
    • При compact и наличии spec формат определяется автоматически по стилю существующего changelog.

url имеет приоритет над file при обоих указанных. Для parser = osv-api и url, и file игнорируются. Для parser = oracle-csaf url необязателен — URL последнего квартального CPU генерируется автоматически, а если advisory за этот квартал ещё не опубликован, загрузчик откатывается к более старым кварталам (в пределах года), пока не найдёт существующий. Для parser = mozilla url и file игнорируются — advisory собираются с сайта security-advisories mozilla.org: страница-индекс сопоставляет <mozilla-product> <new-version> со слагом advisory (MFSA), после чего эта страница advisory разбирается для получения её идентификаторов CVE. Для parser = web_regex обязательны и url, и web-regex-pattern; URL поддерживает плейсхолдеры {old_version} и {new_version} (та же подстановка применяется к URL парсеров markdown/osv-json/html-table), а страница перед поиском проходит через HTML-strip (вырезаются тела <script>/<style>, удаляются теги, декодируются комментарии и сущности, сжимаются пробелы). Описания CVE экранируются от RPM-макросов (%%%) перед записью в %changelog — апстрим-проза с литеральным % безопасна.

Как найти osv-package

  1. Откройте osv.dev и найдите проект по имени (wireshark, curl).
  2. Откройте любую уязвимость этого проекта.
  3. В секции Affected packages указано имя пакета (например, gitlab.com/wireshark/wireshark для экосистемы GIT).
  4. Скопируйте имя пакета и экосистему в конфиг.

Или запросите API напрямую:

curl -s -X POST https://api.osv.dev/v1/query \
  -d '{"package":{"name":"gitlab.com/wireshark/wireshark","ecosystem":"GIT"},"version":"4.4.3"}' \
  | python3 -m json.tool | head -20
ЭкосистемаФормат имениПример
GIT (default)Путь из URL репоgitlab.com/wireshark/wireshark
PyPIИмя в PyPIrequests
npmИмя в npmexpress
crates.ioИмя крейтаtokio
GoПуть модуля Gogolang.org/x/net
Mavenгруппа:артефактorg.apache.logging.log4j:log4j-core

Полный список: https://ossf.github.io/osv-schema/#affectedpackage-field

[merge]

  • scheme — переопределить авто-детекцию схемы: "git-merge" или "tarball". Устанавливается автоматически флагом --switch-to-upstream-git.
  • use-theirs — файлы, которые при конфликте берутся из upstream (через запятую или пробел). Полезно для файлов с версиями: meson.build, configure.ac.

[tarball]

  • gear-update-opts — доп. опции для gear-update (например, --all для извлечения всех директорий из архива).
  • subdir — имя поддиректории внутри тарбола для извлечения (передаётся как gear-update --subdir=<value>). Поддерживает плейсхолдеры {version} и {name}, например subdir = "thunderbird-{version}". Полезно для тарболов с несколькими записями на верхнем уровне, такими как ./ и <name>-<version>/ (исходники Mozilla). Перед использованием проверяется на shell-метасимволы и разделители пути.

[add_changelog] — переопределение для пакета

  • up_template — шаблон записи changelog для zoryn up. Поддерживает {old_version}, {new_version}, {cves}. Например: up_template = "- {old_version} -> {new_version} {cves}".

[sandbox] — пакеты для песочницы хуков

Попакетные настройки гибридной песочницы, в которой выполняются хуки .gear/up.d/ и .gear/merge-up.d/. Эта секция читается только из .gear/version-up, но не из ~/.zoryn.

  • packages — дополнительные пакеты для установки в chroot (сверх BuildRequires: из spec). git ставится всегда.
  • specbr — булево, по умолчанию true. При false BuildRequires: пакета пропускаются: chroot инициализируется «голым» (hsh --initroot-only, без сборки src.rpm); заданные пакеты (git, [sandbox.chroot] packages из ~/.zoryn и packages отсюда) всё равно ставятся. При specbr = false пользовательская команда [sandbox.chroot] prepare из ~/.zoryn игнорируется (выводится предупреждение).
[sandbox]
specbr = false
packages = ["go", "make", "curl"]

[specsubst] — значения specsubst для submit

Один ключ на каждую specsubst-переменную. Сейчас читается kflavour для репозиториев kernel-image (через запятую для нескольких тэгов). Имеет приоритет над префиксом ветки <flavour>/<dist>; -k в командной строке важнее обоих.

[specsubst]
kflavour = "for-vm"

[flow] — какой сценарий выполнять

  • name — сценарий, который zoryn flow выполнит в этом пакете, если аргумент NAME не задан. Это только выбор: сам сценарий должен быть описан в вашей машинной конфигурации ([flows.<имя>] в ~/.zoryn или ~/.config/zoryn/projects.d/<проект>.toml), а неизвестное имя просто обрывает запуск ошибкой. Репозиторий пакета таким образом не может добавить ни одного шага — только выбрать среди ваших.
[flow]
name = "kernel-update"

Версии по дате — пример

[version]
pattern = "{year:4}{month:2}{day:2}"
template = "{year}.{month}.{day}"

.gear/release-targets и .gear/upstream-branch — репозитории ядра

Gear-репозитории ядра (соглашение ALT kernel-team) содержат два дополнительных файла, ограничивающих выбор тегов апстрима при автоматическом поиске новой версии в zoryn up. zoryn читает их, только если они есть; на остальные пакеты это никак не влияет.

.gear/release-targets — по строке на ветку ALT, <ветка> <flavour>...:

sisyphus 6.18
p11 6.18

Вторая и последующие колонки — flavour ядра (std-def, un-def, 6.18 — в современных репозиториях kernel-image-<серия> flavour просто совпадает с серией). Ветку ALT zoryn определяет по имени текущей git-ветки (<flavour>/<dist>, например 6.18/sisyphus, или просто p11; master считается sisyphus) и сверяет с файлом: если текущей ветки там нет, zoryn up останавливается с ошибкой — на этой ветке пакет обновлять не предполагается. Пустые строки и комментарии # игнорируются.

.gear/upstream-branch — ветка апстрима, из которой берутся теги, например:

stable/linux-6.18.y

Именем ветки считается первое слово первой строки, не являющейся комментарием (дальше может идти информационный URL репозитория; пустые строки и комментарии # пропускаются). Кандидатами на обновление становятся только теги, достижимые из этой ветки, — именно это и закрепляет серию: на stable/linux-6.18.y самый новый достижимый тег — последний v6.18.x, а более новые теги из master никогда не будут выбраны. Значение может содержать префикс remote (стиль kernel-team, stable/linux-6.18.y) или быть просто именем ветки (linux-6.18.y); zoryn сопоставляет его с настроенными remote (сначала upstream), а если ничего не находит — останавливается с ошибкой: молча рассматривать все теги значило бы отменить закрепление серии (исправьте имя ветки или обойдите через --tag). То же ограничение задаёт ключ upstream-branch в .gear/version-up; ключ имеет приоритет над файлом.

Ограничение касается только кандидатов на обновление; распознавание текущей версии продолжает работать при миграции между сериями (в спеке 6.17.x, цель — 6.18). Явный zoryn up --tag TAG обходит и это ограничение, и проверку ветки по release-targets.

Фильтрация по форме тега — отсев pre-release вида -rcN или требование vX.Y.Z — не задача этого механизма: этим занимается паттерн [version] в .gear/version-up, а его правило pre-release само отбрасывает rc-теги.

Вместе с ограничением действуют ещё две меры предосторожности:

  • Страж свежих тегов. Пока действует ограничение по ветке апстрима, тег моложе часа пропускается (зеркалам апстрима нужно время), и обновление откладывается целиком — более старый кандидат вместо него не берётся. --force берёт свежий тег сразу.
  • База релиза по ветке. В репозиториях с файлами kernel-team сброс Release: после поднятия версии следует традиции ALT: alt2 на сертификационных ветках c10f2/c9f2, alt1 на остальных.

Проверка

zoryn проверяет конфигурационные файлы при чтении и печатает предупреждение для каждой неизвестной секции или ключа — например unknown key 'pacakges' in [sandbox.hasher]. Предупреждения не прерывают работу; остальная часть конфигурации применяется. Это ловит опечатки вроде ключа packages в [sandbox.hasher] вместо [sandbox.chroot].

Связанное

  • Хуки.gear/merge-up.d/, .gear/up.d/, подсветка синтаксиса, темы логов
  • Песочницаhybrid / bwrap / direct режимы для изоляции хуков