Skip to content

0060. Хаб ProAnimaStudio: одобрение обновлений, подпись релизов, статистика и обратная связь ​

Статус: accepted. Owner: Ian Panaev. Дата: 2026-10-03. Дополняет ADR 0038 (источник обновлений) и ADR 0059.

Контекст ​

Установки Arkvory брали последний стабильный релиз прямо с GitHub. С этим было три проблемы:

  • Выпуск нельзя было раскатить постепенно или остановить: опубликованная версия сразу становилась кандидатом для всех установок.
  • Репозиторий приватный, поэтому каждой установке клиента нужен был GitHub-токен с доступом к нему.
  • Целостность держалась на SHA-256 из того же релиза. Кто получит доступ к публикации, мог бы выпустить файл, который поставят все установки с автообновлением.

У студии есть свой сервис pas-Hub, он ведёт обновления, обратную связь и анонимную статистику приложений ProAnimaStudio. Владелец выбрал (2026-10-03):

  • хаб — основной источник обновлений, при его недоступности — GitHub;
  • хаб доработан под приватный репозиторий;
  • ключ подписи — файл на рабочей станции выпуска;
  • статистика включена по умолчанию и выключается.

Решение ​

Подпись. Релиз подписывается ключом Ed25519 в формате minisign (тот же, что у Tauri).

  • Подписывается манифест arkvory-release.json: в нём SHA-256 архива и установщика.
  • release:local пишет рядом arkvory-release.json.sig и latest.json для хаба. В latest.json по платформам linux-x86_64 и windows-x86_64 лежат подпись в base64 и ссылка на манифест.
  • Черновик, созданный GitHub Actions, подписывается на рабочей станции командой npm run release:sign -- sign-draft <версия>.
  • Закрытый ключ хранится только в ~/.proanima/arkvory-release-signing.key (или в ARKVORY_SIGNING_KEY_FILE). Открытые ключи встроены в apps/deploy/src/release-keys.ts. Ротация: релиз N несёт старый и новый ключ, следующие подписаны новым.

Проверка. Любой релиз из сети — от хаба или с GitHub — ставится только с подписью встроенного ключа. Цепочка: подпись → манифест → SHA-256 архива. Локальный каталог (--artifact, пакеты) — выбор оператора; подпись рядом с ним, если есть, тоже проверяется.

Хаб решает. Порядок проверки обновлений:

  1. Планировщик (раз в 6 часов) и update спрашивают GET /v1/arkvory/update/{os}/{arch}/{текущая}?channel= и передают X-Install-Id.
  2. Хаб отвечает версией, которую человек продвинул в канал stable или beta, с учётом доли раскатки и паузы, либо 204.
  3. Файлы идут через /v1/arkvory/download/…: хаб своим токеном получает у GitHub короткоживущую подписанную ссылку и отдаёт её редиректом. Токен хаба установкам не передаётся. GitHub-токен на установке клиента больше не нужен.
  4. Явная версия (--version, pin) берётся через хаб без решения о раскатке, но с той же проверкой подписи.

Обход через GitHub — только если хаб недоступен. Сеть, тайм-аут или 5xx — тогда читается последний стабильный релиз GitHub (нужен токен для приватного репозитория). Ответ хаба 4xx, отсутствующий файл или неверная подпись — ошибка, а не повод идти в обход.

Статистика. Включена по умолчанию, выключается arkvory configure --statistics off или в консоли. Отправляется:

  • случайный id установки (config/install-id) при проверке обновлений;
  • событие updated после установленного обновления.

Без статистики id не отправляется; хаб тогда отдаёт версию, только когда она раскатана на всех. Версия, ОС и архитектура всё равно видны хабу в адресе проверки. Хаб не хранит IP, имена и содержимое.

Обратная связь. Любой вошедший пользователь отправляет из консоли текст, адрес для ответа и до 6 снимков экрана: вставка из буфера, перетаскивание или выбор файла. Ещё прикладывается журнал страницы: ошибки, предупреждения и неудачные запросы к API; заголовки авторизации и длинные строки, похожие на секреты, маскируются.

  • Маршрут POST /api/v1/feedback (JSON, лимиты хаба) проверяет запрос и пересылает его в хаб формой multipart.
  • Администратор может приложить журнал API и сводку системы: последние ≈1,5 МБ записей журнала процесса, у которых закрытый список полей, плюс версии, схему, состояние обновлений и зеркал, без адресов и секретов. Он видит их в форме до отправки; GET /api/v1/feedback/attachments отдаёт их только администратору.
  • Почту отправляет хаб через SMTP проекта; пароль почтового ящика хранится только в хабе.
  • Адрес хаба для API — ARKVORY_HUB_URL: не задан — хаб студии, пустой — обратная связь выключена.
  • Ошибки: unavailable/feedback_disabled, unavailable/hub_unreachable, rate_limited/feedback_attempts (с Retry-After).

Настройка. arkvory configure --hub-url <https://…> | --hub-off, --update-channel stable|beta, --statistics on|off пишут config/hub.json; адрес хаба также попадает в runtime.json для API. Снимок обновлений получил необязательные поля statistics и channel, запрос configure — необязательный statistics. Изменения контракта аддитивные.

Последствия ​

  • Выпуск: собрать и проверить (release:local), опубликовать черновик, затем одобрить версию для канала и доли установок в консоли хаба. Без одобрения установки её не берут, пока хаб доступен.
  • Потеря ключа подписи означает, что существующие установки не примут новые релизы, кроме как вручную из файла. Резервная копия ключа — обязанность владельца.
  • Хабу нужен fine-grained токен GitHub с Contents: read на ProAnima/Arkvory (secrets/github_token в деплое хаба). В консоли хаба нужен проект arkvory с SMTP-настройками почтового ящика.
  • Не сделано: подпись нативных пакетов .deb, .rpm и .exe (их проверяет оператор, ставящий пакет), отправка обратной связи из CLI.

Проверки ​

  • tests/release-signing.test.mjs:
    • подпись и проверка;
    • подмена байтов или комментария, чужой ключ, ключ с чужим id;
    • папка релиза с .sig и latest.json;
    • отказ при ключе, неизвестном установкам.
  • tests/hub-updates.test.mjs (поддельный хаб на loopback):
    • одобренная версия, подпись и SHA-256;
    • X-Install-Id только при включённой статистике, 204;
    • чужая подпись, несовпадающий манифест;
    • правила обхода через GitHub;
    • настройки и id установки;
    • событие updated.
  • tests/feedback.test.mjs и tests/integration/feedback.test.mjs:
    • лимиты;
    • форма multipart для хаба;
    • журнал сервера только администратору;
    • ответы хаба в контракте ошибок;
    • кольцевой буфер журнала, маскировка.
  • tests/browser/feedback.mjs:
    • вставка, выбор и удаление снимков;
    • предпросмотр вложений, отправка;
    • RU/EN, обе темы, 390 и 1440 px, скрытие после выхода.
  • tests/browser/updates.mjs: переключатель статистики.
  • tests/update-monitor.test.mjs: статистика и канал в снимке.
  • pas-Hub tests/api.rs: приватный репозиторий — синхронизация, выдача версии, подписанная ссылка, токен не уходит в хранилище.

Arkvory · ProAnimaStudio