Skip to content

feat(cot): keep out-of-scope people in a transmission chain, masked - #25

Draft
lbrunofidelis wants to merge 2 commits into
devfrom
feat/#43-masked-chain-nodes
Draft

lbrunofidelis wants to merge 2 commits into
devfrom
feat/#43-masked-chain-nodes

Conversation

@lbrunofidelis

@lbrunofidelis lbrunofidelis commented Sep 24, 2026 •

Copy link
Copy Markdown
Collaborator

PR atrelado

  • Frontend: mostra o nó mascarado com o ID visual no lugar do nome e não deixa abrir a pessoa. Sem esta API a cadeia do usuário restrito continua quebrada; sem o front o nó mascarado aparece sem rótulo e continua clicável.

Por que

Em Cadeias de transmissão, o usuário com restrição geográfica perdia as pessoas de fora da área dele. Um contato da área cujo caso de origem era de outro município aparecia como uma bolinha solta, e as cadeias ficavam menores e em outra quantidade do que as de um usuário sem restrição. O pedido é ver a cadeia inteira, sem os dados nominais de quem ele não pode ver, do mesmo jeito que a tela de relacionamentos já faz.

Causa

O montador de cadeias em common/controllers/outbreak.js aplicava a restrição geográfica aos relacionamentos e às pessoas antes de montar a cadeia. Quem estava fora do escopo era descartado, junto com as ligações, e a cadeia perdia a forma real.

O que muda

  1. common/models/relationship.js: a pessoa com nome retido passa a vir com masked: true junto dos campos de nome anulados.
  2. common/controllers/outbreak.js e common/models/relationship.js: a cadeia passa a ser montada com todos os relacionamentos e pessoas, e quem está fora do escopo do usuário é mascarado em vez de descartado (firstName, middleName, lastName e name nulos e masked: true), com os mesmos helpers que já mascaram os nomes nas listas de relacionamento. O resto dos dados da pessoa segue igual. Um filtro explícito por pessoa continua restringindo as cadeias como antes. Vale para a cadeia ao vivo, para os snapshots e para a contagem, que usam o mesmo montador.

Como validar

  1. Com um usuário restrito a um município, gerar a cadeia de transmissão do surto (ao vivo ou por snapshot).
  2. As pessoas de fora da área aparecem nas cadeias, ligadas aos relacionamentos, com os nomes nulos e masked: true.
  3. A quantidade de cadeias, os tamanhos e o número de ligações ficam iguais aos do admin.
  4. Com o admin, nada muda.

Validado

Mesma base, mesmo surto, cadeia ao vivo com contatos:

usuário versão cadeias tamanhos ligações nós mascarados mascarados com nome
admin dev 7 8, 5, 4, 4, 3, 2, 2 21 0 0
admin esta branch 7 8, 5, 4, 4, 3, 2, 2 21 0 0
restrito (teste2) dev 4 3, 3, 2, 2 6 0 0
restrito (teste2) esta branch 7 8, 5, 4, 4, 3, 2, 2 21 15 0
  • Snapshot e contagem dão os mesmos números da cadeia ao vivo para os dois usuários.
  • Filtro por primeiro nome começando com "Ana": os dois usuários recebem 1 cadeia de tamanho 3 com 2 ligações; para o restrito, o contato de fora da área continua ligado, sem nome e com masked: true.
  • Detalhe de ligação: o admin recebe os nomes como antes; o restrito recebe os nomes nulos e masked: true nas duas pontas fora do escopo.
  • eslint: outbreak.js sem achados. relationship.js só tem o linebreak-style que o arquivo inteiro já tem na dev (o arquivo usa CRLF e as linhas novas seguem o mesmo padrão).

Fora do escopo

  • Pessoas de fora da área que não têm nenhum relacionamento continuam fora da visão do usuário restrito, porque não fazem parte de cadeia nenhuma.
  • A entrega de segurança da aba de relacionamento (fix(api): deny out-of-scope single-record access to outbreak people #24) também grava masked em Relationship.maskPersonName. A mudança é a mesma nas duas branches; a que entrar por último precisa de um rebase simples.

Why (English)

In the transmission chains screen, a user restricted to a geographic area lost every out-of-scope person, so an in-scope contact whose source case lived elsewhere showed up as an isolated node and the chains differed in number and size from an unrestricted user's. The request is to see the whole chain without the nominal data of people the user may not see, the same way the relationship screen already works.

Root cause

The chain builder in common/controllers/outbreak.js applied the geographic restriction to relationships and people before building the chain, dropping out-of-scope people and their links.

What changes

  1. relationship.js: a person whose name was withheld carries masked: true.
  2. outbreak.js and relationship.js: chains are built from the full relationship and people set, and out-of-scope people are masked instead of dropped (firstName, middleName, lastName and name null, masked: true) with the same helpers that mask the relationship lists. An explicit person filter still narrows the chains. This covers live chains, snapshots and the chain count.

How to validate

As a restricted user, build the outbreak chains: out-of-scope people appear connected, with null names and masked: true, and the number and sizes of chains match the admin's. The admin sees no change.

Validated

On the same data the restricted user went from 4 chains (sizes 3, 3, 2, 2, 6 edges) to the admin's 7 chains (sizes 8, 5, 4, 4, 3, 2, 2, 21 edges) with 15 masked nodes and none carrying a name; the admin output is identical before and after. Snapshot, count, person filter and edge detail checks agree. eslint is clean apart from the file-wide CRLF linebreak-style findings that relationship.js already has on dev.

Out of scope

Out-of-scope people with no relationships stay hidden, since they belong to no chain. The relationship security pull request (#24) sets the same masked flag in Relationship.maskPersonName; whichever lands last needs a trivial rebase.

The front end needs to tell a person whose name was withheld apart
from one that genuinely has no name on file.
A geographic restriction dropped out-of-scope relationships and people
from a chain, so a restricted user saw false isolated nodes and chain
counts that differed from an unrestricted user.

Build the chain from the full relationship and people set and mask the
out-of-scope people with the relationship name masking helpers instead
of dropping them. An explicit person filter still narrows the chains.
This covers the live chain, snapshots and the chain count.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant