harden(edge): MessageSchema sender/content obrigatórios (E1)#92
Conversation
Atende finding 🟠 Major do CodeRabbit no PR #91: MessageSchema aceitava {} vazio, deixando entrar payload sem conteúdo nas rotas de IA via cascata em AiConversationAnalysisSchema e AiConversationSummarySchema. Mudança: - sender: agora obrigatório, .min(1) (não-vazio) - content: agora obrigatório (campo presente), .max(5000) mantido, mas SEM .min(1) — content vazio é legítimo em produção (16.9% das mensagens reais: imagens/áudios/documentos sem caption) Validado em 23 cenários (stress test exaustivo) + cruzamento com 672.003 mensagens reais do banco. Refs: PR #91 review comment r3210444961 Source: PR-FUTURO-E1 em /workspace/notes/pr-futuro-e-schemas-hardening.md
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
WalkthroughMessageSchema no módulo de schemas compartilhado torna sender e content campos obrigatórios em vez de opcionais, adicionando validação de string não-vazia para sender com mensagem de erro explícita. ChangesValidação de Campos Obrigatórios
Estimated code review effort🎯 2 (Simples) | ⏱️ ~3 minutos Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Pull request overview
This PR hardens the shared Edge Function Zod MessageSchema used by AI-related endpoints so that empty message objects (e.g. {}) are rejected and no longer count toward .min(5) constraints in conversation summary/analysis schemas.
Changes:
- Made
senderrequired and non-empty (min(1)+max(50)). - Made
contentrequired (still allows empty string) withmax(5000).
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| export const MessageSchema = z.object({ | ||
| sender: z.string().max(50).optional(), | ||
| content: z.string().max(5000).optional(), | ||
| sender: z.string().min(1, "sender is required").max(50), |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@supabase/functions/_shared/schemas.ts`:
- Around line 16-17: The sender field currently uses z.string().min(1) which
allows strings of only whitespace; normalize the input by trimming before
applying length rules so whitespace-only values fail. Update the sender schema
(the symbol "sender" defined with z.string().min(1,...).max(50)) to trim the
string first (e.g., via .transform(s => s.trim()) or zod's trimming helper) and
then apply min(1, "sender is required") and max(50) so empty or whitespace-only
senders are rejected.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: b4bf87b4-0324-4650-bbbb-dfcb6a138915
📒 Files selected for processing (1)
supabase/functions/_shared/schemas.ts
| sender: z.string().min(1, "sender is required").max(50), | ||
| content: z.string().max(5000), |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
No Zod v3.23.8, z.string().min(1) considera " " (somente espaços) válido sem .trim()?
💡 Result:
Sim, no Zod v3.23.8, z.string.min(1) considera " " (somente espaços) como válido, pois o método min verifica o comprimento da string usando.length, que conta espaços em branco como caracteres. Espaços não são removidos automaticamente sem usar.trim.[1][2][3] A documentação oficial confirma que.min(5) aceita "hello" (5 chars) mas rejeita "hi" (2 chars), e.nonempty é equivalente a.min(1).[1][4] GitHub issues discutem explicitamente que min e max contam espaços: um usuário reclamou que espaços são contados, e a resposta oficial confirma que isso é intencional, pois muitos dependem disso, sugerindo transform para ignorar espaços se necessário.[2] Para rejeitar strings só com espaços, use z.string.trim.min(1).[3][5][6] Nenhuma mudança no comportamento de string.min aparece nos changelogs de v3.23.x.[7][8]
Citations:
- 1: https://mintlify.com/colinhacks/zod/api/primitives/string
- 2: Min and max use spaces and characters. colinhacks/zod#2088
- 3: z.string() validates empty strings colinhacks/zod#2466
- 4: https://zod.dev/api
- 5: https://stackoverflow.com/questions/77594561/how-to-remove-whitespace-from-within-a-string-using-zod
- 6: https://stackoverflow.com/questions/77134910/how-can-i-remove-all-whitespace-in-zod
- 7: https://github.com/colinhacks/zod/releases/tag/v3.23.8
- 8: https://github.com/colinhacks/zod/releases/tag/v3.23.0
sender pode passar vazio com somente espaços em branco.
Na linha 16, z.string().min(1) aceita strings contendo apenas espaços (e.g. " "), pois min() conta espaços como caracteres válidos. Isso contorna a validação de obrigatoriedade do remetente. Normalize a string antes da validação:
Diff
- sender: z.string().min(1, "sender is required").max(50),
+ sender: z.string().trim().min(1, "sender is required").max(50),📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| sender: z.string().min(1, "sender is required").max(50), | |
| content: z.string().max(5000), | |
| sender: z.string().trim().min(1, "sender is required").max(50), | |
| content: z.string().max(5000), |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@supabase/functions/_shared/schemas.ts` around lines 16 - 17, The sender field
currently uses z.string().min(1) which allows strings of only whitespace;
normalize the input by trimming before applying length rules so whitespace-only
values fail. Update the sender schema (the symbol "sender" defined with
z.string().min(1,...).max(50)) to trim the string first (e.g., via .transform(s
=> s.trim()) or zod's trimming helper) and then apply min(1, "sender is
required") and max(50) so empty or whitespace-only senders are rejected.
Contexto
Atende finding 🟠 Major do CodeRabbit no PR #91 (comment r3210444961):
Mudança
senderz.string().max(50).optional()z.string().min(1, "sender is required").max(50)contentz.string().max(5000).optional()z.string().max(5000)(obrigatório existir, mas pode ser vazio)created_atz.string().optional()message_typez.string().max(50).optional()Diff: +2 / -2 linhas, 1 arquivo.
Por que
contentNÃO recebeu.min(1)(revisão importante do plano original)Investigação no banco real (672.003 mensagens em 90 dias) mostrou que
contentvazio é legítimo em 16.9% das mensagens (113.677 ocorrências):imageaudiodocumentvideostickertextForçar
content.min(1)quebraria o frontend ao montar arrays de mensagens paraai-conversation-summary/ai-conversation-analysisquando incluísse imagens/áudios sem caption.Validação
✅ 23 cenários de stress-test — todos com comportamento esperado.
✅ Banco real:
sendervazio = 0 ocorrências em 30 dias.✅ Callers frontend (verificados):
AISuggestions.tsx→ ai-suggest-reply:{content, sender}✓ConversationSummary.tsx→ ai-conversation-summary:{sender, content, created_at}✓AIConversationAssistant.tsx→ ai-conversation-analysis:{id, sender, content, type, created_at}✓AIAutoTagsConfig.tsx→ ai-auto-tag: não enviamessages(optional no schema pai)Risco
🟢 Zero. Rejeita só o que era inválido (
{}vazio). Aceita 100% das 672k mensagens reais validadas.Referências
/workspace/notes/pr-futuro-e-schemas-hardening.mdSummary by CodeRabbit
Notas de Versão