Звіт про баг із UI¶
Кожна сторінка в BamDude несе плаваючу червону кнопку Bug в правому нижньому куті. Клацання відкриває панель, через яку можна подати звіт у kainpl/bamdude не залишаючи UI — BamDude збирає санітизовані debug-логи + скріншот + структурований support-snapshot, постить на bamdude.top-релей, і повертає номер свіжо-створеного GitHub-issue.
Шипається в BamDude 0.4.4. Адаптовано з upstream Bambuddy 058f74a7 + dc4d77b9 + 57092822.
Чому через релей?
BamDude сам ніколи не тримає GitHub PAT. PAT — на стороні bamdude.top, де релей створює issue в апстрімовому репо від вашого імені. Ця асиметрія і є точкою — шипити PAT в Docker-образ означало б, що кожен self-hoster отримує копію без можливості селективного відкликання.
Як це працює¶
Bubble — маленька floating action button: іконка Bug, червоне коло, bottom-right. Не блокує контент сторінки. Клацання відкриває висувну панель з 5 станами:
stateDiagram-v2
[*] --> form
form --> logging: Почати збір debug-логів
logging --> stopping: Зупинити та надіслати (або авто-стоп через 5 хв)
stopping --> submitting
submitting --> success
submitting --> error
error --> form: Retry
success --> [*]
form --> [*]: Cancel
Крок 1 — Форма¶
Три поля:
- Опис (обов'язково) — що пішло не так. Вільний текст.
- Email (опційно) — ваш email. Якщо вкажете, він піде у згорнутому блоці GitHub-issue body, щоб maintainer міг зв'язатися напряму. Без email відповіді на GitHub-issue вас не досягають.
- Скріншот (опційно) — вставка з буфера, drag-and-drop, або клік щоб вибрати файл. Зображення canvas-стискається до 1920px по найбільшій стороні + JPEG quality 0.7 перед uploadом — навіть 4K-скріншот вкладається в <1 МБ.
<details> блок під полями показує точно які дані в звіті, і які — ніколи (імена принтерів, серійні номери, IP, access-коди, паролі, email, API-ключі, токени, webhook-URL, hostnames, імена користувачів). Прочитайте перед надсиланням, якщо приватність важлива.
Крок 2 — Логування¶
Клацання Почати збір debug-логів і BamDude:
- Перемикає глобальний debug-log level на DEBUG (зберігаючи попереднє значення в
was_debugдля відновлення). - Шле свіжий status push на кожен підключений принтер через MQTT — щоб у логах був поточний снепшот стану принтерів від самого старту.
- Рендерить 3-крокевий progress indicator +
MM:SSmono lap-таймер.
Тепер відтворіть баг у іншій вкладці. Детальні логи захоплюються неперервно. Сесія авто-зупиняється через 5 хвилин як safety-cap — або клацніть Зупинити та надіслати раніше, коли вже відтворили потрібне.
Крок 3 — Зупинити та надіслати¶
Стоп робить:
- Тягне останні 200 санітизованих рядків логу (імена принтерів / серійники / IP / access-коди / cloud emails / імена користувачів зачищаються на сервері перед тим, як це покине ваш інстал).
- Повертає попередній log level (щоб DEBUG не лишався увімкнутим, якщо до цього він був OFF).
- Передає санітизовані логи + поля форми + скріншот у
POST /bug-report/submit, який кличе налаштований релей.
Крок 4 — Success¶
Релей створює GitHub-issue і повертає номер + URL. Панель показує Thank-You + клікабельне View Issue #N посилання. Все — можна закрити панель і працювати далі.
Крок 5 — Error¶
Якщо релей недоступний, повернув 5xx, або відкинув payload — панель показує загальне error-повідомлення + кнопку Retry (повертає на форму, щоб поправити опис/скріншот і спробувати знов). Кожна невдала спроба також пишеться в audit-таблицю bug_reports для діагностики.
Що санітизується¶
support_info payload будується server-side через _collect_support_info() і _get_recent_sanitized_logs() — обидва навмисне вузькі:
| Включено | Ніколи не включено |
|---|---|
| Версія застосунку | Імена принтерів |
| ОС / архітектура / версія Python | Серійні номери |
| Лічильники рядків БД (тільки лічильники) | IP-адреси |
| Моделі принтерів, кількість сопел, версії прошивки | Access-коди |
| Булеві з'єднання | Паролі |
| Статус інтеграцій (Spoolman, MQTT, Home Assistant) | Email-адреси |
| Нечутливі налаштування (log retention, тема) | API-ключі / токени |
| Кількість мережевих інтерфейсів (без IP) | Webhook URL |
| Деталі Docker (memory limit, network mode hint) | Hostnames |
| Версії залежностей | Імена користувачів |
Чутливі рядки тягнуться з живої БД у момент санітизації і замінюються плейсхолдерами [PRINTER], [SERIAL], [IP], [ACCESS_CODE], [USER], [EMAIL] у логах. Заміна відбувається в BamDude перед виходом payloadу — ні релей, ні GitHub ніколи не бачать оригіналів.
Одна редакція працює інакше: якщо ти логінишся через LDAP, Distinguished Name-и стають [DN]. DN — per-user і приходить із твого каталогу, тож у БД нема за чим його шукати — він упізнається за формою і прибирається всюди, де трапиться. Це важливо, бо провідний CN= — це справжнє ім'я користувача. Те саме правило діє для support bundle.
Rate limiting¶
Два рівні:
- Client-side, на BamDude-інстал — 5 звітів за годину. Лічильник в пам'яті, скидається при рестарті бекенду.
- На стороні релея, на IP — 10 звітів за годину за замовчуванням (конфігурується на релеї). За Cloudflare релей читає реальну IP з
CF-Connecting-IP, тож обмеження по справжньому клієнту, навіть якщо багато BamDude-інсталів ділять один outbound NAT.
Якщо упреться в ліміт — панель показує Rate limit exceeded; почекайте годину і повторіть.
Конфігурація¶
Одна змінна оточення на стороні BamDude:
| Змінна | Дефолт | Що робить |
|---|---|---|
BUG_REPORT_RELAY_URL |
https://bamdude.top/api/bug-report |
Куди bubble постить звіти. Поставте пустий рядок щоб повністю прибрати кнопку. Перевизначте на адресу свого релея якщо self-host. |
Жодної іншої конфігурації — gating через permissions: start-logging потребує settings:update, stop-logging і submit — settings:read. Дефолтні групи Operator + Admin мають обидва.
Self-host релея¶
Якщо публічний релей bamdude.top не підходить (offline-ферма, air-gapped LAN, недовіра до third-party) — можна підняти власний. Релей — ~150 LOC Fastify-сервіс, open source у репо kainpl/bamdude.top. relay/README.md веде через:
- Форму issue body (що шлеться в GitHub).
- Schema-валідацію.
- Knobs rate-limit'у.
- Папку для скріншотів + nginx-routing.
- systemd unit + hardening (NoNewPrivileges, ProtectSystem=strict тощо).
- Як згенерувати fine-grained GitHub PAT скопований лише на Issues одного репо.
Щоб використати свій релей — поставте BUG_REPORT_RELAY_URL=https://your-relay.example.com/api/bug-report на стороні BamDude і передеплойте. Bubble буде постити туди.
Мої репорти¶
У формі діалогу є розгортний список «Мої репорти» — усі звіти, надіслані з цього інсталу, найновіші зверху (до 50), кожен зі своїм поточним статусом і посиланням на GitHub-issue.
Статуси освіжаються в момент розгортання списку — через проксі релея POST /api/bug-report/status: GitHub-токен тримає релей, вашому інсталу свій не потрібен. Закриті звіти показуються як виправлено або не планується (GitHub-ове state_reason); звіт, що дійшов до термінального стану, більше не перепитується.
Якщо релей недоступний — список все одно рендериться з локальної таблиці з приміткою «показано останні відомі статуси»: застаріти можуть лише статуси, сам список завжди локальний.
Self-hosted релей
Самохостнутому релею теж потрібен статус-ендпоінт (POST /status поруч із submit) — без нього список працює, але статуси лишаються submitted.
Audit-таблиця¶
Кожна спроба надсилання — успішна чи провальна — пише один рядок у bug_reports:
| Колонка | Нотатки |
|---|---|
id |
PK. |
description |
Що оператор написав. |
reporter_email |
Опційно. |
github_issue_number / github_issue_url |
Виставляється на успіх. |
status |
Локально submitted / failed; освіжається зі стану GitHub-issue до open, closed (виправлено) чи not_planned щоразу, коли відкривається список «Мої репорти». |
error_message |
Виставляється на failed — код помилки релея, мережевий exception тощо. |
email_sent |
True коли GitHub-issue створене (назва колонки email_sent — legacy з upstream; зараз трекає створення issue, не літеральну доставку email). |
created_at |
UTC timestamp. |
Корисно для діагностики коли оператор каже "я надіслав звіт і отримав помилку" — query таблиці по created_at desc + status='failed' покаже захоплене повідомлення.
Траблшутинг¶
Bubble не з'являється
- Перевірте що
BUG_REPORT_RELAY_URLвстановлений (дефолт стріляє в runtime; bubble не рендериться якщо змінна явно пуста). - Bubble живе всередині
<Layout>— потрібен користувач на звичайній authenticated-сторінці. Setup-required gate (/setup) і login-сторінки Layout не рендерять.
Надсилання валиться з "Bug report relay is not available"
- Проблема на стороні релея. Або bamdude.top лежить, або ваша мережа його не дотягується, або релей вас rate-limit'ить. Перевірка:
curl -fsS https://bamdude.top/api/bug-report/health— має повернути{ok:true,repo:"kainpl/bamdude"}. - За жорстким outbound-проксі — дозвольте
bamdude.top:443.
Надсилання валиться з "Rate limit exceeded"
- Уперлися в per-instance ліміт 5/год. Зачекайте годину, або рестарт бекенду (лічильник у пам'яті, на старті чистий — корисно для тестування).
Issue створене, але maintainer не відповідає
- Додайте email у наступний звіт. Без контактного каналу issue анонімне і follow-up можна зробити лише через GitHub-issue безпосередньо.
Реалізація релея:
kainpl/bamdude.top→relay/.