ЗОРЯ

Головна/Завдання/Частина 4/Стек і збірка

Стек і збірка: що ми збираємо з вашого коміту

оновлено 07.10

1Розкладка репозиторію

схема
<ваш репозиторій>
  .zoria                 логін у мережі (частина 1, P1-05)
  README.md              команди встановлення, збирання і запуску
  compose.yaml           стек здачі
  .npmrc                 реєстр конкурсу і посилання на ZORIA_NPM_AUTH, без секрету
  bot/                   каталог бота з частини 2
    package.json         поле zaria.bot: команда запуску
    nakaz.yaml           ваша грамота
    Dockerfile           образ голови
    src/ ...
  control-plane/         службові ручки (04-service.md)
  hq/                    каталог штабу з частини 3
    package.json         поле zaria.hq: каталог збірки
    Dockerfile           образ штабу
  DECISIONS.md           розбір рішення, до фінальної здачі (scoring.md, 10.1)

Імена bot і hq - із шаблонів zaria-kit; свої імена припустимі, поки каталог бота знаходиться за полем zaria.bot, а каталог штабу - за zaria.hq, і таких каталогів по одному. Клієнт мережі з частини 1 живе там само, де жив.

npx zaria-kit init stack дописує compose.yaml і сервіси навколо того, що у вас уже є, і нічого не перезаписує: каталог бота він знаходить полем zaria.bot, каталог штабу - полем zaria.hq. Каталогу бота немає - кладе і шаблон частини 2. Свій README.md він не чіпає: наступні кроки тоді лягають поруч файлом STACK.md. Переписати СВОЇ файли стека поверх колишніх - --force; ваш код не чіпається і ним.

2Стек: ролі й мітки

2.1

Стек - один файл compose.yaml у корені репозиторію. Сервісів може бути скільки завгодно; конвеєру треба знати три ролі і шлях щоденника віри, і він читає їх мітками:

МіткаНа чому стоїтьЩо означає
zaria.role: headрівно один сервісголова на проводі: їй вузол кладе ZARIA_URL і ZARIA_TOKEN
zaria.control: <порт>не більше одногослужбові ручки (04-service.md); без мітки - голова, порт 7801
zaria.hq: <порт>не більше одногоштаб: віддає зібрану сторінку; без мітки - сервіс з іменем hq, порт 8080
zaria.belief: <шлях>на головіабсолютний шлях щоденника віри всередині контейнера

Сервіс без мітки zaria.role, названий head, теж вважається головою: шаблон працює і без міток.

2.2

Приклад мінімального стека:

YAML
services:
  head:
    build: { context: ., dockerfile: bot/Dockerfile }
    labels:
      zaria.role: head
      zaria.control: '7801'
      zaria.belief: /data/belief.ndjson
    environment:
      ZARIA_URL: ${ZARIA_URL:-}
      ZARIA_TOKEN: ${ZARIA_TOKEN:-}
      ZARIA_BELIEF: /data/belief.ndjson
    volumes: [ diaries:/data ]
  hq:
    build: { context: ., dockerfile: hq/Dockerfile }
    labels: { zaria.hq: '8080' }
volumes:
  diaries: {}
2.3

Щоденник віри обов'язковий (P2-05): за ним працює Ш1 вашого штабу, і його ми знімаємо з машини перед відкатом. Шлях оголошується міткою zaria.belief, а голові передається своєю змінною.

3Правила машини

Машина учасника - не ваш ноутбук: на ній поруч живуть чужі контейнери і наш шлюз. Тому стек перевіряється правилами; порушення - провал ступеня stack з переліком усіх знайдених місць одразу.

3.1

Заборонено в сервісі: privileged, cap_add, devices, device_cgroup_rules, volumes_from, external_links, gpus, cgroup_parent, runtime, credential_spec, isolation.

3.2

Заборонені чужі простори імен і мережі: network_mode крім none і service:<ім'я>, pid, ipc, uts, userns_mode, cgroup зі значенням host або container:<ім'я>.

3.3

security_opt - тільки no-new-privileges.

3.4

Томи - тільки іменовані (type: volume) і tmpfs. Bind-том з хоста заборонено: хост не ваш.

3.5

Мережі і томи верхнього рівня - без external, без свого name, без driver_opts і свого ipam; драйвери - bridge для мереж і local для томів. Розділи secrets і configs верхнього рівня заборонено: файли запікаються в образ.

3.6

Збірка: контекст і Dockerfile - усередині репозиторію (симлінк назовні вважається виходом назовні), без ssh, secrets, additional_contexts, entitlements, без privileged і без network: host.

3.7

env_file - тільки з репозиторію.

3.8

include і extends заборонено: стек описується одним файлом. Вони тягнуть чужі файли під час читання, і після нормалізації їх уже не видно, а замок публікується поруч із вердиктом.

3.9

Імена образів ставить конвеєр. image: поруч із build: ми перевизначаємо, щоб ваш тег не перетер чужий образ на спільному хості.

Мережа машини під час прогону і партії закрита: бачити можна лише шлюз і сервіси власного стека (доповнення 15).

4Збірка

4.1

Збірка йде в пісочниці на нашому боці, з дерева зафіксованого коміту: docker compose config нормалізує файл, далі збираються всі сервіси, у яких є build.

4.2

Мережа збірки - тільки реєстр конкурсу https://npm.zoria.net/. Він же проксує публічний npm, тому звичайні залежності ставляться як завжди; прямих виходів в інтернет у збірки немає. Секрет реєстру кладемо ми: у .npmrc вашого репозиторію лежить посилання на змінну ZORIA_NPM_AUTH, а не сам секрет (частина 2, P2-07).

4.3

Ліміти: 20 хвилин на всю збірку стека, 200 МіБ на дзеркало репозиторію, образи - у межах диска машини учасника. Збірка, що не вклалася в ліміт, - провал ступеня build; дзеркало більше за 200 МіБ - провал ступеня repo.

4.4

Lockfile обов'язковий: npm ci без package-lock.json не працює, а збірка без lockfile невідтворювана. Те саме для штабу.

4.5

Базовий образ беріть за digest (node:24.15.0-bookworm-slim@sha256:...), як у шаблоні: тег переїжджає, digest - ні.

4.6

Збираємо ми, і тільки ми: образ, зібраний у вас, у залік не їде - ні за тегом, ні за digest. Так збірка лишається відтворюваною з коміту.

5Замок стека

5.1

Після збірки конвеєр пише замок: нормалізований compose.yaml з викинутими полями, які ставить машина (build, image, ports, container_name, env_file, deploy, develop, profiles), і з ID зібраних образів. Ключі відсортовано на будь-якій глибині.

5.2

digest замка - sha256 його байтів. Він їде у вердикт (01-submit.md, 4.1) і в запис пакета: за ним видно, що в партії грав саме цей стек.

5.3

Замок і SHA коміту - частина походження вашого коду: вони лягають у запис пакета. Вам їх видно у вердикті, сусідам по трійці - ні (part3/03-record.md, 6.2).

6Мова бота і секрети

6.1

Бот - TypeScript або JavaScript під Node.js 24 або новіший (scoring.md, 5.1а). Ступінь lang перевіряє машинно: поле zaria.bot у package.json каталогу бота запускає node з файлом із цього каталогу, а вихідний код у каталозі - .ts, .js, .mjs, .cjs. Інша мова - провал прогону з причиною "мова бота", коміт не прийнято.

6.2

Обхід - дочірній процес іншою мовою, WebAssembly з кодом бота, бінарник у каталозі - порушення за драбиною санкцій (scoring.md, 13.7). Звичайні залежності з нативними частинами порушенням не вважаються: ідеться про код вашого бота, а не про те, якою мовою написано zlib.

6.3

Штаб цим правилом не зв'язаний: його збирає та команда, яку ви назвали в README.

6.4

Секрети: на прийманні дзеркала працює наш сканер витоків. Він читає дерево коміту і ВСЮ його історію - усіх предків, разом із влитими гілками; інших гілок репозиторію не читає (01-submit.md, 6.1). Шукає за закритим списком родів: закриті ключі, токени випускачів (GitHub, npm, AWS, Slack та інші - кожен упізнається своєю формою), вписаний у .npmrc секрет реєстру і пароль, присвоєний рядком у коді. Посилання на змінну (${ZORIA_NPM_AUTH}), явні заглушки, мітки в квадратних дужках ([REDACTED]), значення з пробільними символами і значення у формі імені змінної середовища (ZORIA_NPM_AUTH) витоком не вважаються. Секрет у .npmrc - лише символи токена після _auth= чи _authToken=, щонайменше 16, а не код навколо такого рядка (доповнення 14). Пароль у коді не шукається на тестових шляхах - у каталогах test/, tests/, __tests__/, __mocks__/, e2e/ на будь-якій глибині і у файлах *.test.*, *.spec.*; блоб історії тестовий, лише якщо тестові всі його шляхи. Роди, що впізнаються формою, шукаються і там (доповнення 13). Знайдений секрет - провал ступеня secrets із родом, шляхом і номером рядка в detail, у дереві й в історії; коміт не прийнято (scoring.md, 8.2). Список родів закритий і запінений комітом вузла: оновлення стороннього сканера не повинне міняти вердикт посеред сезону. Високоентропійний рядок без розпізнавальних знаків він не ловить. Ширше ловить захист пушу на вашому боці (00-part4.md, P4-06): push protection GitHub або локальний хук pre-push зі сканером на загальних правилах - і ловить до того, як секрет поїде в історію.

6.5

Токен реєстру, печатки вузла і паролі в репозиторії не потрібні взагалі: усе, що потрібне збірці й партії, кладемо ми змінними середовища.

7Що ми кладемо вашій машині

ЗміннаКомуКоли
ZARIA_URLголовіадреса шлюзу доріжки перед партією
ZARIA_TOKENголовіпечатка місця на цю партію
ZARIA_FREEZEголові1 на заліковій партії: промоут відповідає відмовою
ZORIA_NPM_AUTHзбірцісекрет реєстру конкурсу

Більше нічого ззовні не приходить. Машина між прогонами пакета відкочується до знімка, зробленого одразу після розгортання: усе, що бот устиг записати на диск, зникає, крім щоденника віри, який ми знімаємо до відкату.