From 4c24c6351c0a078ce538b325695f991029e40c69 Mon Sep 17 00:00:00 2001 From: Repinoid Date: Sun, 11 Oct 2026 20:23:32 +0300 Subject: [PATCH] =?UTF-8?q?docs(history):=20=D1=80=D0=B0=D1=81=D1=88=D0=B8?= =?UTF-8?q?=D1=80=D0=B5=D0=BD=D0=BD=D1=8B=D0=B9=20=D0=BF=D1=80=D0=BE=D0=B3?= =?UTF-8?q?=D0=BE=D0=BD=20PASS=3D49=20KNOWN=3D1=20=E2=80=94=20=D0=B4=D0=B5?= =?UTF-8?q?=D0=B4=D1=83=D0=BF=20=D0=BF=D0=BE=20=D1=81=D0=BE=D0=B4=D0=B5?= =?UTF-8?q?=D1=80=D0=B6=D0=B8=D0=BC=D0=BE=D0=BC=D1=83,=20=D0=B2=D0=B0?= =?UTF-8?q?=D0=BB=D0=B8=D0=B4=D0=B0=D1=86=D0=B8=D1=8F=20namespace=20=D1=82?= =?UTF-8?q?=D0=BE=D0=BB=D1=8C=D0=BA=D0=BE=20=D0=B2=20POST?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- HISTORY/2026-10-11-session-log.md | 35 +++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/HISTORY/2026-10-11-session-log.md b/HISTORY/2026-10-11-session-log.md index 1e37d2d..f9636cf 100644 --- a/HISTORY/2026-10-11-session-log.md +++ b/HISTORY/2026-10-11-session-log.md @@ -227,3 +227,38 @@ consumer → per-tenant PostgreSQL → HTTP API. Вывод: auth (bcrypt из PG), ACL (own-topic only, disconnect на нарушение), tenant-изоляция API (`namespace == sub`), проверка подписи JWT и дедуп повторов — работают на развёрнутом стенде. + +## 10. Расширенный прогон — PASS=49 FAIL=0 KNOWN=1 (2026-10-11) + +Скрипт `/tmp/e2e_suite.py` (~50 проверок на развёрнутом стенде). + +**Что покрыто:** CRUD устройств (201/409/400/404/204) · лимиты идентификаторов +(name/device_id 64 → 201, 65 → 400; namespace 56 → 201, 57 → 400) · пагинация +(limit/offset, потолок 1000) · JWT (без токена 401, `sub`≠namespace 403, чужой +ключ 401, истёкший 401, не-HS256 401) · MQTT (SUBACK на свой топик, round-trip, +QoS1 → PUBACK, PINGRESP) · ACL-отказы с разрывом соединения (чужое устройство, +wildcard, чужой namespace, 11 уровней топика при `max_topic_levels=10`, retained +при `retain_available=false`, subscribe на `+/telemetry/+` и чужой ns) · +payload (не-JSON → строка, 200 КБ → доставлен, 20 сообщений подряд → 20/20) · +служебное (`/health`, `/healthz`, `/ready`, `/console`, `/iot-admin`, `/` = 200; +`POST /health` = 405; `/iot-admin/stats` без токена 401). + +**Найдено/подтверждено (требует решения):** + +1. 🟡 **Дедуп — по СОДЕРЖИМОМУ.** `message_id = SHA256(ns|device_id|topic|payload)` + (`bridge/handler.go:73`), поэтому два одинаковых payload подряд дают +1 строку + (проверено: 49→50). Для реальных устройств это значит: если payload не содержит + timestamp/счётчика, легитимные повторные одинаковые показания будут отброшены. + Надо предупредить в документации для устройств (или включать ts в payload). +2. 🟡 **Валидация namespace только в POST.** `validateIdentifier(ns, "namespace", 56)` + вызывается только в `CreateIoTDevice` (`devices.go:168`); `GET/DELETE/PATCH` + принимают любой ns → `200` (проверено: `GET /v1/namespaces/bad_ns/iot/devices` → 200). + Хранилище такой ns отсекает (`safeNamespaceRe`), поэтому чтение телеметрии + отдаёт `500` вместо `400`. Утечки нет (изоляция по `sub`), но реакция + несогласованная — вынести проверку в общий middleware/хелпер. +3. ⚪ `Dockerfile` (комментарий) обещает `/metrics` на порту API — маршрута нет (404). +4. ⚪ Чтение телеметрии `?limit=200` возвращает payload'ы целиком (в тесте — 200 КБ + на запись); при массовом опросе API ощутимо тормозит (наблюдалось на 200m CPU). + +Методическая заметка: при повторных прогонах тесты «доставки» надо делать с +уникальным payload, иначе срабатывает дедуп и тест ложно падает.