# Arquitetura [English](../architecture.md) · **Português** O Acauã é um produto único em Rust: um daemon/CLI, um núcleo compartilhado e um dashboard web embutido. 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 | Motivo | |---|---|---| | Core, CLI e daemon | Rust 2021 (MSRV 1.88) | Toolchain única, segurança de memória, sem dependências externas de runtime | | API HTTP | Axum + Tokio + Tower HTTP | Superfície assíncrona enxuta, fácil de embutir | | Dashboard Web | HTML/CSS/JS vanilla | Sem etapa de build de frontend, assets embutidos no binário via `rust-embed` | | Armazenamento analítico | DuckDB + Parquet | Armazenamento colunar embutido obrigatório, linkado à `libduckdb.so` oficial pré-compilada | | Implantação | Docker / docker-compose | Daemon de SOC coletivo, usuário não-root sem privilégios, rootfs somente leitura | | Validação científica | Python apenas em `research/` | astropy/scipy/networkx para fixtures, nunca distribuído | O workspace possui dois crates: `acaua-core` e `acaua-cli`. Ambos utilizam `version.workspace = true`. ## Componentes ``` Logs Zeek ──► acaua-core::zeek ──► eventos normalizados ──► storage │ ├──► pillar1 (beaconing) ├──► pillar2 (sessões persistentes) ├──► pillar3 (anomalias de protocolo) └──► pillar4 (fusão) ──► alertas + evidência │ acaua-cli (serve) ──► API axum ──► dashboard web embutido ──────────┘ ``` - `zeek`: parser delimitado e confinamento de caminhos. Nunca segue symlink fora da raiz do dataset. - `storage`: motor DuckDB em memória sobre arquivos Parquet particionados por dia com TTL de sete dias. - `pillar1`–`pillar4`: funções puras sobre eventos normalizados. Retornam scores e evidência, nunca apenas um float. - `fusion`: combinação limitada em ordem fixa. Deve ser simétrica e reproduzível. - `doctor`: checagens do ambiente local; reporta linkagem da DuckDB pré-compilada e status do Zeek em container. - `update`: checa novas versões consultando a API de Releases do Gitea. ## As seis correções ### 1. Rayleigh/Schuster, não Lomb–Scargle puro Timestamps de eventos são um processo pontual unidimensional: não há valor `y` para ajustar. O periodograma primário é, portanto, Rayleigh/Schuster: ```text P(T) = (2 / N) * [ (sum cos(2*pi*t_i / T))^2 + (sum sin(2*pi*t_i / T))^2 ] ``` Lomb–Scargle generalizado fica reservado para a extensão futura que avaliará um atributo real de resposta (como tamanho de payload ou duração) contra o tempo. ### 2. Proteger o caso de dispersão zero no MADM Um beacon sintético ou sem jitter produz intervalos perfeitamente iguais. O desvio absoluto mediano em relação à mediana (MADM) é então `0.0`. Dividir por `0.0` ou tratá-lo como dado ausente é incorreto: dispersão zero é o resultado mais suspeito possível. A implementação protege esse caso com atribuição explícita de score (`1.0`) e sentinela documentado. ### 3. Substituir assimetria de Pearson por assimetria de Bowley A assimetria amostral baseada no terceiro momento central é sensível a outliers individuais e pode divergir. A assimetria de Bowley utiliza quartis: ```text B = (Q3 + Q1 - 2*Q2) / (Q3 - Q1) ``` Ela é limitada em `[-1.0, 1.0]` por definição e resistente a outliers extremos. Quando `Q3 == Q1` (dados concentrados), a implementação atribui `0.0` com flag sentinela. ### 4. Isolar o espaço de pesquisa Python `research/` tem seu próprio ambiente virtual e dependências. Ele é excluído do workspace Cargo, ignorado em builds Docker e releases de CI, e testado apenas quando scripts de validação de pesquisa forem invocados diretamente. ### 5. Modo degradado documentado para NetFlow/IPFIX NetFlow v9 e IPFIX não carregam nomes de consulta DNS, SNI TLS, cadeias de certificados ou cabeçalhos HTTP. Qualquer análise que dependa de recursos de protocolo fica indisponível. O Acauã documenta isso como modo degradado e nunca alega paridade entre registros de fluxo e logs Zeek completos. ### 6. Fronteira única HTTP e RPC O daemon expõe uma API Axum em loopback por padrão. A UI web embutida se comunica com o daemon exclusivamente por chamadas HTTP padrão. ## API A API HTTP é servida por `acaua serve`: | Método | Caminho | Significado | |---|---|---| | GET | `/api/health` | Liveness e versão | | GET | `/api/status` | Uptime, diretório de dados, sumário do dataset | | GET | `/api/alerts` | Alertas paginados com evidência | | POST | `/api/analyze` | Ingestão e análise de diretório de dataset | | GET | `/api/update` | Checagem de novas releases | | GET | `/logo.png` | Asset de marca embutido | | GET | `/*` | Fallback de UI embutida (`rust-embed`) | `serve` escuta em `127.0.0.1:8787` por padrão. Expô-lo em uma rede externa exige um proxy reverso com autenticação. ## Armazenamento DuckDB é uma dependência obrigatória linkada dinamicamente à `libduckdb.so` oficial pré-compilada (versão 1.5.6 fixada com SHA-256 em `scripts/fetch-libduckdb.sh`). Extensões Parquet, JSON e ICU já vêm compiladas estaticamente na biblioteca oficial. O esquema consiste em arquivos Parquet particionados por dia sob o diretório de dados configurado, com consultas DuckDB em memória e TTL de sete dias. ## Atualizações Atualizações do Acauã são distribuídas por imagens de container (`docker compose pull && docker compose up -d`). O comando `acaua update` consulta a API de Releases do Gitea para `ciberfauna/acaua` e notifica os operadores quando uma tag de versão mais nova estiver disponível. A sobrescrita binária em disco (`update --apply`) foi removida: em um daemon de SOC coletivo orquestrado via container, atualizações devem ser controladas por puxar imagens novas em vez de processos que alteram o próprio executável. ## Alternativas rejeitadas 1. **Serviço Python com FastAPI/ClickHouse:** Rejeitado. Um runtime Python introduziria imagens pesadas e fronteiras de memória desnecessárias; o ClickHouse adicionaria um servidor externo e custo operacional para datasets que cabem perfeitamente em um armazenamento colunar embutido. O produto é 100% Rust. 2. **Aplicativo desktop (Tauri / AppImage / NSIS):** Rejeitado. Diferente do Guará (forense em disco bruto local) e do Sabiá (hardware Wi-Fi em modo monitor), o Acauã não tem dependência de hardware local: é um daemon de SOC multiusuário consumindo logs do Zeek. Um wrapper desktop traria manutenção e superfície de segurança sem ganho operacional. ## Implantação - **Docker Compose (Oficial):** Imagem multi-arch (`git.lucasrguerra.dev.br/ciberfauna/acaua`), rodando com usuário não-privilegiado `acaua` (UID 10001), filesystem somente leitura e capabilities revogadas. - **Compilação nativa:** `scripts/fetch-libduckdb.sh ~/.cache/acaua/duckdb` seguido de `cargo build --release -p acaua-cli`. ## Comportamento em falhas Entradas malformadas são ignoradas com diagnóstico delimitado e contado. Um log ausente não é fatal. Um banco corrompido é reportado pelo `doctor` e nunca recriado silenciosamente sobre dados existentes. ## Versionamento e compatibilidade SemVer 2.0.0. O JSON de evidência carrega uma versão de esquema. Qualquer alteração em uma pontuação ou no formato de evidência é breaking change para versões minor `0.x` e deve constar no changelog.