[Fable 5][P3] PilotRequestModal: клиентская валидация слабее Pydantic-схемы — лид на лендинге получает сырой JSON 422 #1240

Closed
opened 2026-06-13 04:49:48 +00:00 by bot-backend · 0 comments
Collaborator

Из армейского ревью Claude Fable 5 (2026-06-11)

Confirmed by 2/2 адверсариальных верификатора, severity P3 (api-contract), confidence 0.7.

Файл

frontend/src/components/landing/PilotRequestModal.tsx:66

Evidence (цитата кода)

if (!form.name.trim()) return;
if (form.email && !EMAIL_RE.test(form.email)) {
  setEmailError("Некорректный email");
  return;
}

Why bug

Backend PilotRequestInput требует name min_length=2, phone ≤50, company ≤200 (backend/app/api/v1/pilot.py:26-32), а форма проверяет только непустое name и не ставит minLength/maxLength на name/phone/company. Имя из 1 символа или вставленная длинная строка проходит на клиенте → 422, и в окне ошибки рендерится mutation.error.message = «API error 422: {"detail":[{"type":"string_too_short"...}]}» (apiFetch кладёт сырой body в Error). Публичная лид-форма показывает технический JSON вместо понятного сообщения — лид теряется.

Suggested fix

Зеркалировать ограничения схемы (minLength={2} на name, maxLength на phone/company/name) и/или маппить 422 в дружелюбный текст вместо raw error.message.

Verify notes

  • [real/P3] Трасса: имя «Я» (1 символ) проходит клиентскую проверку line 66 (только !form.name.trim(); форма noValidate, нет minLength/maxLength на name/phone/company) → backend Field(min_length=2) даёт 422 → apiFetch (api.ts:39) кладёт сырой body в Error.message → модалка рендерит mutation.error.message verbatim: «API error 422: {"detail":[{"type":"string_too_short"...}]}». То же для phone >50 симв. P3: edge-ввод, форма восстановима, но публичная лид-форма кажет сырой JSON.
  • [real/P3] Цепочка подтверждена кодом: клиент проверяет только !form.name.trim() (форма noValidate, без minLength/maxLength), бэкенд требует name min_length=2, phone≤50, company≤200; кастомного 422-хендлера нет. useSubmitPilotRequest использует apiFetch, который кладёт сырой response.text() в Error.message, и модалка рендерит его как есть. Имя из 1 символа активирует кнопку и даёт лиду сырой JSON. «Лид теряется» преувеличено (можно исправить и переотправить), message выровнен (maxLength=2000) — потому P3.

Provenance

  • Finders: fe-rest
  • Confidence: 0.7
  • Originally batched at: main@d796027
## Из армейского ревью Claude Fable 5 (2026-06-11) Confirmed by 2/2 адверсариальных верификатора, severity **P3** (api-contract), confidence 0.7. ## Файл [`frontend/src/components/landing/PilotRequestModal.tsx:66`](frontend/src/components/landing/PilotRequestModal.tsx:66) ## Evidence (цитата кода) ``` if (!form.name.trim()) return; if (form.email && !EMAIL_RE.test(form.email)) { setEmailError("Некорректный email"); return; } ``` ## Why bug Backend PilotRequestInput требует name min_length=2, phone ≤50, company ≤200 (backend/app/api/v1/pilot.py:26-32), а форма проверяет только непустое name и не ставит minLength/maxLength на name/phone/company. Имя из 1 символа или вставленная длинная строка проходит на клиенте → 422, и в окне ошибки рендерится mutation.error.message = «API error 422: {"detail":[{"type":"string_too_short"...}]}» (apiFetch кладёт сырой body в Error). Публичная лид-форма показывает технический JSON вместо понятного сообщения — лид теряется. ## Suggested fix Зеркалировать ограничения схемы (minLength={2} на name, maxLength на phone/company/name) и/или маппить 422 в дружелюбный текст вместо raw error.message. ## Verify notes - [real/P3] Трасса: имя «Я» (1 символ) проходит клиентскую проверку line 66 (только !form.name.trim(); форма noValidate, нет minLength/maxLength на name/phone/company) → backend Field(min_length=2) даёт 422 → apiFetch (api.ts:39) кладёт сырой body в Error.message → модалка рендерит mutation.error.message verbatim: «API error 422: {"detail":[{"type":"string_too_short"...}]}». То же для phone >50 симв. P3: edge-ввод, форма восстановима, но публичная лид-форма кажет сырой JSON. - [real/P3] Цепочка подтверждена кодом: клиент проверяет только !form.name.trim() (форма noValidate, без minLength/maxLength), бэкенд требует name min_length=2, phone≤50, company≤200; кастомного 422-хендлера нет. useSubmitPilotRequest использует apiFetch, который кладёт сырой response.text() в Error.message, и модалка рендерит его как есть. Имя из 1 символа активирует кнопку и даёт лиду сырой JSON. «Лид теряется» преувеличено (можно исправить и переотправить), message выровнен (maxLength=2000) — потому P3. ## Provenance - Finders: `fe-rest` - Confidence: 0.7 - Originally batched at: main@d796027
bot-backend added the
Fable 5 ревью
label 2026-06-13 04:49:48 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#1240
No description provided.