Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
# CSRF). Loopback e APP_HOST sempre valem. "*" desliga a checagem (não recomendado). Ex.: sentry.intranet
# ALLOWED_HOSTS=

# --- PII policy / Política de dados pessoais (docs/catalogo-pii.md) --------------------------------
# cpf_endereco (default/padrão) | lgpd_publicacao | lgpd_interno | gdpr | saude_hipaa
# POLICY_PROFILE=cpf_endereco

# --- Local decision model / Decisor local (optional, docs/decisions.md) ------------------------
# Requires / Exige: pip install -e ".[laya]"
# DECISION_ENGINE=off # laya | off
Expand Down Expand Up @@ -49,7 +53,7 @@
# --- PDF -> image conversion (phase 0) / Conversão PDF -> imagem ---------------
# Rendering DPI for full-page OCR. Higher = better small text, slower and heavier.
# DPI de renderização para o OCR da página inteira. Maior = melhor p/ texto pequeno, porém mais lento.
# BASE_DPI=1000
# BASE_DPI=300

# --- OCR (Tesseract) -----------------------------------------------------------
# Path to the tesseract binary if it is not on PATH. / Caminho do executável se não estiver no PATH.
Expand Down
9 changes: 6 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ em documentos. O único produto existente é o **SENTRY Redact**: um pipeline qu
**endereços pessoais** em PDFs (OCR Tesseract + detector YOLO de assinaturas + LLM de visão via Ollama),
sugere tarjas, verifica a saída e só gera o PDF final depois da revisão humana num editor web.

Os módulos SENTRY Detect, Mask/Transform, Gateway e Audit são **visão**, não código: não os descreva como
existentes em documentação, interface ou mensagens.
**SENTRY Detect** existe em parte: catálogo de PII, perfis de política e detectores por regra (`utils/detect/`).
Nomes, rostos e dados sensíveis estão no catálogo como *planejados*; não os descreva como detectados.
Os módulos Mask/Transform, Gateway e Audit são **visão**, não código: não os descreva como existentes.

## 2. Invariantes (não negociáveis)

Expand Down Expand Up @@ -62,6 +63,7 @@ Navegador ─► gatekeeper.py (:8000, opcional) ─proxy─► app_service.py (
| `utils/session.py` | Pastas da tarefa, logs, exportação, reconstrução do PDF e tarja nativa (`apply_native_pdf_redactions`) |
| `utils/verifier.py` | Verificação pós-tarja: relê o PDF final e confronta o original (`find_uncovered_cpfs`) |
| `utils/pii.py` | Mascaramento de CPF em logs |
| `utils/detect/` | SENTRY Detect: catálogo de PII com enquadramento legal (`catalog.py`), perfis de política (`profiles.py`, `POLICY_PROFILE`), detectores por regra (`rules.py`) e dígitos verificadores (`validators.py`). Pacote isolado, com contrato JSON (API `/policy/*`), pronto para virar serviço. `docs/catalogo-pii.md` é gerado: `python -m utils.detect --markdown` |
| `utils/decisions/` | Decisor local (Laya) e automelhoramento: perguntas, motor, regra de combinação, treino com portão de qualidade e versões. Guia: [docs/decisions.md](docs/decisions.md) |
| `utils/auth.py` | Autenticação por `API_TOKEN` com sessão aleatória (app e gatekeeper): `?token=` só abre a sessão e sai da URL |
| `utils/net_guard.py` | Checagem de `Host`/`Origin` (anti *DNS rebinding* e CSRF) usada pelo app e pelo gatekeeper; `ALLOWED_HOSTS` |
Expand All @@ -78,7 +80,8 @@ Navegador ─► gatekeeper.py (:8000, opcional) ─proxy─► app_service.py (
- **README da interface.** O botão *Documentação* do editor mostra o `README.md` da raiz pelo renderizador
local (`GET /readme`). Ele não interpreta HTML: as linhas HTML do topo aparecem como texto. Isso é
proposital (ver `test_readme_renderer_is_local_and_escapes_html`); não troque por `innerHTML`.
- **`BASE_DPI` padrão é 1000.** Ótimo para texto miúdo, caro em RAM e tempo. Os testes usam valores menores.
- **`BASE_DPI` padrão é 300** (era 1000 até a 5.3.0). Medido: acima de 300 o Tesseract fragmenta os dígitos e a revocação de CPF cai (docs/benchmarks.md). Não suba o padrão sem rodar o benchmark.
- **OCR em paralelo.** As páginas passam pelo OCR em threads (`ocr_workers`). Detecte falha do Tesseract com `OCREngine.thread_failures()` (por thread), nunca com o contador global, senão a falha de uma página é atribuída a outra. As duas passadas (padrão + esparsa) são mantidas de propósito.
- **Artefatos com dados pessoais.** `output/`, `WEB_INPUT/`, `documentos_finais/` e `tasks.json` estão no
`.gitignore` e nunca devem ser versionados.
- **Licenças AGPL.** PyMuPDF e Ultralytics são AGPL-3.0; novas dependências precisam de justificativa e
Expand Down
11 changes: 6 additions & 5 deletions BACKLOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ leia o [AGENTS.md](AGENTS.md): invariantes, arquitetura e como rodar os testes.
**P2** (robustez, operação e experiência) · **P3** (melhoria e refatoração).
- Itens marcados como **visão** vêm do roteiro do produto: não têm data nem promessa de entrega.
- As referências `arquivo:linha` valem para o estado de referência e podem se deslocar.
- Estado de referência: `5.3.0`, 2026-10-04. Itens B-40 a B-65 vieram de uma revisão completa do código e da redação do manual nessa data.
- Estado de referência: `5.4.0`, 2026-10-04. Itens B-40 a B-65 vieram de uma revisão completa do código e da redação do manual nessa data.

## Resumo

| Prioridade | Abertos | Foco |
|---|---|---|
| 🔴 P0 | 0 | Proteger o serviço local contra outros sites no mesmo navegador e o token de acesso |
| 🟠 P1 | 13 | Falhar fechado em mais situações (OCR, respostas da IA, tarjas manuais, rotação) |
| 🟡 P2 | 11 | Robustez dos processos, limites de recursos, Docker e editor |
| 🟡 P2 | 10 | Robustez dos processos, limites de recursos, Docker e editor |
| 🔵 P3 | 5 | Limpeza de código, lint e marca |
| 🧠 Roteiro | 9 | Detecção configurável (nomes, telefones, RG...), GLiNER e decisor Laya que aprende (B-71 a B-79) |
| 🔭 Visão | 5 | Auditoria, políticas e novos módulos SENTRY |
Expand Down Expand Up @@ -52,8 +52,8 @@ Arquitetura: `detectar (regras + GLiNER + LLM) → decidir (Laya) → revisão

| ID | Prioridade | Item | Depende de |
|---|---|---|---|
| B-71 | P1 | **Política configurável**: o usuário escolhe os tipos (CPF, endereço, nome, telefone, e-mail, RG...) na interface e na CLI; arquivo de política versionado; registrar qual política foi aplicada em cada tarefa | — |
| B-72 | P1 | **Novos tipos por regras com validação**: RG, CNH, PIS/NIS, título de eleitor, telefone, e-mail, CEP, placa, cartão (dígito verificador quando houver), com testes e casos falsos positivos conhecidos | B-71 |
| B-71 | P1 | **Política configurável — parte 1 concluída (5.4.0):** catálogo com enquadramento legal, 5 perfis via `POLICY_PROFILE`, rótulo do tipo em cada tarja, resumo por documento, API `/policy/*`. **Falta:** escolher o perfil na interface e por tarefa, e registrar a política aplicada num relatório exportável | — |
| B-72 | P1 | **Concluído (5.4.0):** RG, CNH, título de eleitor, PIS/NIS, CNS, passaporte, CTPS, telefone, e-mail, IP, cartão (Luhn), conta bancária, chave Pix, data de nascimento e placa, com dígito verificador, formato ou contexto (`tests/test_detect.py`). **Falta:** medir revocação por tipo em documentos fictícios realistas e estender a verificação pós-tarja a esses tipos | B-71 |
| B-73 | P1 | **Nomes e rótulos livres com GLiNER** (modo leve na CPU): o usuário escreve o rótulo ("nome de pessoa", "número de processo"); trechos mapeados para as caixas do OCR; confiança baixa → revisão | B-71 |
| B-74 | P2 | **Exceções decididas pelo Laya**: "nome a proteger" × "servidor/signatário público" (LAI), com perguntas próprias, treino e portão | B-73, B-70 |
| B-75 | P2 | **Perfis de política e roteamento**: perfis prontos (Transparência/LAI, Saúde, Jurídico, Só CPF) e o Laya sugerindo o perfil pelo tipo de documento | B-71, B-70 |
Expand Down Expand Up @@ -97,7 +97,6 @@ Arquitetura: `detectar (regras + GLiNER + LLM) → decidir (Laya) → revisão
| B-65 | **Expor na interface a remoção das imagens originais** (`POST /purge/{id}`), hoje só pela API | `app_service.py:420-429` |
| B-10 | Tarja nativa: remover ou sinalizar metadados, anexos, anotações, campos de formulário e camadas ocultas que sobrevivem à tarja | [docs/limitations.md](docs/limitations.md) (Saída) |
| B-11 | Aviso na interface quando `OLLAMA_API_URL` não aponta para `localhost` | [docs/limitations.md](docs/limitations.md) (Plataforma) |
| B-12 | Desempenho em PDFs grandes (centenas de páginas): perfis de DPI, paralelismo do OCR fora do `AI_LOCK` | [docs/limitations.md](docs/limitations.md) (Desempenho) |
| B-59 | Publicar a imagem Docker (GHCR) na Release, respeitando a ressalva de licenciamento | [docs/licensing.md](docs/licensing.md), `.github/workflows/release.yml` |

## 🔵 P3 · Refatoração e manutenção
Expand Down Expand Up @@ -126,6 +125,8 @@ Arquitetura: `detectar (regras + GLiNER + LLM) → decidir (Laya) → revisão

| ID | Item | Versão | Teste |
|---|---|---|---|
| B-12 | Desempenho: `BASE_DPI` 300 (medido: melhor revocação e mais rápido), OCR das páginas em paralelo nas duas passadas e na verificação, pré-carga do Laya, PNG leve. Documento real de 10 páginas: ~14 min → ~3 min | 5.4.0 | `tests/test_performance.py`, `docs/benchmarks.md` |
| B-67 | Regiões a revisar desenhadas na página (alerta com posição) e documento aberto que se atualiza ao terminar o processamento | 5.4.0 | `tests/test_review_marks.py`, `tests/ui/test_ui_review_marks.py` |
| B-41 | Token na URL só abre a sessão (redireciona sem o token); cookie de sessão aleatório (`HttpOnly`, `SameSite=Strict`, `Secure` com HTTPS) no lugar do token cru; `token=` mascarado nos registros (`utils/auth.py`) | 5.3.0 | `tests/test_auth.py`, `tests/test_service_endpoints.py` |
| B-42 | Painel do gatekeeper exige `API_TOKEN` quando definido; `kill_port_owner` só encerra um `app_service.py` órfão e não usa shell | 5.3.0 | `tests/test_auth.py`, `tests/test_gatekeeper.py` |
| B-52 | Saída do app herdada pelo gatekeeper (o PIPE nunca lido travava o app) | 5.3.0 | `gatekeeper.py` |
Expand Down
47 changes: 47 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,53 @@ Todas as mudanças relevantes ficam registradas aqui. Formato baseado no

## [Não publicado]

## [5.4.0] - 2026-10-04

Critérios nacionais e internacionais de dados pessoais (catálogo de PII e perfis de política), ~4,7× mais rápido
num documento real, regiões a revisar desenhadas na página e uma rodada de revisão independente com contra-análise.
**Mudanças de comportamento:** `BASE_DPI` padrão passou de 1000 para 300 (medido: melhor revocação); quem define
`BASE_DPI`/`YOLO_CROP_PADDING` no `.env` deve revisar os valores. O perfil padrão (`cpf_endereco`) mantém o
comportamento anterior; os novos tipos valem ao escolher outro perfil em `POLICY_PROFILE`.

### Corrigido (revisão independente e contra-análise)
- **Páginas rotacionadas:** a passada de texto digital usava as coordenadas da página sem rotação e colocaria tarjas no lugar errado (o dado ficaria visível); agora aplica a rotação (`page_words`). Testado sobre os pixels desenhados.
- Registros de erro do uvicorn voltaram a mascarar CPF e `token=` também no *traceback* e em argumentos que não são texto.
- A região "Revisar aqui" não bloqueia mais o clique nas tarjas embaixo dela; trocar de documento não dispara mais um "processamento concluído" falso; erro no processamento não mostra mensagem de sucesso.
- Telefone: não pega mais o final de um número maior; aceita fixo sem DDD com palavra de contexto e DDD com zero de operadora "(065)" coberto inteiro. Data de nascimento aceita "1º de março"; outra data ou rótulo entre "nascimento" e o valor (ex.: "Emissão") anula o contexto. CPF logo depois de "RG" não é mais contado como RG. Placa no formato antigo ("ISO-9001") passa a exigir contexto.
- Uma região a revisar por ocorrência (antes, uma caixa podia cobrir a página inteira); regiões sempre limitadas à página.
- Finalizar ("Aplicar proteção") não apaga mais o resumo de tipos e os tempos do processamento; os rótulos das tarjas atravessam a finalização (antes telefone/e-mail viravam "Endereço residencial" no modo legado).
- Verificação pós-tarja em lotes: limita imagens temporárias em disco e o progresso avança durante o OCR.
- `BASE_DPI` lido num só lugar (`render_dpi`), com a mesma faixa válida em todo o pipeline.

### Testes
- 66 casos de contra-análise (`tests/test_counter_analysis.py`): falsos positivos em texto administrativo comum, formatos reais, lixo aleatório, páginas gigantes com tempo limitado (sem regex explosivo), acentos e caracteres especiais, concorrência, matriz de perfis e uma regressão por achado da revisão. Vetores fixos conferidos à mão para PIS, CNS, título de eleitor (incluindo a regra de SP/MG) e números de teste públicos de cartão.
- Testes que comprovadamente falham sem a correção (verificado para rotação e para o clique sob a região).

### Adicionado (critérios de dados pessoais)
- **Catálogo de PII** (`utils/detect/catalog.py`, documentação gerada em `docs/catalogo-pii.md`): 30 tipos com enquadramento em **LGPD** (art. 5º, I e II), **GDPR** (art. 4, 9 e 10), **ISO/IEC 29100**, **NIST SP 800-122** e **HIPAA Safe Harbor**, nível (identificador direto, dado pessoal, sensível, indireto) e forma de detecção. Tipos sem detector ficam como *planejados* (nomes, rostos, dados sensíveis).
- **Perfis de política** (`POLICY_PROFILE`): `cpf_endereco` (padrão, comportamento original), `lgpd_publicacao` (LAI), `lgpd_interno`, `gdpr` e `saude_hipaa`; cada tipo é tarjado (sugestão para revisão) ou só alertado (região a revisar). O endereço residencial também obedece ao perfil.
- **Novos detectores por regra** sobre as três leituras de cada página (OCR padrão, OCR esparso, texto digital): RG, CNH, título de eleitor, PIS/NIS, Cartão SUS, passaporte, CTPS, telefone, e-mail, dados bancários, chave Pix, data de nascimento, placa e IP. Cada regra exige dígito verificador oficial, formato distintivo ou palavra de contexto; a palavra de contexto nunca é tarjada.
- O editor mostra o **tipo** de cada tarja sugerida (ex.: "Possível Telefone"), e o cartão da tarefa mostra o **resumo dos tipos encontrados** (quantidades, nunca os valores).
- API só de leitura `GET /policy/catalog` e `GET /policy/profiles` (contrato de um futuro serviço SENTRY Detect).
- No documento real de teste, o perfil `lgpd_publicacao` passou a encontrar RG e telefone, antes não tarjados.

### Alterado
- **Mais rápido e mais preciso:** um documento real digitalizado de 10 páginas caiu de **~14 min para ~3 min** (OCR de ~510 s para ~19 s).
- **`BASE_DPI` padrão: 1000 → 300.** Medido (`docs/benchmarks.md`): a 300 DPI a revocação de CPF foi de 100% contra ~60% a 1000 DPI (o Tesseract quebra os dígitos em pedaços em imagens grandes), e a verificação achou 16/16 vazamentos contra 11–13/16. No documento real, os CPFs achados a 1000 DPI foram todos achados a 300 DPI. **Atenção:** quem define `BASE_DPI` no `.env` deve revisar o valor (e `YOLO_CROP_PADDING`, que é em pixels).
- **OCR das páginas em paralelo** (nova variável `OCR_WORKERS`; padrão: metade dos núcleos, até 8), nas duas passadas e na verificação pós-tarja. A detecção de falha do Tesseract continua por página (contador por thread). **As duas passadas de OCR (padrão + esparsa) foram mantidas.**
- O decisor Laya carrega o modelo **em paralelo** com a análise de endereços do LLM.
- Imagens das páginas gravadas com compressão PNG leve.

### Adicionado
- **Onde revisar:** cada alerta com posição conhecida (CPF ainda detectável, CPF sem tarja, dúvida do decisor sobre endereço) marca a **região na página** com um contorno tracejado laranja ("⚠ Revisar aqui"); clicar no alerta da barra leva até a região e a destaca.
- **Documento aberto se atualiza sozinho** quando o processamento termina (sem recarregar a página); com edições não salvas, só avisa, nunca descarta.
- **Texto digital do PDF como passada extra** de CPF, somada ao OCR, quando o PDF tem camada de texto.
- **Tempo por etapa** registrado na tarefa e mostrado no cartão (total; detalhe ao passar o mouse).

### Corrigido
- O filtro que mascara `token=` nos registros quebrava o formatador de acesso do uvicorn (um *traceback* por requisição no console; as requisições funcionavam). Agora mascara dentro dos argumentos, preservando o formato.
- A tarja nativa sem a largura da imagem de origem supunha 1000 DPI fixo; agora usa `BASE_DPI`.

## [5.3.0] - 2026-10-04

Decisor local que aprende (experimental, desligado por padrão) e uma rodada completa de segurança: os dois
Expand Down
2 changes: 1 addition & 1 deletion CITATION.cff
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ authors:
- family-names: Gambati
given-names: Joberth Firmino
alias: Yiuky
version: 5.3.0
version: 5.4.0
date-released: 2026-10-04
license: AGPL-3.0-or-later
repository-code: "https://github.com/Yiuky/PrivioSentry"
Expand Down
6 changes: 3 additions & 3 deletions README.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@ PRIVIO SENTRY is a local-first project for detecting and protecting personal, se

* Every output **must be reviewed by a person** before publication or sharing.
* "Concluído" means *no pending alert was detected by the automatic checks*, not that the document is guaranteed clean.
* Only **CPF** and **personal addresses** are targeted. Names, phone numbers, e-mails, RG, bank data, photos, QR codes, metadata, etc. are **not** redacted. See [docs/limitations.md](docs/limitations.md) and [docs/threat-model-lgpd.md](docs/threat-model-lgpd.md).
* What gets redacted depends on the **policy profile** (`POLICY_PROFILE`). The default covers only **CPF** and **residential addresses**; the LGPD, GDPR and health profiles add RG, CNH, voter ID, PIS/NIS, SUS health card, passport, CTPS, phone, e-mail, bank data, Pix key, date of birth, plate and IP ([PII catalog](docs/catalogo-pii.md), in Portuguese). Names, parents' names, faces, sensitive data (health, religion...), QR codes and metadata are **not yet** detected. See [docs/limitations.md](docs/limitations.md) and [docs/threat-model-lgpd.md](docs/threat-model-lgpd.md).
* Never use real documents to report bugs or in tests; see [SECURITY.md](SECURITY.md).

## LGPD positioning

PRIVIO SENTRY is a **technical control that can support privacy and security practices**, including those related to Brazil's data-protection law (**LGPD**, Lei 13.709/2018). It is **not** an "LGPD compliance" engine, it is not legal advice, and using it does not by itself make any document or process compliant: that depends on purpose, legal basis, necessity, governance, data lifecycle and roles. Local processing is an architectural choice, not a legal conclusion; actual guarantees depend on your deployment (network configuration, logging, temporary files, model behavior). The UI label **LOCAL PROCESSING** describes where processing happens; it does not claim the machine is offline.

The LGPD separates *personal data* from *sensitive personal data* (health, biometric, genetic...). Today only CPF numbers and residential addresses (personal data) are targeted. See [docs/brand/LGPD_PRODUCT_POSITIONING.md](docs/brand/LGPD_PRODUCT_POSITIONING.md) and the official sources: [LGPD](https://www.planalto.gov.br/ccivil_03/_ato2015-2018/2018/lei/l13709.htm), [ANPD](https://www.gov.br/anpd/pt-br).
The LGPD separates *personal data* from *sensitive personal data* (health, biometric, genetic...). Sensitive categories are mapped in the PII catalog but not yet detected. See [docs/brand/LGPD_PRODUCT_POSITIONING.md](docs/brand/LGPD_PRODUCT_POSITIONING.md) and the official sources: [LGPD](https://www.planalto.gov.br/ccivil_03/_ato2015-2018/2018/lei/l13709.htm), [ANPD](https://www.gov.br/anpd/pt-br).

## What SENTRY Redact does today

Expand Down Expand Up @@ -163,7 +163,7 @@ Brand, design and UX guidelines live in [docs/brand/](docs/brand/) (including th

## Limitations

* Only CPF and personal addresses; no names, phones, e-mails, faces, etc.
* Names, parents' names, faces and sensitive data are not yet detected; other types depend on the policy profile.
* Recall of the detection and of the verification was only measured on synthetic data (see [docs/benchmarks.md](docs/benchmarks.md) when available); real-world scans can be worse.
* Handwriting and low-quality scans are the weakest point. The signature detector has modest accuracy (see model card).
* Address redaction depends on an LLM classification and on fuzzy matching: it can over- or under-redact.
Expand Down
Loading
Loading