fix(seguranca): fechar os 19 gaps de tenant_id - #31
Merged
Conversation
A varredura do PR #28 mapeou 19 consultas a colecoes de tenant sem filtro de organizacao. Nao vazavam leitura no uso normal (o id costuma vir de documento ja filtrado), mas aceitavam um id de outra organizacao chegando pela URL - faltava defesa em profundidade. Corrigidos por arquivo, nao em lote, conforme o plano: ESCRITAS (as mais graves - permitiam alterar dado de outro tenant) - activity: contador de views de KB - review: agendamento e conclusao de revisao (2x) - postmortem: atualizacao do documento - smart-search: atualizacao de solicitacao de KB - webhooks: estatisticas de entrega LEITURAS - gps: fluxo lido a partir da sessao (3x) - gamification: 10 consultas. Aqui havia dois problemas distintos - calculateUserStats nem recebia tenantId (agora recebe, e sem valor padrao de proposito: um default silencioso reintroduziria o bug), e checkAndAwardBadges ja recebia mas nao usava nas queries. O baseline KNOWN_GAPS ficou vazio: a catraca agora falha em qualquer consulta nova sem tenant_id, sem excecoes herdadas. Novos casos legitimos devem ir para ALLOWED_EXCEPTIONS com o motivo escrito.
Contributor
There was a problem hiding this comment.
Pull request overview
Este PR fecha os “gaps” de isolamento multi-tenant identificados pelo detector (PR #28), adicionando tenant_id aos filtros de consultas/escritas em coleções tenant-scoped e deixando o baseline (KNOWN_GAPS) vazio para que o teste passe a falhar para qualquer regressão futura.
Changes:
- Adiciona
tenant_id: request.tenantIdemupdateOne/findOne/countDocumentsque antes aceitavam_id/created_bysem escopo de tenant. - Ajusta Gamificação para receber
tenantIdemcalculateUserStatse usartenant_idnas queries. - Zera
KNOWN_GAPSno testetenant-isolationpara ativar a “catraca” sem exceções herdadas.
Reviewed changes
Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| backend/tests/tenant-isolation.test.js | Baseline KNOWN_GAPS agora vazio; mantém a “catraca” para novos gaps. |
| backend/src/modules/activity/activity.routes.js | Escopa update do contador de views de KB por tenant_id. |
| backend/src/modules/review/review.routes.js | Escopa updates de agendamento/conclusão de review por tenant_id. |
| backend/src/modules/postmortem/postmortem.routes.js | Escopa update do post-mortem por tenant_id. |
| backend/src/modules/smart-search/smart-search.routes.js | Escopa update de kb_requests por tenant_id. |
| backend/src/modules/gps/gps.routes.js | Escopa leituras de gps_flows por tenant_id. |
| backend/src/modules/gamification/gamification.routes.js | Escopa contagens/queries de stats e badges por tenant_id. |
| backend/src/modules/webhooks/webhooks.routes.js | Escopa update de estatísticas de webhook por tenant_id (mas há um bug de escopo a corrigir). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
466
to
469
| await db.collection('webhooks').updateOne( | ||
| { _id: webhook._id }, | ||
| { _id: webhook._id, tenant_id: request.tenantId }, | ||
| { $inc: statsUpdate } | ||
| ); |
This was referenced Aug 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
O que resolve
A varredura criada no PR #28 mapeou 19 consultas a coleções de tenant sem filtro de organização. Elas não vazavam leitura no uso normal — o id costuma vir de um documento já filtrado — mas aceitavam um id de outra organização chegando pela URL. Faltava defesa em profundidade.
Corrigidos por arquivo, não em lote, conforme o plano definido quando a lista foi congelada.
Escritas (as mais graves — permitiam alterar dado de outro tenant)
activityreview(2x)postmortemsmart-searchwebhooksExemplo — antes um
recordIdde outra organização passado no corpo alterava a data de revisão do KB alheio:Leituras
GPS (3x): fluxo lido a partir da sessão, agora filtrado.
Gamificação (10x): aqui havia dois problemas distintos, e vale destacar o segundo:
calculateUserStatsnem recebiatenantId. Agora recebe — e sem valor padrão de propósito: umtenantId = nullsilencioso reintroduziria exatamente o bug na próxima vez que alguém chamasse a função sem o argumento.checkAndAwardBadgesjá recebiatenantIdna assinatura, mas não usava em nenhuma das queries. O parâmetro estava lá dando falsa impressão de que o escopo era respeitado.O baseline ficou vazio
KNOWN_GAPSagora énew Set([]). A catraca passa a falhar em qualquer consulta nova semtenant_id, sem exceções herdadas — que era o objetivo desde o começo. Casos legítimos futuros devem ir paraALLOWED_EXCEPTIONScom o motivo escrito, não de volta para a lista de gaps.Test plan
npm test→ 25 passam, com o baseline vazionode --checkem todos os arquivos alterados