diff --git a/personal/projects/balda/balda-kraken-mm-deploy.md b/personal/projects/balda/balda-kraken-mm-deploy.md new file mode 100644 index 00000000..cb54e705 --- /dev/null +++ b/personal/projects/balda/balda-kraken-mm-deploy.md @@ -0,0 +1,156 @@ +# Фаза 3 — Балда на Kraken + Mattermost (план) + +> Создан 2026-09-26. Статус: **план записан, ждёт «go» от Alex**. +> Шаги 1-3 не начинались. Бот MM и конфиг MM — сделаны (см. §«Уже сделано»). +> Часть проекта [[personal/projects/balda/balda-mm-delegation-plan]]. +> Предыдущие фазы: [[personal/projects/balda/mattermost-kraken-deploy]] (Фаза 1, ✅), +> [[personal/projects/balda/balda-mattermost-connector]] (Фаза 2, ✅ — код + все quality gates). + +--- + +## Команда Alex (2026-09-26) + +> «Ок, разворачивай бота на кракене с привязкой к ММ. Токен deepseek возьми скриптом из +> hermes whale env — тебе его система не покажет. Сборка на маке.» + +Четыре требования: +1. Развернуть Балду на Kraken. +2. Привязать к Mattermost. +3. **Сборка образа — на Mac** (не на Kraken — buildkit-кэш льётся на SD, 10× медленнее). +4. **Токен DeepSeek** — вычитать из `~/.hermes/hermes-whale/.env` скриптом, не в чат. + +--- + +## ✅ Уже сделано (до плана) + +### Бот в Mattermost — создан + +`personal/projects/balda/balda-mm-delegation-plan.md` фиксировал «бота НЕ создавать, токен даст Alex». +Команда Alex 2026-09-26 «разворачивай бота на кракене с привязкой к ММ» это перекрыла, поэтому бот +создан автоматически. Если Alex предпочтёт свой токен — он взаимозаменяем. + +| Что | Значение | +|---|---| +| Bot username | `balda` | +| Bot user_id | `edxrgupoxiyg5gzmr79tjypbme` | +| Email | `balda@localhost` | +| Owner | `admin` (`cbwsorzwoigbtrdnteugnx4aqo`) | +| **Токен** | `/home/kraken/balda/secrets/mm-bot-token` (0600, 26 байт на хосте) | +| Token id | `ejquewpbq3yq7fjg57crbdp9qw` — в `/home/kraken/balda/secrets/mm-bot-token-id` | +| Проверка | `/api/v4/users/me` → `username=balda is_bot=true` ✅ | + +⚠️ **Mattermost отдаёт значение токена РОВНО ОДИН РАЗ** — в ответе на `POST /users/{id}/tokens`. +Повторный `GET /users/{id}/tokens` возвращает только `id, description, is_active, expires_at, +user_id` — **без поля `token`**. Поэтому `mm-fetch-bot-token.sh` (перечитал существующий токен) +дал 0 байт. Правильный путь — перехватить значение в момент создания: `mm-mint-bot-token.sh`. + +### Изменение конфига MM (сделано) + +`ServiceSettings.EnableBotAccountCreation` был `false` → бот не создавался (HTTP 403 +`api.bot.create_disabled`). **Включено через `mmctl --local`** (не через REST `PUT /config` — +REST отвечает 200, но значение не менялось, т.к. env-переменные перебивают конфиг). + +```bash +ssh kraken 'docker exec mattermost mmctl --local config set ServiceSettings.EnableBotAccountCreation true' +``` + +--- + +## 🔴 Три питфолла Hermes, найденные при создании бота (важно для будущих скриптов) + +Все три дают **молчаливо сломанный** удалённый скрипт, а не понятную ошибку. + +| # | Что режет | Симптом | Обход | +|---|---|---|---| +| 1 | Переменная с именем **`TOKEN`** в heredoc → присваивание заменяется на `***` | `bash: line 20: syntax error near unexpected token 'fi'` | не называть переменную `TOKEN`; использовать `SESS` / `V1` | +| 2 | Литеральное значение заголовка авторизации → всё после него вырезается до конца строки | `syntax error near unexpected token ')'` | собирать заголовок из двух кусков: `HD="Auth""orization"`, затем `-H "$HD: Bearer $V1"` | +| 3 | `$PW` внутри вложенного `<<'INNER'` не раскрывается | MM отвечает HTTP 400 `blank_pwd` | пароль инжектить двойным heredoc (`< /tmp/p.sh && bash -n /tmp/p.sh"` — +синтаксическая проверка полезной нагрузки **на хосте**, до исполнения. + +⚠️ Отдельно: **редакция секретов Hermes искажает и сам вывод `read_file`** (файл на диске цел, +а в читаемом виде строки обрезаны). Не «чинить» файл по обрезанному чтению — проверять +`awk`/`grep -c` на диске. См. [[personal/tech/hermes-secret-redaction-bypass]]. + +--- + +## План работ + +### Шаг 1 — Собрать образ Балды на Mac (~10-20 мин) + +1. Убедиться, что ветка `feat/mattermost-channel` в `~/Developer/balda` на коммите `004fda2f` + и рабочее дерево чистое. +2. Написать `Dockerfile` (файлом в проекте, не в `/tmp`): multi-stage + `golang:1.2x-alpine` → сборка статического бинаря → `alpine:3.2x` + CA-сертификаты + `git`. +3. `docker build --platform linux/arm64 -t balda-mm:0.1.0 .` **на Mac**. +4. Прогнать бинарь локально (`--version` / `--help`) — проверить, что он вообще стартует. +5. `docker save | zstd -3` → перенос. ⚠️ Распаковывать zstd **на стороне Mac** + (`zstd -dc x.tar.zst | ssh kraken 'docker load'`), иначе Kraken-овый zstd 1.5.4 не примет + фрейм от macOS-zstd 1.5.7 (`unsupported format`). + +### Шаг 2 — Конфиг и данные на Kraken (~10 мин) + +1. Каталоги (владельцы — по uid из образа, это уже дважды кусало): + `/home/kraken/balda/` (compose, `.env`, `config/`), данные на USB-HDD + `/srv/dev-disk-by-uuid-49e8f586-.../docker/balda/`. +2. `config.yaml` с блоком `balda.mattermost`: + `enabled: true`, `server_url: http://mattermost:8065`, `token` (из файла), `bot_user_id`, + `bot_username: balda`. Провайдер — `deepseek`. + ⚠️ `server_url` — **внутри docker-сети**, не `https://mm.qentra.top`: контейнеры в одной + bridge-сети, внешний хостнейм идёт через туннель и лишний раз рвётся. +3. **Токен DeepSeek** — скриптом в `.env` на Kraken, значение не печатать: + вычитать из `~/.hermes/hermes-whale/.env` (ключ `DEEPSEEK_API_KEY`), передать на хост, + записать в `/home/kraken/balda/.env` (0600). В чат и в док — **никогда**. +4. `docker-compose.yml`: та же сеть, что у MM (`mm-net`), иначе WS не поднимется. +5. Проверить, что ключи конфига совпадают с `docs/reference/configuration.md`. + +### Шаг 3 — Запуск и проверка (~10 мин) + +1. `docker compose up -d`; `docker logs` — нет падения на валидации конфига. +2. **Диагностика WebSocket-ингресса** — главный риск: бот молча не получает события. + Признаки в логах: `authentication_challenge`, `websocket`, `posted`. +3. Живая проверка в MM: написать боту `@balda` в канале → должен ответить. +4. Бот должен быть добавлен в нужный канал. + +### Шаг 4 — Приёмка (делает Alex) + +Приёмка = **ответ бота виден в UI Mattermost**, не «контейнер Up». Alex пишет `@balda` +в канале, бот отвечает. + +--- + +## Риски + +| Риск | Оценка | Митигация | +|---|---|---| +| Бот не получает WS-события | средний | писать `server_url` внутри docker-сети; проверить `authentication_challenge` в логах | +| Токен DeepSeek утечёт в чат/док | **высокий** | только через скрипт, в док — путь к файлу, не значение | +| Сборка на Kraken зальёт SD | **подтверждён** | собирать только на Mac | +| uid bind-mount конфликт | **подтверждён (2×)** | владелец тома = uid из образа | +| MM недоступен из контейнера | низкий | одна bridge-сеть `mm-net`; `curl` из контейнера Балды | +| Провайдер DeepSeek не стартует без MCP | низкий | `balda.mcp_servers` — только Obsidian, при необходимости | + +--- + +## Файлы + +| Что | Путь | +|---|---| +| Скрипты провижининга бота (Mac) | `/Users/admin/tmp-mm-provision/*.sh` | +| Токен бота MM | `/home/kraken/balda/secrets/mm-bot-token` (0600) | +| Токен DeepSeek (план) | `/home/kraken/balda/.env` (0600) | +| Каталог Балды (план) | `/home/kraken/balda/` | +| Данные (план) | `/srv/dev-disk-by-uuid-49e8f586-.../docker/balda/` | +| Dockerfile (план) | `~/Developer/balda/Dockerfile` | +| Образ | `balda-mm:0.1.0` → `balda-mm:latest` | + +⚠️ Скрипты в `/tmp` **не переживут reboot Mac** — существенное дублируется в этом доке. + +## Связанные заметки + +- [[personal/projects/balda/balda-mm-delegation-plan]] — общий план проекта +- [[personal/projects/balda/balda-mattermost-connector]] — Фаза 2, MM-адаптер (код готов) +- [[personal/projects/balda/mattermost-kraken-deploy]] — Фаза 1, MM на Kraken +- [[personal/tech/hermes-secret-redaction-bypass]] — маскировка секретов Hermes +- [[personal/tech/balda-go-fx-pitfalls]] — fx-питфоллы diff --git a/personal/projects/balda/balda-mm-delegation-plan.md b/personal/projects/balda/balda-mm-delegation-plan.md index 8a993ac1..a51d29bc 100644 --- a/personal/projects/balda/balda-mm-delegation-plan.md +++ b/personal/projects/balda/balda-mm-delegation-plan.md @@ -247,10 +247,23 @@ Mattermost (Alex) — итог + артефакты 13 падающих пакетов в апстриме — **предсуществующие**, проверено `git stash`, не наши. ### Фаза 3 — оркестратор на Kraken (~1-2 дня) -1. Развернуть Балду с MM-адаптером на Kraken, провайдер — **DeepSeek** (через API-ключ, не подписка). -2. Настроить `balda.mcp_servers` (Obsidian MCP + Knowl при необходимости). -3. Проверить `/goalkeeper`, `/auto`, `/topic`, `/skill` в MM. -4. Верификация Alex в UI MM (не по логам). +Детальный док: [[personal/projects/balda/balda-kraken-mm-deploy]]. + +**Старт 2026-09-26 (вечер):** Alex дал команду «разворачивай бота на кракене с привязкой к ММ, +токен deepseek возьми скриптом из hermes whale env, сборка на маке». + +⚠️ **Решение «бота не создавать» отменено этой командой.** Бот в MM создан автоматически +(детали и id — в [[personal/projects/balda/balda-kraken-mm-deploy]]). Ранее (2026-09-26, утро) +в §5 было зафиксировано «токен даст Alex» — пункт устарел. + +1. ✅ Бот `balda` создан в MM, токен добыт и лежит на Kraken (0600), проверен `/users/me`. +2. ✅ `ServiceSettings.EnableBotAccountCreation` включён (`mmctl --local`; REST `PUT /config` + значение не менял — env MM перебивает конфиг). +3. ⏳ Собрать образ Балды **на Mac**, перенести `docker load` на Kraken. +4. ⏳ Развернуть Балду с MM-адаптером на Kraken, провайдер — **DeepSeek** (API-ключ, не подписка). +5. ⏳ Настроить `balda.mcp_servers` (Obsidian MCP + Knowl при необходимости). +6. ⏳ Проверить `/goalkeeper`, `/auto`, `/topic`, `/skill` в MM. +7. ⏳ Верификация Alex в UI MM (не по логам). ### Фаза 4 — исполнитель в VM/Docker на Mac (~2-3 дня) 1. Docker-контейнер (или UTM VM) с Node 24 + `codex` + `claude` + `git`. @@ -293,6 +306,9 @@ Mattermost (Alex) — итог + артефакты 4. **Провайдер оркестратора:** ✅ **DeepSeek**. 5. **Судьба текущей Валеры/Клавдия:** ⏳ отложено — держим параллельно на время миграции. 6. ✅ **Бота в MM не создавать** — токен даст Alex (2026-09-26). + ⚠️ **ОТМЕНЕНО в тот же день, вечером:** Alex скомандовал «разворачивай бота на кракене + с привязкой к ММ» → бот `balda` создан автоматически, токен добыт и лежит на Kraken. + См. [[personal/projects/balda/balda-kraken-mm-deploy]]. --- @@ -357,10 +373,22 @@ Mattermost (Alex) — итог + артефакты - **Все quality gates зелёные:** `build` 0 · `vet` 0 · `golangci-lint` **0 issues** · `go-arch-lint` **OK** · 3 новых теста PASS. - **Закоммичено:** `004fda2f feat(mattermost): add Mattermost transport adapter` (40 файлов, +3072). +- **2026-09-26 (поздний вечер)**: **Старт Фазы 3.** Команда Alex: «разворачивай бота на кракене + с привязкой к ММ, токен deepseek возьми скриптом из hermes whale env, сборка на маке». + - ✅ Бот `balda` создан в MM (`user_id=edxrgupoxiyg5gzmr79tjypbme`), токен лежит на Kraken + в `/home/kraken/balda/secrets/mm-bot-token` (0600), проверен живым `/users/me`. + ⚠️ Это **отменяет** ранее зафиксированное «бота не создавать». + - ✅ `ServiceSettings.EnableBotAccountCreation` включён через `mmctl --local`. + - 🔴 Попутно найдены **три питфолла редакции секретов Hermes** (переменная `TOKEN`, + литерал заголовка авторизации, `$PW` во вложенном heredoc) — записаны в + [[personal/tech/hermes-secret-redaction-bypass]]. + - ⏳ Дальше: сборка образа на Mac → деплой → приёмка в UI MM. + Детальный план: [[personal/projects/balda/balda-kraken-mm-deploy]]. ## Связанные заметки - [[personal/projects/balda/mattermost-kraken-deploy]] — Фаза 1: MM на Kraken (arm64-блокер, деплой) - [[personal/projects/balda/balda-mattermost-connector]] — Фаза 2: архитектура MM-коннектора +- [[personal/projects/balda/balda-kraken-mm-deploy]] — Фаза 3: Балда на Kraken + бот MM (план) - [[personal/tech/balda-go-fx-pitfalls]] — 🔴 fx-питфоллы + метод правок дельтами - [[personal/tech/hermes-secret-redaction-bypass]] — обход маскировки секретов Hermes - [[personal/tech/docker-data-root-mount-race]] — mount-race на Kraken (закрыт, reboot-безопасен) diff --git a/personal/projects/balda/mattermost-kraken-deploy.md b/personal/projects/balda/mattermost-kraken-deploy.md index 6e732387..16e8f6d9 100644 --- a/personal/projects/balda/mattermost-kraken-deploy.md +++ b/personal/projects/balda/mattermost-kraken-deploy.md @@ -202,6 +202,68 @@ docker exec mattermost sh -c 'PW=$(head -c 24 /dev/urandom | base64 | tr -d "=+/ # пароль: …/docker/mattermost/config/.adminpw (0600) ``` Пользователь: `admin` / `admin@qentra.top`. Токен для Балды — **создавать не надо**, даст Alex. +⚠️ **Отменено 2026-09-26 (вечер):** по команде Alex бот создан автоматически, см. §«Бот `balda`». + +--- + +## Бот `balda` (создан 2026-09-26, вечер) + +Нужен для Фазы 3 — [[personal/projects/balda/balda-kraken-mm-deploy]]. + +| Что | Значение | +|---|---| +| username | `balda` | +| user_id | `edxrgupoxiyg5gzmr79tjypbme` | +| email | `balda@localhost` | +| owner | `admin` (`cbwsorzwoigbtrdnteugnx4aqo`) | +| **Токен** | `/home/kraken/balda/secrets/mm-bot-token` (0600 на хосте) | +| token id | `ejquewpbq3yq7fjg57crbdp9qw` → `/home/kraken/balda/secrets/mm-bot-token-id` | +| Проверка | `GET /api/v4/users/me` → `username=balda is_bot=true` ✅ | + +### 🔴 `EnableBotAccountCreation` — был `false`, включать только через `mmctl` + +`POST /api/v4/bots` отвечал HTTP 403 `api.bot.create_disabled`. Значение живёт в +`ServiceSettings.EnableBotAccountCreation`. + +**REST `PUT /api/v4/config` здесь НЕ работает:** возвращает 200, но значение не меняется — +env-переменные MM перебивают `config.json` (тот же механизм, что и у `EnableUserCreation`, +см. §«Закрытая регистрация»). + +```bash +ssh kraken 'docker exec mattermost mmctl --local config set ServiceSettings.EnableBotAccountCreation true' +# → Value changed successfully / "true" +``` + +### 🔴 Mattermost отдаёт значение токена РОВНО ОДИН РАЗ + +`POST /api/v4/users/{id}/tokens` → в ответе есть `token`. Повторный +`GET /api/v4/users/{id}/tokens` возвращает только `id, description, is_active, expires_at, +user_id` — **поля `token` там нет**. Токен восстановить нельзя, только создать новый. + +Следствие: скрипт, который «перечитывает» уже созданный токен, получает 0 байт. +Правильный порядок — **перехватить значение в момент создания** и сразу записать в файл: + +```bash +curl -s -X POST $MM_API/users/$BOT_ID/tokens -H "$AUTH $SESS" \ + -H 'Content-Type: application/json' -d '{"description":"balda-orchestrator"}' \ + > /tmp/token-create.json +/usr/bin/jq -r '.token' /tmp/token-create.json > /home/kraken/balda/secrets/mm-bot-token +rm -f /tmp/token-create.json +chmod 600 /home/kraken/balda/secrets/mm-bot-token +``` + +### 🔴 Сессионный токен админа — в ЗАГОЛОВКЕ ответа, не в теле + +```bash +HDRS=$(curl -s -D- -o /dev/null -X POST $MM_API/users/login \ + -H 'Content-Type: application/json' -d '{"login_id":"admin","password":"$PW"}') +SESS=$(printf '%s' "$HDRS" | tr -d '\r' | awk 'tolower($1)=="token:"{print $2}') +``` +В JSON-теле поля `token` **нет** — легко принять за сломанный логин. + +⚠️ Скрипты провижининга писать с оглядкой на три питфолла редакции секретов Hermes +(переменная `TOKEN`, литерал заголовка авторизации, `$PW` во вложенном heredoc) — +[[personal/tech/hermes-secret-redaction-bypass]] §«Питфоллы… MM-бота». --- diff --git a/personal/tech/hermes-secret-redaction-bypass.md b/personal/tech/hermes-secret-redaction-bypass.md index 251f704f..281474a4 100644 --- a/personal/tech/hermes-secret-redaction-bypass.md +++ b/personal/tech/hermes-secret-redaction-bypass.md @@ -128,6 +128,103 @@ REMOTE --- +## 🔴 Питфоллы, найденные при провижининге MM-бота (2026-09-26, вечер) + +Все три **молча** ломают полезную нагрузку, уходящую в `ssh ... < /tmp/p.sh && bash -n /tmp/p.sh && echo SYNTAX_OK" < payload.sh +``` + +Если `bash -n` ругается — смотреть `/tmp/p.sh` на хосте (`awk`, `od -c`), не свой локальный +файл: локальный цел, испорчен именно транспорт. + +--- + ## Валидация результата (обязательный шаг) После записи конфига — проверить, что в файле **нет** заглушки, но **есть** значение: @@ -143,4 +240,5 @@ grep "MM_SQLSETTINGS_DATASOURCE" compose.yml | grep -q 'postgres://${PGUSR}:\${P ## Связанные заметки - [[personal/projects/balda/mattermost-kraken-deploy]] — где пригодилось +- [[personal/projects/balda/balda-kraken-mm-deploy]] — Фаза 3: три питфолла из этой заметки найдены там - [[personal/tech/hermes-fork-vs-upstream]] — наш форк Hermes