Конфигурация¶
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 работает даже с такой конфигурацией:
У всех остальных секций есть разумные значения по умолчанию. Переопределяйте только то, что действительно отличается.
Полный пример¶
[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. Если ключ не задан, логин выводится из gituser.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 по умолчанию):
[ssh]¶
multiplexing— включить мультиплексирование SSH через OpenSSH ControlMaster (по умолчанию:true). Повторно использует TCP-соединения, снижая задержки при многошаговых операциях сборки.persist— время жизни master-соединения (по умолчанию:10m). Формат — как ControlPersist вssh_config(5).alive_interval—ServerAliveIntervalдля мультиплексированного соединения, в секундах (по умолчанию:15).alive_count_max—ServerAliveCountMaxдля мультиплексированного соединения (по умолчанию: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, где контейнера нет, — hostnamedevenv-<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— строка bashPS1, встраиваемая в~/.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).type—localили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 add—hsh … --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 (например, теги passt2026_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-тэг | pattern | template | RPM-версия |
|---|---|---|---|
v1.2.3 | v{major:+}.{minor:+}.{patch:+} | {major}.{minor}.{patch} | 1.2.3 |
release-1.2 | release-{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 |
camlidl113 | camlidl{major:1}{minor:2} | {major}.{minor} | 1.13 |
RELEASE_8_4_5 | RELEASE_{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-506 | v{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:firefox→Firefox,firefox-esr→Firefox ESR,thunderbird→Thunderbird.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¶
- Откройте osv.dev и найдите проект по имени (
wireshark,curl). - Откройте любую уязвимость этого проекта.
- В секции Affected packages указано имя пакета (например,
gitlab.com/wireshark/wiresharkдля экосистемыGIT). - Скопируйте имя пакета и экосистему в конфиг.
Или запросите 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 | Имя в PyPI | requests |
npm | Имя в npm | express |
crates.io | Имя крейта | tokio |
Go | Путь модуля Go | golang.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. ПриfalseBuildRequires:пакета пропускаются: chroot инициализируется «голым» (hsh --initroot-only, без сборки src.rpm); заданные пакеты (git,[sandbox.chroot] packagesиз~/.zorynиpackagesотсюда) всё равно ставятся. Приspecbr = falseпользовательская команда[sandbox.chroot] prepareиз~/.zorynигнорируется (выводится предупреждение).
[specsubst] — значения specsubst для submit¶
Один ключ на каждую specsubst-переменную. Сейчас читается kflavour для репозиториев kernel-image (через запятую для нескольких тэгов). Имеет приоритет над префиксом ветки <flavour>/<dist>; -k в командной строке важнее обоих.
[flow] — какой сценарий выполнять¶
name— сценарий, которыйzoryn flowвыполнит в этом пакете, если аргументNAMEне задан. Это только выбор: сам сценарий должен быть описан в вашей машинной конфигурации ([flows.<имя>]в~/.zorynили~/.config/zoryn/projects.d/<проект>.toml), а неизвестное имя просто обрывает запуск ошибкой. Репозиторий пакета таким образом не может добавить ни одного шага — только выбрать среди ваших.
Версии по дате — пример¶
.gear/release-targets и .gear/upstream-branch — репозитории ядра¶
Gear-репозитории ядра (соглашение ALT kernel-team) содержат два дополнительных файла, ограничивающих выбор тегов апстрима при автоматическом поиске новой версии в zoryn up. zoryn читает их, только если они есть; на остальные пакеты это никак не влияет.
.gear/release-targets — по строке на ветку ALT, <ветка> <flavour>...:
Вторая и последующие колонки — 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 — ветка апстрима, из которой берутся теги, например:
Именем ветки считается первое слово первой строки, не являющейся комментарием (дальше может идти информационный 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].