Перейти к основному содержимому

ADR 0203 — Поток runner через браузер выводится из употребления, путь — установщик

Статус​

Accepted. 2026-10-01 (AT-014, BRB-031, раунд 36; решение владельца от 01.10: «вывести из употребления поток браузера из ADR 0118 — генерацию ключа, загрузку бинарника и запись config через браузер; путь — install.sh»). Пересматривает, не редактируя, ADR 0118 (автоматическая настройка runner через браузер, RN-464..466) и закрывает BRB-031. Сохраняет ADR 0154 (два вида ключа), ADR 0155 (ключ машины рождается в терминале, и установщик его регистрирует, RN-547/551/552) и ADR 0150 (однострочный установщик и проверка собственного происхождения).

Контекст​

ADR 0118 заставил браузер генерировать пару Ed25519 (Web Crypto), регистрировать публичный ключ (POST /projects/:projectId/runner-device-keys), скачивать бинарник (GET /runner-releases/binary) и записывать три файла в папку через File System Access API — или, вне Chromium, запускать две загрузки. Он письменно принял ограничение: «браузер не сохраняет бит выполнения; chmod +x в Linux/macOS остаётся ручным». Это был последний ручной шаг любого пути установки, и это BRB-031.

ФАЗА 29 создала второй путь без этого шага: install.sh скачивает бинарник, сверяет его с подписанным checksums.txt и устанавливает его через install -m 0755 (RN-531). ФАЗА 30 завершила спаривание со стороны машины: brabo-runner device-key create генерирует пару НА МАШИНЕ (RN-551), установщик регистрирует публичный ключ через внутренний маршрут МАШИНЫ с service token (RN-552) и связывает обе вещи в конце установки (RN-547). С тех пор поток браузера был вторым путём, свёрнутым в <details> RunnerOnboardingPanel (RN-548), а его вывод из употребления остался объявленным как решение сопровождающего, а не следствие той поставки.

Измерено в dev (ec0fbea52d) до изменения — кто использует то, что использует поток:

  • У apps/web/src/lib/runner-bootstrap.ts (генерация пары, экспорт JWK, загрузка бинарника, запись папки, ручной набор) был один production-потребитель, RunnerOnboardingPanel. Вне его — только собственный тест и scripts/ci/alvos-do-runner.spec.ts, который читал список платформ браузера как четвёртое место, перечисляющее цели.
  • registerRunnerDeviceKey (apps/web/src/lib/api-client.ts) вызывался только из runner-bootstrap.ts.
  • POST /projects/:projectId/runner-device-keys вызывался только из runner-bootstrap.ts и из e2e/testes/chave-de-dispositivo.spec.ts, который существовал, чтобы доказать ИМЕННО ключ, сгенерированный в Chromium. Ни один скрипт, ни один runner, ни один workflow, ни один install.sh его не вызывает — установщик использует POST /internal/machine-device-keys.
  • У GET и DELETE того же маршрута есть ДРУГИЕ потребители: раздел ключей Настроек (RN-561), распознавание панели (RN-548) и отзыв.
  • PatAuthGuard принимает ключ ПРОЕКТА по kid, и в реальных установках есть ключи проекта, зарегистрированные потоком браузера.
  • У GET /runner-releases/binary (proxy загрузки) единственным production-потребителем был браузер.

Решение​

  1. RunnerOnboardingPanel отправляет к install.sh. Первым планом панели становится команда установщика (curl -fsSLO …/install.sh && bash install.sh, ТА ЖЕ фраза из runbook и самого install.sh, RN-526), копируемая, с текстовым описанием того, что она делает — скачивает бинарник, сверяет с подписанным манифестом, устанавливает уже исполняемым и спаривает машину, — и EsperaDoRunner (RN-474) под ней. Команда — копия на TS фразы установщика, и scripts/dev/install-invocacao.spec.ts отклоняет копию, которая разойдётся.
  2. Что ОСТАЁТСЯ в панели: распознавание уже спаренного ключа (RN-548 и ключа ПРОЕКТА, AT-107), с теми же оговорками, — и, когда распознан ключ, обслуживающий проект, блок установщика УХОДИТ. Ручная команда с PAT (--token) остаётся в <details>, переименованном под случай, который она решает: «Outra máquina, ou rodar manualmente».
  3. Что ИСЧЕЗАЕТ из web: runner-bootstrap.ts целиком и его тест (генерация ключа через Web Crypto, загрузка бинарника браузером, запись через File System Access и набор из двух загрузок), registerRunnerDeviceKey и тип RunnerDeviceKeySummary, ключи i18n кнопок и состояний потока и селектор платформы.
  4. Что ИСЧЕЗАЕТ из api: POST /projects/:projectId/runner-device-keys, вместе с RegisterRunnerDeviceKeyUseCase и двумя DTO, принадлежавшими только ему. Он остался без вызывающего. Внутренний маршрут МАШИНЫ (POST /internal/machine-device-keys) ОСТАЁТСЯ, и линейка формы JWK (exigirJwkPublicaEd25519, в домене) остаётся с ним.
  5. УЖЕ зарегистрированный ключ проекта продолжает действовать и может быть отозван. В базе ничего не меняется: заполненный runner_device_keys.project_id остаётся допустимым видом, PatAuthGuard продолжает принимать подписанный им JWT, GET продолжает перечислять, а DELETE — отзывать. Runner, настроенный через браузер до этого ADR, не ломается: папка с brabo-runner.config.json и brabo-runner-device-key.jwk.json по-прежнему читается CLI (RN-466 целиком), и unit ПРОЕКТА, которую он мог установить, продолжает работать. Перестаёт существовать создание НОВОГО ключа проекта.
  6. e2e ключа, сгенерированного в браузере, уходит вместе с ним. То, что он доказывал, — что kid, записанный БРАУЗЕРОМ, принимается сервером, — больше не имеет производителя. Цепочка kid → JWT → PatAuthGuard с реальным ключом по-прежнему покрыта в apps/api/test/interfaces/pat-auth.guard.spec.ts, а пара, сгенерированная на машине, — в apps/runner/src/criar-chave-de-dispositivo.spec.ts.
  7. Список целей runner начинает жить в ТРЁХ местах, а не в четырёх: список браузера ушёл вместе с модулем, и scripts/ci/alvos-do-runner.spec.ts не даёт ему молча вернуться.

Ветка — breaking/: удаление публичного маршрута, задокументированного в OpenAPI, — это изменение контракта для тех, кто его вызывает, а политика версий (scripts/ci/version.ts) говорит, что решает ФУНКЦИЯ, — patch сказал бы «обновляйте не думая».

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

Хорошие.

  • У пути установки больше нет ручного шага chmod нигде в продукте: единственный, у которого он был, ушёл. BRB-031 закрывается.
  • НОВЫЙ ключ устройства рождается в одном месте — терминале машины — и регистрируется одним регистратором — установщиком. api теряет маршрут записи, аутентифицируемый JWT сессии.
  • Web теряет ~530 строк кода криптографии, загрузки и записи на диск, которые jsdom не мог проверить без дублёра.

Плохие, объявленные.

  • Установка с командой теряет путь без PAT. Маршрут, создающий ключ МАШИНЫ, обслуживает только установку ОДНОГО человека (409 при двух и более, RN-552), а install.sh устанавливает весь Brabo на машину — он не годится для спаривания ВТОРОЙ машины с уже существующей установкой. Для этих людей путь становится ручной командой с PAT (--token), которую панель продолжает предлагать и называет путём для другой машины. Поток браузера был единственным способом спарить без PAT в этом случае, и решение владельца всё равно выводит его из употребления.
  • GET /runner-releases/binary остаётся без production-потребителя. Proxy НЕ был удалён здесь: решение назвало маршрут регистрации ключа, а proxy несёт проверку целостности RN-525 и открытую половину происхождения BRB-005. Удалить или оставить — решение владельца, отдельное.
  • Тот, у кого была открыта вкладка потока в момент деплоя, получает 404 на POST при клике — старый bundle всё ещё вызывает маршрут. Перезагрузка страницы решает это.
  • RN 464..466 и 473/475 описывают поток таким, каким он был; они получают пометку о пересмотре, никогда не удаление.