diff --git a/servers/rpi.md b/servers/rpi.md index f119408..e9e5b95 100644 --- a/servers/rpi.md +++ b/servers/rpi.md @@ -153,6 +153,13 @@ Docker CE 29.9 + Compose v5.6 из репо download.docker.com (в Debian ст - Индикатор работы добавлен 2026-10-11: [astra-bot `20a8ffc`](https://git.ruzzy.dev/ruzzy/astra-bot/commit/20a8ffc). Раньше typing отправлялся один раз и пропадал через несколько секунд; теперь при распознавании голосовых и выполнении задачи отдельное тихое сообщение с машинкой 🚗 редактируется каждые 4 с, typing обновляется. Один индикатор на чат, перекрывающиеся задачи учитываются; после окончания сообщение удаляется. Проверки: 46 тестов, включая перекрытие задач, редактирование/удаление и неудачную отправку. Резервная копия `/opt/astra-bot/bot.py.bak-20261011-waiting-car`; установка выполнена, перезапуск через `restart-check.py` после ответа. +## Разговорный навык Маруси (подготовлен 2026-10-11) +- Установлен и включён `astra-marusia.service`, код — [astra-bot `27e39ea`](https://git.ruzzy.dev/ruzzy/astra-bot/commit/27e39ea), `/opt/astra-marusia/server.py`; юнит и инструкция — `stacks/astra-marusia/`. Это отдельная беседа без инструментов управления сервером; семейные ответы для 10 лет. История до 16 реплик на user_id в памяти, очищается после перезапуска/суток простоя; тексты не пишутся в access log. +- Слушает только `127.0.0.1:8788`, `/health` проверен. Секрет пути webhook — `/etc/astra-marusia.env` (root 600), `MARUSIA_SKILL_ID` пока пуст: POST закрыты до регистрации навыка. Публичного HTTPS URL, туннеля и привязки колонки ещё нет. ⚠️ Это готовая локальная часть, не подключённая колонка. +- Используется существующая авторизация Codex/ChatGPT через read-only bind `~astra/.codex/auth.json` в отдельный CODEX_HOME `/var/lib/astra-marusia`; пользовательские config/rules, shell/apps/browser и проектные инструкции отключены. systemd `ProtectHome=tmpfs`, `ProtectSystem=strict`, `NoNewPrivileges=yes`; рабочий StateDirectory 700. ⚠️ Read-only привязка auth может потребовать повторной проверки после обновления/refresh авторизации; не выдавать колонке административный тред Telegram. +- Проверки: 50 тестов бота/навыка, настоящий ответ модели «Два плюс два — четыре» (7 с), успешный запуск сервиса. Webhook ждёт модель до 2 с, затем предлагает спросить «готово?»; повтор session_id/message_id идемпотентен. До двух запросов к модели одновременно, до 50 разговоров. Короткое ожидание нужно из-за задержки модели; реальное время ожидания/tts и формат платформы проверить в отладчике VK. +- Осталось владельцу: зарегистрировать приватный навык VK и прислать skill_id; для публичного адреса нужен ограниченный SSH-туннель к fr1 + HTTPS-прокси. С rpi у astra есть только ключ Gitea, доступа SSH на fr1 нет. Шаблон nginx подготовлен, на fr1 не установлен. + ## Открытые хвосты (на 2026-10-11) - USB3-хаб с питанием — теперь только ради скорости: WD Elements 1 ТБ работает второй копией в роутере (~10 МБ/с); на малине через хаб было бы ~100 МБ/с (обновлено 2026-10-11, было «копия одна»). - Нет node-exporter (CPU/RAM/диск самой малины в Prometheus не видны) — пуш через pushgateway для node-метрик неудобен; решить, нужен ли. diff --git a/stacks/astra-marusia/README.md b/stacks/astra-marusia/README.md new file mode 100644 index 0000000..5573376 --- /dev/null +++ b/stacks/astra-marusia/README.md @@ -0,0 +1,35 @@ +# Разговор с Астрой через Марусю + +Код: `ruzzy/astra-bot`, `marusia/server.py`, тесты `test_marusia.py`. +Сервис на rpi слушает только `127.0.0.1:8788`; наружу пока не опубликован. +Webhook: `POST /webhook/<секрет из /etc/astra-marusia.env>`. +Проверка: `GET /health`. + +Отдельный разговор на идентификатор пользователя Маруси, до 16 реплик в памяти; +при перезапуске история очищается, через сутки простоя удаляется. Беседа семейная, +ответы подходят ребёнку 10 лет. Тексты не пишутся в access log. Голос распознаёт +Маруся, Астра отвечает текстом, Маруся озвучивает `response.tts`. + +Codex использует существующую авторизацию ChatGPT: файл auth.json привязан +только для чтения в отдельный CODEX_HOME. Пользовательская конфигурация, правила, +документы проекта и инструменты shell/apps/browser отключены. systemd скрывает +домашние каталоги, запрещает повышение привилегий и запись за пределами своего +StateDirectory. Не подключать этот сервис к административному треду Telegram. +После обновления Codex повторно проверять список отключаемых feature flags. + +Быстрый ответ ожидается до 2 секунд. Если ответ ещё готовится, колонка просит +сказать «готово?»; новая реплика во время ожидания не запускает вторую задачу. +Повтор webhook с теми же session_id/message_id получает кешированный ответ. +Не более двух обращений к модели одновременно, не более 50 разговоров. + +Для завершения нужны: приватный навык в аккаунте VK владельца, его skill_id +в env, публичный HTTPS URL с проксированием на rpi (например nginx на fr1 +и отдельный ограниченный SSH-туннель). Доступа SSH к fr1 у astra на rpi сейчас нет; +ключ Gitea — не ключ сервера. Не открывать домашний порт в интернет напрямую. +На публичном прокси отключить access log webhook (секрет в URL), ограничить +размер тела 64 KiB, POST и частоту запросов; таймаут 5 секунд. +Регистрация/проверка: https://platform.vk.com/ и +https://skill-tester.marusia.mail.ru/ (актуальность интерфейса проверить при входе). +До заполнения skill_id все POST закрыты (403), знание случайного пути обязательно. +skill_id не является криптографическим доказательством отправителя; секрет URL +и приватный доступ навыка обеспечивают первичное ограничение доступа. diff --git a/stacks/astra-marusia/astra-marusia.service b/stacks/astra-marusia/astra-marusia.service new file mode 100644 index 0000000..56ad704 --- /dev/null +++ b/stacks/astra-marusia/astra-marusia.service @@ -0,0 +1,30 @@ +[Unit] +Description=Astra conversation skill for Marusia +After=network-online.target +Wants=network-online.target + +[Service] +User=astra +Group=astra +WorkingDirectory=/var/lib/astra-marusia +EnvironmentFile=/etc/astra-marusia.env +Environment=CODEX_HOME=/var/lib/astra-marusia +Environment=HOME=/var/lib/astra-marusia +ExecStart=/usr/bin/python3 /opt/astra-marusia/server.py +Restart=on-failure +RestartSec=5 +StateDirectory=astra-marusia +StateDirectoryMode=0700 +UMask=0077 +NoNewPrivileges=yes +ProtectSystem=strict +ProtectHome=tmpfs +BindReadOnlyPaths=/home/astra/.codex/auth.json:/var/lib/astra-marusia/auth.json +PrivateTmp=yes +ProtectKernelTunables=yes +ProtectKernelModules=yes +ProtectControlGroups=yes +RestrictSUIDSGID=yes + +[Install] +WantedBy=multi-user.target diff --git a/stacks/astra-marusia/env.example b/stacks/astra-marusia/env.example new file mode 100644 index 0000000..33a2772 --- /dev/null +++ b/stacks/astra-marusia/env.example @@ -0,0 +1,3 @@ +# Root-owned /etc/astra-marusia.env, mode 600. Never commit actual secret. +MARUSIA_WEBHOOK_SECRET=GENERATE_RANDOM_SECRET_AT_LEAST_32_CHARACTERS +MARUSIA_SKILL_ID= diff --git a/stacks/astra-marusia/nginx-location.example b/stacks/astra-marusia/nginx-location.example new file mode 100644 index 0000000..633f87e --- /dev/null +++ b/stacks/astra-marusia/nginx-location.example @@ -0,0 +1,12 @@ +# Include inside the existing HTTPS server block on fr1 AFTER creating an SSH tunnel. +# Reverse tunnel must bind only to fr1 127.0.0.1:18788 -> rpi 127.0.0.1:8788. +# No public port 8788/18788; VK uses the existing HTTPS listener. +location ^~ /marusia/webhook/ { + access_log off; + client_max_body_size 64k; + limit_except POST { deny all; } + proxy_connect_timeout 1s; + proxy_read_timeout 5s; + proxy_pass http://127.0.0.1:18788/webhook/; +} +# Add a limit_req zone in nginx http{} and apply its limit here before exposure.