docs(plan2): inline production warnings (RLS+NULL tenant + empty IP allowlist)

CV.11 final code-review WARNING #1 + #3:
- RouteSupplierLeadJob::failed() — explicit note про elevated-role требование
  (failed_webhook_jobs RLS-policy блокирует INSERT с tenant_id=NULL без BYPASSRLS)
- SupplierWebhookController header — предупреждение про пустой allowlist в prod

Остальные 3 WARNING + 8 NIT отложены в Plan 3 NOTES.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Дмитрий
2026-05-10 20:08:11 +03:00
parent 9daa94d917
commit d5aa972730
2 changed files with 12 additions and 0 deletions
@@ -30,6 +30,12 @@ use Symfony\Component\HttpFoundation\IpUtils;
*
* Backward-compat: legacy /api/webhook/{token} (per-tenant) живёт параллельно
* на WebhookReceiveController не пересекается.
*
* ⚠️ PRODUCTION: пустой `supplier_ip_allowlist = '[]'` (или невалидный JSON,
* который `?: []` молча проглатывает) делает endpoint достижимым с любого IP
* только secret защищает. На prod admin ОБЯЗАН заполнить allowlist реальными
* IP/CIDR поставщика. Дополнительно: hash_equals на уровне `verifySecret`
* timing-safe только при равной длине; rate-limit per-IP добавится в Plan 3+.
*/
class SupplierWebhookController extends Controller
{
+6
View File
@@ -254,6 +254,12 @@ class RouteSupplierLeadJob implements ShouldQueue
* Сохраняет упавший job в `failed_webhook_jobs` (tenant_id=null sharing-flow,
* tenant ещё не определён на момент routing'а) для ручного разбора.
* supplier_lead.error апдейтится текстом исключения.
*
* ⚠️ PRODUCTION: failed_webhook_jobs имеет RLS-policy `tenant_isolation USING
* (tenant_id = current_setting('app.current_tenant_id')::bigint)`. INSERT с
* tenant_id=NULL под non-BYPASSRLS ролью молча отклонится (NULL = ::bigint NULL).
* Queue-worker обязан подключаться к БД под elevated-ролью (postgres / service-account
* с BYPASSRLS) ИЛИ нужен INSERT-policy WITH CHECK (true) на эту таблицу Plan 3+.
*/
public function failed(Throwable $e): void
{