wraithbound-publisher — операторский Rust CLI. Он запускается разработчиком или CI, но никогда не поставляется игроку вместе с Electron launcher.

Что автоматизировано

CLI сам получает официальные assets и Java runtime, строит manifests и синхронизирует S3. Исходная кастомная сборка остаётся локальной папкой: набор модов, конфигов и патчей невозможно безопасно восстановить только по версии Minecraft. Подготовка assets внутри CLI разделена на четыре части: модель Mojang index, загрузку, SHA-1/atomic file helpers и построение launcher manifest. Поэтому добавление другого источника assets не требует менять S3 publication code.

Сборка

Будут созданы две команды:

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

Относительные пути разрешаются относительно каталога publisher.toml. strip_components = 1 убирает верхнюю папку из ZIP runtime. Если архив сразу содержит bin/, задайте 0.

Credentials

Секреты не записываются в TOML:
Bucket можно передать через WB_PUBLISHER_S3_BUCKET. Для CI предпочтительны короткоживущие credentials с правами только на launcher prefix. Путь к Ed25519 seed передаётся отдельно:
Не помещайте AWS secrets в Electron config, launcher logs, Git или документацию. Publisher — единственный нативный операторский инструмент, которому разрешён прямой доступ к S3.

Команды

Создать пример

Существующий файл не перезаписывается без --force.

Проверить конфигурацию

Проверяются server_id, profile, build source, assetIndex, Java version и безопасные S3 path segments.

Подготовить assets и runtime

Assets provider:
  1. читает существующий assets/indexes/{assetIndex}.json;
  2. если index отсутствует, получает version metadata с Mojang;
  3. сверяет SHA-1 index;
  4. проверяет размер и SHA-1 каждого object;
  5. скачивает только отсутствующие или повреждённые objects.
Runtime provider принимает только HTTPS, требует ожидаемый SHA-256, извлекает ZIP во временную папку, блокирует небезопасные ZIP paths и активирует каталог только после появления bin/javaw.exe или bin/java.

Dry run

Команда строит реальные manifests и печатает общий размер и число объектов, но не подключается к S3. --skip-prepare полезен для полностью подготовленного локального дерева. Полный список S3 keys, size, SHA-256 и локальных путей выводится только с --list-objects, чтобы обычный CI log не разрастался на тысячи строк и не раскрывал устройство runner-диска. Для проверки repository-конфига без production private key используйте обёртку из корня platform:
Она создаёт одноразовый тестовый ключ и work directory только внутри игнорируемой .smoke, запускает publish --dry-run --skip-prepare, затем восстанавливает прежнее значение env и удаляет временные данные. S3 и launcher-server при этом не изменяются.

Создать только assets manifest

Общий objects/ может содержать несколько версий. Команда выбирает только SHA-1, перечисленные в indexes/{assetIndex}.json, поэтому игрок не скачивает чужие assets.

Публикация

Порядок строго фиксирован:
  1. тела файлов клиента, assets и runtime;
  2. assets manifest;
  3. runtime manifest;
  4. server manifest;
  5. signed manifest.envelope.pb, который связывает server, assets и runtime manifests в один release (если настроен release/signing);
  6. profile.json как последний metadata-объект; активация выполняется отдельно в launcher-server.
release.mirrors[].base_url является публичным корнем доставки, а не S3 endpoint. Publisher формирует из него versioned URL ${base_url}/servers/{serverId}/releases/{releaseId}/files, а assets и runtime помещает ниже того же release-каталога. Все URL входят в Ed25519-подпись. После успешной загрузки publisher может установить envelope через remote admin gRPC или в общий каталог launcher-server. Путь строится из текущих serverId и release.id, поэтому одна конфигурация не содержит зашитого номера сервера. Remote token читается из WB_LAUNCHER_ADMIN_TOKEN и не записывается в TOML. JSON остаётся форматом S3 metadata для site API и локальных native-планов. Electron принимает его только после сравнения client/assets/runtime inventories с проверенным protobuf envelope. Удалять JSON можно лишь после отдельной миграции site API и локальных scanner/downloader contracts. Для каждого S3 object сохраняется metadata sha256. При следующем запуске совпадающие size и hash пропускаются. Автоматическое удаление объектов не выполняется, поэтому ошибочная конфигурация не очистит bucket.

JSON Lines для CI

События содержат check, assets-prepared, runtime-prepared, plan, catalog-release, published или fatal. Событие object появляется только при явном --list-objects.

Совместимая команда manifest-builder

Она сохраняет прежний контракт и пишет JSON Lines progress в stderr.

Диагностика