SentrySentry
IA

Modelo ONNX Local

ThreatModel clássico (features → sklearn → ONNX) via ort, com retreinamento hot-swap

Modelo ONNX Local

O modelo local do Sentry é um classificador ML clássico (regressão logística) que roda como fork assíncrono ao lado do hot path. Inferência é local — sem rede, determinística, tipicamente sub-ms — via ort (ONNX Runtime), atrás da feature Cargo onnx (opcional, desligada por default).

Trait ThreatModel

/// A local, deterministic, no-network threat model.
#[async_trait]
pub trait ThreatModel: Send + Sync {
    fn name(&self) -> &'static str;
    fn version(&self) -> &str;
    async fn analyze(&self, evt: &Event) -> anyhow::Result<Vec<Signal>>;
}

Definida em sentry-ai/src/threat.rs — o pipeline depende de um Box<dyn ThreatModel> sem puxar ort para todo build. A implementação ONNX é OnnxThreatModel (feature onnx), carregada pelo daemon em build_ai_fork quando [ai] enabled = true. Sem a feature, o estágio fica desligado com um warning — o resto do Sentry continua funcionando.

load valida a largura da entrada do modelo contra FEATURE_NAMES: um modelo treinado com outra versão das features falha no startup com instrução de retreinar, nunca roda dessincronizado. Probabilidade de anomalia acima de threshold emite um sinal AnomalousPayload com peso signal_weight.

Features — a fonte única de verdade

sentry-ai/src/features.rs é o single source of truth do input do modelo: a mesma função extract roda na inferência (fork do daemon) e no export de treino (sentry model export escreve CSV com header = FEATURE_NAMES). O script de treino valida o header do CSV e falha alto se as pontas divergirem — treino e inferência não podem driftar.

São 25 features, todas normalizadas para 0.0–1.0 (vetor de tamanho fixo; eventos não-HTTP viram vetor de zeros). Resumo por grupo:

GrupoFeatures
Estrutura do pathpath_len, query_len, path_depth, path_digit_ratio, path_special_ratio, path_entropy, path_encoded_count, path_dot_dot, path_null_byte
Tokens de ataque (sobre texto URL-decodificado + lowercase)sqli_token_score, xss_token_score, traversal_token_score, jndi_token, cmd_token_score
Extensão do arquivohas_file_ext, ext_is_script, ext_is_sensitive
Método HTTPmethod_is_get, method_is_post
User-Agentua_len, ua_is_empty, ua_bot_token
Status da respostastatus_4xx, status_5xx
Query stringquery_param_count

Loop de retreinamento

A extração de features acontece exclusivamente em Rust — o script Python só consome os vetores exportados. O ciclo completo:

  1. Export — sentry model export (handler, flags) grava um CSV (FEATURE_NAMES,label) com as features extraídas pelo Rust sobre eventos recentes do Postgres:
    • --hours N — janela de busca (default 720 = 30 dias);
    • --out <arquivo> — destino (default dataset.csv);
    • --synthetic — dataset seed sintético sem Postgres (--rows, default 4000, metade benigna);
    • --confirmed — labels de incidentes confirmados (evento ligado a incidente = 1, resto = 0). Sem a flag, positivos são os eventos com verdict block/challenge/rate_limit.
  2. Treino — tools/train_model.py (tools/train_model.py): StandardScaler + LogisticRegression (sklearn, class_weight="balanced") avaliado em holdout, exportado para ONNX com zipmap: false (probabilidades como tensor float plano).
  3. Substituição — troque o arquivo apontado por model_path (o seed commitado é models/anomaly_v1.onnx).
  4. Hot swap — sentry model reload (handler) envia NOTIFY sentry_model_changed via Postgres; o daemon recarrega o arquivo do disco e troca o modelo a quente (listener), com o modelo vivo em Arc<RwLock<Arc<dyn ThreatModel>>>. Falha de carga mantém o modelo anterior.
  5. Status — sentry model status (handler) mostra enabled, path, mode/trigger/threshold, se o arquivo carrega (com --features onnx) e o provider LLM ativo.
sentry model export --synthetic
python tools/train_model.py --csv dataset.csv --out models/anomaly_v1.onnx
sentry model reload    # exige Postgres: o daemon escuta NOTIFY sentry_model_changed
sentry model status

O build precisa da feature: cargo build --release --features sentry-cli/onnx.

Configuração [ai]

[ai]
enabled = false
model_path = "models/anomaly_v1.onnx"
threshold = 0.7             # prob. de anomalia que emite o sinal
signal_weight = 25          # peso do AnomalousPayload (override: [scorer.weights])
mode = "fork"               # fork | inline | shadow
trigger = "above_score"     # above_score | always | quarantine_only
min_score = 20              # gate de score do hot path (above_score)
concurrency = 4             # inferências paralelas (fork mode)
cache_ttl_secs = 300        # cache de resultados por hash do payload

Chaves e defaults em AiConfig. O que mode/trigger/cache fazem em runtime está descrito em Camada de IA.

On this page