Files
acaua/docs/pt-BR/arquitetura.md
T
Lucas RayanandClaude Sonnet 5 1b974bb90d chore: initial project skeleton
Acauã: Network Detection & Threat Hunting, heuristic analysis over a
rolling 7-day window using deterministic math (time series, graph
theory, information theory) instead of opaque ML models. Third
product in the Ciberfauna ecosystem, alongside Guará and Sabiá.

Follows the ecosystem's established conventions: OpenWolf project
memory, bilingual PT-BR/EN docs and UI, Gitea Actions CI/CD on the
same self-hosted runners, Conventional Commits, SemVer, logo and
productName handling, MIT OR Apache-2.0 licensing.

Architecture decision (made with the project owner after a dedicated
consultation, not the original blueprint's suggested stack): Rust
throughout, not Python/FastAPI/React. Most of the statistics (Bowley
skew, MADM, Shannon entropy, PCR, Z-score, novel-edge detection,
pivot chains) reduces to SQL over an embedded DuckDB/Parquet store;
only the spectral analysis and graph centrality need host-language
code, and both have workable Rust crates. Documented in full, including
six corrections to the original blueprint's math (Rayleigh/Schuster
instead of a degenerate Lomb-Scargle over bare timestamps, an explicit
sentinel for Bowley skew's Q3=Q1 case, Jensen-Shannon instead of
unbounded KL, a dedicated long-connection detector, JA4 vs. JA4+
licensing caution, deterministic per-alert evidence), in
docs/architecture.md.

Skeleton only: crates/acaua-core has the four detection pillars,
fusion, storage, zeek log parsing and the updater as typed stubs that
compile and return a clear "skeleton" status rather than real
detection logic — that is separate, future work. crates/acaua-cli has
serve/analyze/doctor/update. apps/gui is a minimal Tauri shell. Also
already includes the one-click desktop self-update mechanism shared
with Guará and Sabiá (AppImage/.deb/Windows installer), even with no
release published yet, for consistency across the ecosystem.

No Gitea repository exists for this project yet; this is a local-only
commit.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VAyr8d7HuAdUGB6aA5xmDD
2026-10-31 10:20:03 -03:00

178 lines
8.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Arquitetura
[English](../architecture.md) · **Português**
O Acauã é um único produto Rust: um daemon/CLI, um núcleo compartilhado, uma UI
web embutida e um shell Tauri. O runtime distribuído não tem Python nem banco
externo. Este documento registra as decisões estruturais e as seis correções
aplicadas ao blueprint original.
## Stack
| Camada | Escolha | Por quê |
|---|---|---|
| Núcleo, CLI e daemon | Rust 2021 | Uma toolchain, segurança de memória, sem dependência de runtime |
| API HTTP | Axum + Tokio + Tower HTTP | Superfície async pequena e fácil de embutir |
| UI | HTML/CSS/JS vanilla | Sem etapa de build de frontend, assets embutidos no binário |
| Desktop | Tauri 2 | Janela nativa sobre a mesma UI |
| Armazenamento analítico | DuckDB + Parquet (feature opcional `duckdb`) | Embutido, colunar, local-first |
| Validação científica | Python só em `research/` | astropy/scipy/networkx para fixtures, nunca distribuído |
O workspace tem dois crates: `acaua-core` e `acaua-cli`. A GUI fica em
`apps/gui`, **fora** do workspace Cargo, como no Guará e no Sabiá. A spec citou
`version.workspace = true` para o manifesto do desktop; manter a GUI fora do
workspace torna isso impossível, então o `check.sh` impõe igualdade de SemVer
entre `Cargo.toml`, `acaua-cli/Cargo.toml`, o manifesto do desktop e
`tauri.conf.json`. É um desvio deliberado, não um esquecimento.
## Componentes
```
Logs Zeek ──► acaua-core::zeek ──► eventos normalizados ──► armazenamento
│
├──► pilar1 (beaconing)
├──► pilar2 (sessões persistentes)
├──► pilar3 (anomalias de protocolo)
└──► pilar4 (fusão) ──► alertas + evidência
│
acaua-cli ──► API axum ──► UI embutida ◄── shell Tauri ────────────┘
```
- `zeek`: parser limitado e confinamento de caminho. Nunca segue link simbólico
para fora da raiz do dataset.
- `storage`: escritor DuckDB/Parquet com TTL de sete dias. Desligado por padrão
para o esqueleto não exigir build C++.
- `pillar1`–`pillar4`: funções puras sobre eventos normalizados. Devolvem
pontuação e evidência, nunca só um float.
- `fusion`: combinação limitada e em ordem fixa. Precisa ser simétrica e
reproduzível.
- `doctor`: checagens do ambiente local; sem chamadas de rede exceto a checagem
explícita de atualização.
- `update`: cliente de Gitea Releases só para a CLI.
## As seis correções
### 1. Rayleigh/Schuster, não Lomb–Scargle puro
Timestamps de eventos são um processo pontual unidimensional: não existe um `y`
para ajustar. O periodograma primário é, portanto, Rayleigh/Schuster:
```text
P(f) = |sum_k exp(2*pi*i*f*t_k)|^2 / N
```
O Lomb–Scargle generalizado só é usado quando existe um `y` real (por exemplo,
bytes por bucket). Isso evita inventar uma variável dependente e mantém a
distribuição nula honesta.
### 2. Bowley com sentinela explícito
O coeficiente de Bowley usa quartis. Quando `Q3 == Q1`, o denominador é zero; a
implementação devolve um sentinela documentado (`0.0` com a flag de evidência
`degenerate_quartiles`) em vez de `NaN`, infinito ou panic. O sentinela faz parte
do registro do alerta, não é fallback silencioso.
### 3. Jensen–Shannon, não KL puro
KL diverge quando a distribuição de referência tem zero onde a observada não
tem. A fusão usa Jensen–Shannon, que é simétrica, limitada e definida para bins
com probabilidade zero com um piso de suavização documentado. Isso torna a
pontuação comparável entre pilares e segura para histogramas esparsos.
### 4. Sessões persistentes têm detector próprio
Uma conexão aberta por horas nunca produz um intervalo curto, então um detector
de beaconing pode ignorá-la. O pilar 2 pontua duração, lacunas ociosas e fluxos
longos repetidos diretamente. Os dois pilares podem disparar; a fusão trata isso
como evidências separadas, não como contagem dupla do mesmo sinal.
### 5. Cautela com a licença JA4
A impressão digital JA4 de cliente TLS pode ser usada. JA4S, JA4H, JA4X, JA4SSH
e JA4L têm licença não-OSI e **não** são habilitadas por padrão. Qualquer uso
futuro exige decisão explícita de licenciamento e opt-in documentado. O conjunto
padrão precisa continuar redistribuível sob MIT/Apache-2.0.
### 6. Determinismo e evidência JSON por alerta
Todo alerta carrega um registro JSON: hash do dataset, versão do código, pilar,
entradas, valores intermediários, sentinelas, pesos e pontuação final. As
reduções rodam em ordem fixa; iteração de hash map ou agendamento de threads não
pode mudar uma pontuação. Com a mesma entrada e versão, a evidência precisa ser
byte a byte idêntica.
## Fluxo de dados
1. `acaua analyze <dir>` valida o diretório, lê logs suportados e normaliza
eventos. Neste esqueleto ele valida e devolve um relatório stub.
2. Eventos normalizados vão para o armazenamento local (quando a feature
`duckdb` está ligada) com TTL de sete dias.
3. Cada pilar roda sobre uma janela determinística e devolve candidatos com
evidência.
4. A fusão combina candidatos, aplica limiares e grava alertas.
5. `serve` expõe a API e a UI embutida; o shell Tauri abre a mesma UI contra um
daemon local ou remoto.
## API
| Método | Caminho | Finalidade |
|---|---|---|
| GET | `/api/health` | Liveness e versão |
| GET | `/api/status` | Uptime, diretório de dados, estado dos pilares |
| GET | `/api/alerts` | Alertas paginados com evidência |
| POST | `/api/analyze` | Analisar um caminho de dataset |
| POST | `/api/update` | Checar atualização da CLI |
| GET | `/logo.png` | Asset de marca embutido |
| GET | `/*` | Fallback da UI embutida |
O `serve` escuta em `127.0.0.1:8787` por padrão. Não há camada de autenticação
no esqueleto; expor em interface de rede exige proxy reverso com autenticação.
## Armazenamento
DuckDB é dependência **opcional** (`features = ["duckdb"]`, `bundled`). O
esqueleto padrão não compila o backend C++. Quando ligado, o schema é de eventos
normalizados append-only mais uma tabela de alertas, com exportação Parquet e
retenção de sete dias. O arquivo do banco fica sob o diretório de dados
configurado e nunca fora dele.
## Atualizações
`update.rs` consulta a API de Gitea Releases do repositório `acaua`, escolhe o
asset da plataforma atual, baixa por HTTPS com `curl`, verifica SHA-256 e
substitui o binário da CLI. Ele se recusa a atualizar automaticamente uma GUI em
execução; o desktop só informa que existe versão nova. Isso espelha o updater do
Sabiá e evita um segundo mecanismo de atualização.
O plugin updater do Tauri e seu fluxo de manifesto e assinatura não são usados
de propósito: adicionariam um segundo caminho de assinatura e distribuição, e o
desktop não deve se auto-atualizar. O caminho único da CLI é mais fácil de
auditar e mantém os assets de release em tarballs mais SHA-256.
## Alternativas rejeitadas
Um blueprint anterior propunha um serviço Python e um banco colunar externo. Os
dois são rejeitados. Um serviço Python adicionaria um segundo runtime, custo de
empacotamento e uma fronteira de rede dentro de uma ferramenta local-first; um
banco externo adicionaria servidor e custo operacional para datasets que cabem em
um armazenamento colunar embutido. O produto é 100% Rust, com Python confinado a
`research/`.
## Implantação
- **Nativa:** `cargo build --release -p acaua-cli`, depois `acaua serve`.
- **Desktop:** bundles Tauri para Linux e Windows, construídos no CI.
- **Docker:** imagem enxuta de runtime para laboratório; veja [docker.md](docker.md).
## Comportamento em falha
Entrada malformada é ignorada com diagnóstico contado e limitado. Log ausente não
é fatal. Store corrompido é reportado pelo `doctor` e nunca recriado por cima de
dados existentes. Atualização falha mantém o binário atual.
## Versionamento e compatibilidade
SemVer 2.0.0. O JSON de evidência carrega versão de schema. Qualquer mudança em
pontuação ou no formato da evidência é quebra para versões menores `0.x` e
precisa constar no changelog.