Files
SQS-service/doc/thinking/my-analysis-of-opus-report-2026-10-05.md
T

92 lines
7.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Критический анализ отчёта Opus (мой разбор, 2026-10-05)
> Кем: я (DeepSeek). Что: критический разбор отчёта Opus
> (`opus-report-2026-10-05.md`) по архитектуре shared-sqs.
> Метод: ключевые утверждения Опуса перепроверялись по коду напрямую, а не
> принимались на веру. Источники — «файл:строка».
---
## Что я перепроверил по коду (факты)
| Утверждение Опуса | Вердикт | Источник в коде |
|---|---|---|
| P0.1: SecretKey детерминирован из email + соль в исходнике | ✅ подтверждено | `tenant_store.go:289-292` `secretKeyFromEmail` = `SHA256(lower(email)+":shared-sqs:secret-key:v1")`; соль — константа `secretKeySalt` (`tenant_store.go:286`); `accessKeyFromEmail` = `SHA256(email)[:12]` |
| P0.2: JWT без проверки подписи, доверие на PingNubesAPI | ✅ подтверждено | `jwt.go` — парсинг структуры + `exp`; `PingNubesAPI` принимает, если хоть один стенд не 401/403 |
| Кэш: отозванный токен живёт до ~7 мин | ✅ подтверждено | `cache.go`: `cacheTTL=5m`, `cacheGraceTTL=2m` |
| Глобальный мьютекс на весь сервис | ✅ подтверждено | `globals.go:20-23` — один `SyncQueues.RWMutex` + `Queues map[string]*Queue` |
| Сиротство очередей при пересчёте legacy-тенанта | ✅ подтверждено | `tenant_store.go:202-205` — комментарий в коде сам это описывает |
| MessageRetentionPeriod не реализован | ✅ подтверждено | `models.go` — `// TODO - not used` |
Ложных утверждений не найдено.
---
## Сильные стороны отчёта
1. **P0.1 — самая ценная находка.** Детерминированный вывод SecretKey из
публичного email — реальный, доказуемый по коду дефект. Указан не только
механизм, но и точные функции. Именно это реально блокирует «готовность SQS».
2. **Верно разделены SigV4 и JWT.** SigV4 проверяется полноценно
(`auth_middleware.go`: canonical request, `subtle.ConstantTimeCompare`,
clock skew, presigned); JWT — нет. Большинство поверхностных ревью их путают.
3. **Классификация P0/P1/P2 адекватна** — безопасность+durability отделены от
масштабируемости и гигиены.
4. **Пункты 3–7** (глобальный лок, SPOF, async-Redis, нет RetentionPeriod,
плоский слайс) — архитектурно точны.
5. **Раздел «противоречия док↔код» конкретен** (особенно №1: док про
`sub`/`bySub`/`sless-`, код про `email`/`byEmail`/`t-`).
---
## Слабые места и оговорки
1. **P0.2 переоценён как самостоятельный «критичный».** Вектор «подмена email
→ доступ» опасен **только в связке с P0.1**: неверный email даёт чужие креды,
потому что креды детерминированы из email. Исправь P0.1 (случайные креды в
Redis) — и неверный email из JWT уже не даст чужих ключей, только
провиженинг под чужим именем (менее критично). Опус не связал P0.1 и P0.2
явно, хотя атака работает попарно. Стоит оформить как один инцидент.
2. **П.4 «SPOF/нет горизонтального масштабирования»** — справедливо
архитектурно, но сервис и проектировался single-instance managed
HTTP-контейнером (README). Это осознанное ограничение, а не баг. В разряд
«высокого риска сейчас» ставить преждевременно — это долгосрочная
архитектурная развилка, а не текущий блокер.
3. **П.5 (async-Redis = потеря подтверждённых сообщений) — полуверно.**
Сообщение в памяти уже есть (клиент получил 200 = сообщение в памяти,
источнике правды). Теряется только при краше пода **до** async-`HSet`, и
только это узкое окно. Окно реально, но «нарушение durability» подано
сильнее, чем есть: теряются не все сообщения, а только при краше в окне.
4. **П.10 (timing side-channel admin-токена)** — технически верно, но admin-токен
приходит как высокоэнтропийный bearer; практическая эксплуатируемость timing-атаки
через сеть у одного короткого сравнения ничтожна. Формально в P2 и есть, но
вес в подаче чуть завышен.
5. **П.14 (`/metrics` публичен)** — стоит оговорка: лейбл `tenant` = tenantID
(`t-...`), а НЕ SecretKey. Утечка реальна (число очередей/сообщений по
тенанту), но это не утечка кредов. Формулировка корректна, но без оговорки
читается страшнее.
6. **Пробел контекста (не ошибка Опуса, а следствие моего allowlist-запрета):**
отчёт не отделяет «код-блокировку» от «платформенной блокировки» — периодические
таймауты ~31–33с и MSS-баг для тел >~1400 байт (разобрано в
`doc/thinking/nubes-ticket.md`). Даже идеальный код их не уберёт. Итоговый
вывод о «готовности SQS» надо читать с этой поправкой.
---
## Итоговая оценка
Отчёт — **добротный, по фактам точный**. Из 16 пунктов рисков ложных нет;
спорные — только **вес/приоритет**:
- P0.2 связать с P0.1 (один инцидент);
- п.4 (SPOF) и п.10 (timing) слегка переоценены для текущей single-instance роли.
Главная ценность: **P0.1 (детерминированный SecretKey)** — подтверждённый по
коду блокер готовности, который до этого так жёстко не формулировался.
Единственный реальный пробел — платформенный контекст (таймауты/MSS), но он
возник из моего же allowlist и устраняется дополнением, не исправлением.