
Uma plataforma SIEM, EDR e SOAR de código aberto, auto-hospedada e alimentada por IA, para operações de segurança modernas.
Stack de segurança auto-hospedado para equipes pequenas/médias que não possuem um
SOC dedicado. Instale um agente em cada endpoint, aponte-os para o servidor, e você obtém
logs de SIEM, integridade de arquivos, vulnerabilidades de pacotes, um explorador
de logs baseado em OpenSearch, triagem autônoma com IA e um mecanismo de playbooks SOAR, tudo em um
único docker compose up.
A parte de "IA" é um modelo Ollama executado localmente (padrão llama3.2:3b).
Os logs nunca saem da máquina; não há chave da OpenAI, nem chave da Anthropic, nem
telemetria para casa. Se você quiser um modelo mais inteligente e tiver RAM, troque-o no .env.

Coleta telemetria de agentes Windows e Linux por um único canal TCP. Eventos de SIEM, alertas, FIM, pacotes, conexões de rede, portas abertas, atividade do Docker, quadros de tela.
Detecta com regras Sigma, no endpoint. 23 regras cobrindo 23 técnicas
do MITRE ATT&CK acompanham o conf/sigma/builtin/; adicione conjuntos de regras da comunidade
ao lado delas. O Sigma corresponde a campos nomeados em vez de texto, então
Image|endswith: '\vssadmin.exe' não pode ser derrotado pela palavra "vssadmin"
aparecendo em uma mensagem não relacionada — e
CommandLine|utf16le|base64offset|contains lê dentro de um payload
-EncodedCommand em base64, onde a linha de comando em texto puro mostra apenas o
wrapper. Medido no corpus de avaliação: 9 de 10 ataques detectados apenas pelo Sigma,
0 de 9 negativos difíceis sinalizados falsamente. Esta camada é determinística e continua
funcionando quando o modelo está indisponível.
Correlaciona entre eventos, o que nenhuma regra por evento consegue fazer. Um único logon
com falha é rotina; cinco contas falhando a partir de uma única origem em quarenta segundos é um
password spray, e olhar para qualquer um desses cinco eventos nunca lhe dirá
isso. Cobre spray, força bruta, um sucesso chegando após falhas
repetidas, e rajadas de criação de contas ou instalações de serviços — em ambas as
plataformas, a partir de IDs de eventos do Windows ou de linhas analisadas do auth.log.
Executa em dois pontos de observação, porque eles veem ataques diferentes. Por host no agente, onde um ataque contra uma única máquina é visível por completo. E entre hosts no caminho de ingestão, onde um spray que percorreu uma falha por vez sobre cinquenta máquinas aparece — nenhum agente individual vê mais de um evento, e esse é o ataque mais competente, já que pulverizar amplo e raso permanece abaixo tanto do bloqueio por conta quanto dos limites por host.
Cobertura total com Sigma: 27 técnicas. Cada janela dispara uma vez em vez de uma vez por evento, e cada contador é limitado — um contador baseado em um nome de usuário fornecido pelo atacante é uma primitiva de esgotamento de memória, não uma detecção.
Mapeia detecções para o MITRE ATT&CK, a partir das próprias regras. As regras carregam
tags: attack.t1490, então não há tabela de mapeamento mantida manualmente que possa ficar desatualizada. A
página de cobertura separa três estados que um único "percentual de cobertura" esconderia:
coberto e visto, coberto e silencioso, e não coberto de forma alguma — sendo o último
o único onde o silêncio do console não significa nada.
Faz triagem de cada evento com um LLM local. Três workers executam em paralelo:
um observa cada evento recebido em tempo real, um executa varreduras
profundas orientadas pelo operador, e um decide se deve tomar uma ação defensiva
(BLOCK_IP, ISOLATE_HOST, KILL_PROCESS, etc.).
Modo shadow para o worker defensivo. Ative AI_SHADOW_MODE=1 e
cada veredito autônomo é encaminhado para aprovação humana no SOAR Hub
em vez de ser despachado. Útil para ajustar o modelo com tráfego
real antes de deixá-lo agir por conta própria.
Indexa tudo no OpenSearch para que você possa pesquisar sua frota com consultas fuzzy / exatas / prefixo a partir de um único lugar.
Executa playbooks SOAR construídos em um pequeno editor visual com rastreamento de resultados multi-etapa e por nó, podendo ser acionados manualmente ou por veredito da IA.
Varredura de vulnerabilidades dos pacotes instalados de cada agente contra o OSV (online ou via um mirror interno).
Puxa feeds de threat-intel do abuse.ch (Feodo, ThreatFox, URLhaus) para uma tabela local de indicadores, com poda por obsolescência e um interruptor de air-gap.
Valida configurações de agentes antes de enviá-las. Parse de YAML, forma estrutural e compilação de regex — uma regex inválida é YAML válido e silenciosamente desativa a regra que a contém.
Área de trabalho remota integrada via streaming JPEG por WebSocket, sem necessidade de instalação separada de VNC no endpoint.
A barra lateral agrupa tudo em três seções: telemetria (dashboard, agentes, alertas, ativos, FIM, logs, IA), resposta de automação (ações defensivas, playbooks, regras de automação) e administração.
Cada agente registrado tem sua própria página com doze abas. A visão geral mostra medidores de recursos ao vivo, os logs de SIEM mais recentes, metadados do agente e um resumo de ameaças:

Alertas são tudo o que as próprias regras de correlação do agente já sinalizaram. Coloridos por severidade, filtráveis, pesquisáveis:

A aba AI Analysis é o lado voltado ao operador do LLM local. Varreduras manuais e automáticas chegam aqui. Cada insight carrega um chip de veredito, confiança, indicadores MITRE (quando o modelo os retorna), IOCs, próximos passos e um botão View Source que abre a linha exata do log que a IA analisou:

Hardware, software e sockets de rede por agente. A aba Hardware lista cada dispositivo PnP, software lista os pacotes instalados, rede lista cada socket TCP/UDP com seu processo proprietário:


Pesquisa entre agentes com suporte do OpenSearch. Escolha um agente, escolha um conjunto de dados (eventos de SIEM, alertas de segurança, eventos de processo, rede, FIM, logs de auditoria) e pesquise. Há também um botão para abrir o OpenSearch Dashboards (fork do Kibana) para usuários avançados:

Cada tentativa de login na própria plataforma, tanto local quanto LDAP, com resultado, IP de origem e timestamp. Útil quando alguém está no clima de "quem logou quando":

Você precisará de Docker 24+ com Compose v2 e Python 3.10+ no host (apenas para a etapa única de build do agente). O stack completo quer ~16 GB de RAM, veja Requisitos de sistema abaixo.```bash git clone https://github.com/d3vhex/Sentora.git cd Sentora
cp .env.example .env
python scripts/init_secrets.py
cd Sentora ./build_agent.sh # on Linux/macOS/WSL
cd ..
docker compose up --build -d
Abra <http://localhost:8000>. O login padrão é `admin` / `admin123`.
Altere-o imediatamente em **Users & Roles**.
O Ollama baixa automaticamente `llama3.2:3b` no primeiro boot. Verifique com:```bash
docker exec sentora-ollama ollama list
Implantar um agente: a partir da página Deploy Agent, copie o comando de uma linha para o SO desejado. Na máquina de destino (shell de administrador), cole-o. O instalador baixa o binário, grava uma configuração, registra-se no servidor e registra-se como uma tarefa agendada / unidade systemd.
| Serviço | Porta | Acessível a partir de | Finalidade |
|---|---|---|---|
app | :8000 | qualquer lugar | API REST + UI React |
ingest | :5001 | qualquer lugar | Coletor de logs TCP (o agente envia para cá) |
db | :3307 | localhost | MySQL 8.0 (3306 dentro da rede) |
rabbitmq | :5672 / :15672 | localhost | Fila de trabalhos + UI de gerenciamento |
ollama | :11434 | localhost | Runtime LLM local |
opensearch | :9200 | localhost | Pesquisa de logs em texto completo |
opensearch-dashboards | :5601 | localhost | Explorador opcional estilo Kibana |
ai-worker-{automation,manual,defensive} | — | Workers de análise LLM |
Apenas app e ingest escutam em todas as interfaces. O restante faz bind em
BIND_ADDR (padrão 127.0.0.1), porque nenhum deles autentica na
configuração padrão — o OpenSearch roda com o plugin de segurança desativado e o
Dashboards é uma visão não autenticada de todos os logs coletados. Exponha um
colocando-o atrás do mesmo proxy reverso e autenticação que o app, não
ampliando BIND_ADDR.
O botão "Open Dashboards" no Log Explorer aponta para a porta 5601 no hostname do servidor, então funciona a partir do próprio host; operadores remotos precisam desse proxy reverso.
| Perfil | CPU | RAM | Disco | Observações |
|---|---|---|---|---|
| Laboratório (≤ 5 agentes) | 4 núcleos | 12 GB | 40 GB SSD | llama3.2:3b, heap do OpenSearch em 1 GB |
| Pequena equipe (10–50 agentes) | 8 núcleos | 16 GB | 100 GB SSD | Os padrões do compose são suficientes |
| Produção (50+ agentes) | 16+ núcleos | 32 GB+ | 250 GB+ NVMe | Mova OpenSearch e Ollama para hosts próprios |
Pegada ociosa:
llama3.2:3b): ~3 GB, mais durante inferênciaSe você estiver com pouca RAM, troque para qwen2.5:1.5b ou outro modelo
Ollama pequeno e reduza o heap do OpenSearch. Uma GPU não é necessária, mas o Ollama
a usará automaticamente se estiver presente.
Quando o veredito do worker defensivo é ACT com confiança ≥
AI_AUTO_ACT_CONF (padrão 0.75) e a ação recomendada está na
lista segura abaixo, o worker enfileira a ação diretamente na tabela
automations do agente:```
BLOCK_IP KILL_PROCESS RESTART_SERVICE ISOLATE_HOST
DISABLE_USER QUARANTINE_FILE SUSPEND_PROCESS LOGOFF_USER
CONTAINER_ISOLATE CONTAINER_STOP CONTAINER_KILL
### Modo de sombra
Defina `AI_SHADOW_MODE=1` no `.env` e o worker defensivo para de disparar
ações reais. Vereditos que teriam acionado uma resposta autônoma
são salvos como **propostas** em vez disso, com `source_file = AI_DEFENSIVE_SHADOW`
e `shadow_status = pending`. O operador revisa cada uma delas em
**SOAR Hub > Shadow Queue** e pode:
- **Aprovar** > a ação SOAR real (`call_agent_soar`) é disparada e a
proposta é marcada como `approved` (com timestamp + nome do operador).
- **Rejeitar** > a proposta é marcada como `rejected` com uma nota opcional.
Nenhuma ação é tomada.
Propostas nunca expiram; nada decide por você. Útil para deixar o
modelo rodar sobre telemetria de produção enquanto você constrói confiança em seus
vereditos antes de liberar `BLOCK_IP` / `ISOLATE_HOST` reais, etc.
---
## Notas de segurança
### Autenticação
A UI autentica com uma sessão do lado do servidor: o login emite um token opaco
em um cookie `HttpOnly`, e `userdb.sessions` é a autoridade. Apenas o
SHA-256 do token é armazenado, então um dump do banco de dados não produz nada utilizável.
Dois relógios se aplicam, ambos configuráveis no `.env`:
| Configuração | Padrão | Significado |
| :--- | :--- | :--- |
| `SESSION_IDLE_MINUTES` | `60` | A sessão expira esse tempo após a última requisição |
| `SESSION_ABSOLUTE_HOURS` | `12` | Limite máximo independente da atividade |
| `SESSION_COOKIE_SECURE` | `0` | Defina como `1` quando o TLS terminar na frente do app |
| `SESSION_COOKIE_SAMESITE` | `Lax` | `Lax` bloqueia o POST/XHR entre sites que o CSRF precisa |
Sessões são revogadas imediatamente em mudança de senha, redefinição de senha de admin,
mudança de papel e exclusão de conta — um admin removendo o acesso de alguém não
deixa mais a aba aberta dessa pessoa funcionando.
Toda rota é **negada por padrão**: sem uma sessão válida, uma requisição é
rejeitada antes do handler executar. As exceções são o endpoint de login, o
shell da SPA, ativos estáticos e os endpoints voltados a agentes, que autenticam
com `X-Agent-Key` ou um token de inscrição em vez disso.
`X-User-ID` ainda é enviado pelo frontend, mas não é mais identidade — o
servidor o valida contra a sessão e rejeita uma incompatibilidade. Como
navegadores não podem anexar cabeçalhos personalizados a requisições entre sites sem um
preflight de CORS, exigi-lo em requisições que alteram estado reforça o `SameSite`
como um segundo controle de CSRF.
A proteção de rotas é declarada com `@require_permission(...)` e aplicada por
middleware através de um registro, então ela se aplica independentemente de qual lado do
`@app.route` o decorator esteja. O log de inicialização imprime o total:```
[Auth] Routes: <n> permission-gated, <n> session-only, <n> public.
Se essa linha reportar 0 permission-gated, o RBAC não está sendo aplicado — trate
isso como uma indisponibilidade.
Cada rota deve ser uma de três coisas: protegida por permissão, listada em
_PUBLIC_HANDLERS, ou nomeada em SESSION_ONLY_HANDLERS em
tests/test_auth_wiring.py com um comentário explicando por que apenas a sessão
é suficiente. Um teste verifica isso, então uma nova rota não pode chegar silenciosamente sem governança —
que é como run_playbook, delete_soar_action e test_ldap_connection
acabaram acessíveis por qualquer conta que conseguisse fazer login.
Cinco tentativas falhas para uma conta, ou vinte a partir de um endereço, dentro
de quinze minutos, e novas tentativas são recusadas com 429 até que a janela
passe. Contadas a partir de login_logs, que já registrava cada falha
e que ninguém lia — o bcrypt era o único freio contra adivinhação online.
| Configuração | Padrão | Significado |
|---|---|---|
LOGIN_MAX_FAILURES_USER | 5 | Falhas por conta permitidas na janela |
LOGIN_MAX_FAILURES_IP | 20 | Falhas por endereço; maior, porque um escritório compartilha um único endereço NAT |
LOGIN_LOCKOUT_WINDOW_MIN | 15 | Até onde no passado as falhas são contadas |
A verificação ocorre antes da comparação de senha, então também elimina a diferença
de tempo entre um nome de usuário conhecido e um desconhecido. Ela falha de forma aberta se
login_logs estiver inacessível: uma página de login que não pode ser acessada porque a
tabela de auditoria está fora do ar é, por si só, uma indisponibilidade.
X-Forwarded-For é honrado apenas a partir de um peer listado em TRUSTED_PROXIES
(endereços ou CIDRs separados por vírgula, vazio por padrão). Sem nada na frente
do aplicativo, o cabeçalho é fornecido pelo atacante, então acreditar nele incondicionalmente —
que é o que isso substituiu — permitia que um chamador gravasse qualquer endereço no trilho
de auditoria e redefinisse seu próprio limite de taxa na mesma requisição.```
TRUSTED_PROXIES=10.0.0.0/8,192.168.1.5
Deixe vazio quando a aplicação for acedida diretamente.
### A API do próprio agente
O agente escuta em `0.0.0.0:9099` e executa como SYSTEM ou root. Cada rota
exige `X-Agent-Key`; `/self_destruct` exige especificamente a chave de inscrição
deste próprio agente, para que um segredo vazado de toda a frota não possa
desinstalar todos os endpoints de uma vez. `/health` responde à liveness sem
chave e não revela mais nada sem uma.
Não há fallback permissivo. Uma versão anterior aceitava qualquer chave não
vazia sempre que `AGENT_MASTER_SECRET` não estivesse definido no host — o que
nunca era definido, então era o padrão em todo lugar. Um EDR que falha aberto é
pior do que nenhum EDR, porque o console reporta o endpoint como protegido.
`AGENT_BIND` move o listener. Ainda é `0.0.0.0` por padrão porque o servidor
alcança os agentes via HTTP nesta porta; vincular ao loopback exige um
transporte substituto, não uma mudança de configuração.
### CORS
`CORS_ORIGINS` tem como padrão vazio. Na implantação normal, esta aplicação
serve o próprio SPA, então os pedidos são de mesma origem e nenhuma entrada é
necessária. Um wildcard é rejeitado de imediato: os navegadores recusam
`Access-Control-Allow-Origin: *` em qualquer pedido que carregue cookies.
Implantações de origem dividida devem listar origens explícitas e definir
`SESSION_COOKIE_SAMESITE=None` com `SESSION_COOKIE_SECURE=1`.
### Segredos padrão
`.env.example` vem com placeholders. O `.env` real é ignorado pelo git.
Rode estes antes de expor a plataforma a qualquer coisa além de `localhost`:
- `DB_PASSWORD`
- `AGENT_SHARED_SECRET` (fallback de autenticação do agente). Gerado
automaticamente no primeiro boot se não estiver definido.
O login `admin / admin123` não precisa mais ser lembrado: a conta semeada
é criada com `must_change_password`, e enquanto isso estiver definido, a sessão
não alcança nada além de `/change-password`. Aplicado no middleware em vez de
na UI, porque uma flag que o front end é confiado a honrar é uma sugestão e a
API também responde ao curl.
### Certificados TLS
Nada vem com uma chave privada. Um `certs/server.key` e `certs/rootCA.key`
funcionais costumavam ser commitados, o que dava a cada implantação a mesma
identidade TLS e a publicava: qualquer um que já tivesse clonado o repositório
tinha a chave, então o certificado não provava nada sobre quem estava do outro
lado.
Com `TLS_ENABLED=1` e sem certificado presente, a aplicação gera um no
primeiro boot. Cada instalação recebe a sua própria chave e a chave nunca sai
da máquina que a criou. `certs/*.key` e `certs/*.crt` são ignorados pelo git.
A CA é autoassinada, então os navegadores avisam a menos que você a confie
explicitamente. Esse aviso é honesto — prefira-o a um segredo partilhado que
não produz aviso algum. Para qualquer coisa pública, aponte `TLS_CERT` /
`TLS_KEY` para um certificado real; quando estiverem definidos e ausentes, a
aplicação diz isso em vez de substituir por um autoassinado.
Para regenerar manualmente:```bash
python certs/generate_certs.py --force
As chaves antigas ainda estão no histórico do git. Trate o par que foi enviado antes desta alteração como queimado; novas instalações não o utilizam mais.
O servidor usa duas chaves Fernet, ambas geradas automaticamente no primeiro boot:
| Chave | Localização | Protege |
|---|---|---|
| Chave do agente | data/fernet.key (ou FERNET_KEY_PATH) | Telemetria do agente; distribuída via /api/agents/bootstrap |
| Chave do servidor | .env FERNET_KEY | Campos internos do servidor em repouso (ex.: coluna de senha) |
chmod 600 em ambas. Faça backup delas. Perder qualquer uma torna os
dados criptografados correspondentes ilegíveis. Ainda não há rotação no local.
Dois mecanismos independentes, ambos opcionais:
Enriquecimento por veredito (ai/intel.py). O worker de IA cruza
indicadores encontrados em um log com AlienVault OTX e VirusTotal. Requer
OTX_API_KEY / VT_API_KEY; se não definidos, nenhuma chamada externa é feita.
Feeds de indicadores (core/threat_feeds.py). Popula a tabela threat_intel
a cada hora a partir do abuse.ch — Feodo Tracker (endereços C2 de botnets), ThreatFox
(IoCs mistos com pontuação de confiança) e URLhaus (URLs que distribuem malware).
Os indicadores carregam last_seen e são removidos após THREAT_INTEL_STALE_DAYS
(padrão 30): um endereço que hospedou um C2 no último trimestre geralmente pertence
a outra pessoa agora, e mantê-lo gera falsos positivos indefinidamente. Cada
feed é limitado a THREAT_INTEL_MAX_PER_FEED linhas porque a tabela é lida
no caminho de alerta.
O abuse.ch tem movido downloads para trás de uma chave de conta gratuita. Um feed
que retorna 401/403 informa isso no log do servidor; defina THREAT_INTEL_AUTH_KEY.
Verifique o que realmente chegou:```bash docker logs sentora-server | grep ThreatIntel
### Modo air-gap```ini
OSV_MODE=mirror
OSV_MIRROR_URL=http://osv.internal
THREAT_INTEL_MODE=off
# or serve the feeds internally:
# THREAT_INTEL_FEODO_URL=http://mirror.internal/feodo.json
Com esses definidos, além de OTX_API_KEY / VT_API_KEY não definidos, nada sai da
rede. As fontes estão incluídas, o Ollama é local, nenhum CDN é contatado.
/api/exposure/report conta pacotes sem correção e eventos de integridade de arquivos
em toda a frota, por agente, do pior para o melhor. Ele informa sua própria cobertura:
complete: false quando um agente não pôde ser lido, porque um total sobre metade
da frota não é um total da frota.
Não há deliberadamente nenhuma pontuação. O endpoint anteriormente retornava
100 - vulns*2 - fim*5 como uma "pontuação de conformidade" — isso não corresponde a nenhum framework,
não escala com o tamanho da frota e trava em zero em qualquer frota real. A classificação
de gravidade está ausente pelo mesmo motivo: vulnerabilities_report não tem
coluna de gravidade e seus campos são criptografados em repouso, então qualquer nota teria
que ser inventada.
POST /<agent>/config/<type> valida antes que qualquer coisa chegue a um sensor:
análise YAML, forma estrutural e — a camada que importa — compilação de regex.
Uma regex inválida é YAML perfeitamente válido e desativa silenciosamente
a categoria que a contém, então uma verificação apenas de sintaxe a enviaria direto para
o endpoint. O editor faz lint contra o mesmo endpoint enquanto você digita e
relata problemas com números de linha clicáveis.
Agent (Win / Linux) │ TCP frames + REST polling ▼ ingest (:5001) ──► RabbitMQ ──► AI worker fleet (3 modes) │ │ ▼ ▼ MySQL (per-agent _db) ai_analysis_results │ ▼ app (Sanic :8000) ──► React UI + REST + WebSocket screen proxy
A versão mais aprofundada (layout por módulo, esquema, pipeline de IA, autonomia SOAR, superfícies de air-gap) encontra-se em
[docs/Sentora_Architecture.md](https://github.com/d3vhex/sentora/blob/HEAD/docs/Sentora_Architecture.md).
Documentação operacional:
| Documento | Abrange |
| :--- | :--- |
| [Arquitetura](https://github.com/d3vhex/sentora/blob/HEAD/docs/Sentora_Architecture.md) | Layout de módulos, fluxo de dados, modelo de autenticação, pipeline de IA |
| [Implantação em produção](https://github.com/d3vhex/sentora/blob/HEAD/docs/production-deployment.md) | Dimensionamento, topologia de rede, TLS, backup, monitoramento, air-gap |
| [Runbook de atualização](https://github.com/d3vhex/sentora/blob/HEAD/docs/update-runbook.md) | Upgrades, rollout de agentes, migrações de banco de dados, rollback |
| [Relatório de progresso](https://github.com/d3vhex/sentora/blob/HEAD/docs/PROGRESS_REPORT.md) | O que mudou e porquê |
---
## Configuração de desenvolvimento```bash
# 1. Database. Only init_userdb.sql — it creates and selects `userdb`.
#
# db/init.sql is NOT a server-init script. It is the per-agent schema
# template, applied by server.create_tables_if_not_exist() after
# connecting to that agent's own database, which is why it contains no
# CREATE DATABASE or USE. Running it standalone fails at line 5 with
# "No database selected" — the same way it broke every first-time
# `docker compose up` while it was mounted into the MySQL init directory.
mysql -u root -p < db/init_userdb.sql
# 2. Backend. requirements.lock pins every version the image is built
# from; requirements.txt is the loose list it was resolved from.
pip install -r requirements.lock
python app.py
# 3. Ingest (separate terminal)
python server.py
# 4. Frontend dev server
cd frontend
npm install
npm run dev
Mesmo script, três papéis:```bash WORKER_TYPE=automation python ai_worker.py WORKER_TYPE=manual python ai_worker.py WORKER_TYPE=defensive python ai_worker.py
Produção: deixe o `docker-compose.yaml` fazer isso.
---
## Contribuindo
PRs são bem-vindos. Antes de abrir:
1. Fork → branch → PR contra `main`.
2. Execute as verificações:```bash
pytest -ra # no MySQL or RabbitMQ needed
python -m compileall -q app.py core security
cd frontend && npx tsc --noEmit && npm run build && cd ..
# With the stack up — enumerates every route and calls it twice
python scripts/api_smoke_test.py
@require_permission(...). O log de inicialização
imprime a contagem; se ele reportar 0 permission-gated, algo está errado
com a fiação, não com a sua rota.Para qualquer coisa maior que uma correção, abra uma issue primeiro para que possamos alinhar a abordagem.
. ├── app.py # Sanic API + React SPA host ├── server.py # TCP ingest ├── ai_worker.py # AI worker fleet (3 modes) ├── ai/ │ ├── utils.py # LLM helpers, AI cache, SOAR queueing │ └── intel.py # OTX / VT per-verdict enrichment (opt-in) ├── core/ │ ├── mq.py # RabbitMQ publisher │ ├── opensearch.py # OpenSearch index/search │ ├── config_validation.py # Agent YAML validation (parse, shape, regex) │ └── threat_feeds.py # abuse.ch indicator feeds ├── security/ │ ├── session.py # Server-side session store │ └── ssrf.py # Proxy destination rules ├── scanners/ │ └── vuln.py # Server-side OSV scanner ├── scripts/ │ ├── init_secrets.py # Generate the secrets .env needs │ ├── rotate_db_password.py # Rotate the MySQL root password safely │ └── api_smoke_test.py # Exercise every route against a live server ├── tests/ # pytest; no MySQL or RabbitMQ required ├── frontend/ # React 18 + TS SPA │ └── src/lib/ # Shared logic (playbook action catalogue) ├── Sentora/ # Cross-platform agent ├── certs/ # Self-signed dev certs ├── docs/ # Architecture + screenshots └── docker-compose.yaml
---
## Licença
AGPL-3.0. Consulte [LICENSE](https://github.com/d3vhex/sentora/blob/HEAD/LICENSE).
Use, modifique, redistribua. O que a AGPL acrescenta em relação à GPL regular:
se você executar uma versão modificada em um servidor de rede onde outros usuários
interagem com ela, você deve publicar as modificações sob AGPL também.
- Auto-hospedagem para uso interno → sem obrigação de divulgação do código-fonte.
- SaaS voltado ao público sobre um Sentora modificado → você deve publicar
as modificações.
- Quer distribuir um derivado de código fechado ou pular a cláusula de copyleft
de rede? Uma isenção de licença comercial está disponível. Entre em contato com o autor.
O nome e o logotipo "Sentora" são marcas registradas dos autores do projeto e
não são cobertos pela AGPL. Faça fork livremente, mas renomeie se redistribuir
como produto próprio.
---
## O que não está na Community Edition
A Community Edition não tem limites artificiais: sem limite de agentes, sem
limite de retenção, sem bloqueio de recursos no núcleo. Execute-a tão amplamente
quanto seu hardware permitir.
A distribuição paga Pro / Enterprise adiciona recursos de integração empresarial
(SSO SAML/SCIM, multi-inquilinos, relatórios de conformidade, HA, auditoria WORM,
pacotes de atualização assinados para air-gap, aprovações SOAR com 4 olhos,
encaminhadores premium de ticketing/SIEM). A capacidade central de detecção nunca
fica atrás dessa barreira.
Se qualquer um desses itens for relevante para sua implantação,
[entre em contato](mailto:[email protected]).