feat: comprehensive security, performance, UX and deployment audit

Security:
- CORS restricted to explicit methods/headers, configurable via CORS_ORIGINS env
- Auth added to /reports/{rid}/html and /compliance-report endpoints
- Ownership check on report downloads
- Rate limiting on login (10 attempts/5min per IP with threading.Lock)
- Non-root container user (agent via gosu entrypoint)
- Nginx security headers (X-Frame-Options, X-Content-Type-Options, X-XSS-Protection, Referrer-Policy, Permissions-Policy)
- .gitignore and .dockerignore for secret leak prevention
- .env.example with documentation

Performance:
- 16 SQLite indexes on foreign keys and frequently queried columns
- Pagination on chat messages (100), reports (50), audit log (100)
- subprocess.run wrapped in run_in_executor (3 async handlers)
- asyncio.wait_for timeouts on GenAI calls (300s) and Chromium PDF (120s)
- Thread pool reduced to 10 workers
- Code splitting with React.lazy (bundle: 1.3MB -> ~550KB initial)
- React.memo on TreeItem (recursive compartment tree)

Error handling:
- 13 bare except clauses replaced with logged Exception handlers
- Graceful shutdown handler (terminates subprocesses + executor)
- File upload validation (50MB max, extension whitelist per endpoint)
- Health check expanded (version, uptime, db_ok)
- Cache-Control on /api/genai/models (1h)
- Auto-cleanup audit_log > 30 days

Dead code removed:
- DownloadsPage.tsx, StubPage.tsx, MfaPage.tsx (moved to UsersPage)
- Legacy frontend/ directory
- 19 unused i18n keys, dist/ removed from git tracking

UX & i18n:
- 8 alert() calls replaced with styled error states (TerraformPage)
- 50+ hardcoded Portuguese strings localized to i18n (pt/en) across 11 files
- aria-label on all icon-only buttons (Chat, Explorer, Sidebar)
- focus-visible CSS for keyboard navigation
- Responsive grid fix (360px -> 280px for mobile)
- aria-hidden on decorative SVGs

Deployment:
- Docker resource limits (backend 4G, frontend 512M)
- Log rotation (json-file, 10MB x 3)
- Terraform version parameterized via ARG
This commit is contained in:
nogueiraguh
2026-03-20 13:48:30 -03:00
parent 61fbb3861d
commit fbcb1966d5
35 changed files with 1301 additions and 4903 deletions

View File

@@ -1,7 +1,6 @@
const pt: Record<string, string> = {
// ── Sidebar ──
'nav.principal': 'Principal',
'nav.config': 'Configuração',
'nav.admin': 'Administração',
'nav.chat': 'Chat Agent',
'nav.terraform': 'Terraform',
@@ -16,11 +15,12 @@ const pt: Record<string, string> = {
'nav.embeddings': 'Embeddings',
'nav.embConsult': 'Consultar Embeddings',
'nav.users': 'Usuários',
'nav.mfa': 'MFA',
'nav.audit': 'Audit Log',
'sidebar.lightMode': 'Modo claro',
'sidebar.darkMode': 'Modo escuro',
'sidebar.logout': 'Sair',
'sidebar.settings': 'Configurações',
'sidebar.backToMenu': 'Voltar ao menu',
'sidebar.roleAdmin': 'Administrador',
'sidebar.roleUser': 'Usuário',
'sidebar.subtitle': 'Infrastructure & Security',
@@ -107,6 +107,14 @@ const pt: Record<string, string> = {
'tf.copied': 'Copiado',
'tf.noWs': 'Nenhum workspace ativo',
'tf.deleteWs': 'Excluir',
'tf.noFilesToPlan': 'Nenhum arquivo para planejar',
'tf.selectOciConfig': 'Selecione OCI Config e Compartment',
'tf.running': 'Executando...',
'tf.terminalTitle': 'Terminal de saida do Terraform',
'tf.terminalHint': 'Execute Plan, Apply ou Destroy para ver os resultados aqui',
'tf.autoFix': 'Auto-corrigir',
'tf.editSystemPrompt': 'Editar System Prompt',
'tf.refreshReference': 'Refresh Reference',
// ── Prompt Generator ──
'pg.history': 'Historico',
@@ -308,24 +316,15 @@ const pt: Record<string, string> = {
'rpt.errorEmbedding': 'Erro ao gerar embedding',
'rpt.cancelled': 'Cancelado',
'rpt.completedAt': 'Concluido:',
// ── Downloads ──
'dl.title': 'Downloads',
'dl.subtitle': 'Baixe relatorios CIS gerados',
'dl.allTenancies': 'Todas as Tenancies',
'dl.allSections': 'Todas as secoes',
'dl.reports': 'relatorio(s)',
'dl.refresh': 'Atualizar',
'dl.loadError': 'Erro ao carregar relatorios',
'dl.loading': 'Carregando relatorios...',
'dl.noReports': 'Nenhum relatorio concluido.',
'dl.noReportsHint': 'Execute um scan na aba Reports para gerar relatorios.',
'dl.files': 'arquivo(s)',
'dl.hide': 'Ocultar',
'dl.viewFiles': 'Ver Arquivos',
'dl.loadingFiles': 'Carregando arquivos...',
'dl.noFiles': 'Nenhum arquivo encontrado',
'dl.filesInSections': 'arquivo(s) em {0} secoes',
'rpt.complianceGenerating': 'Gerando Compliance Report...',
'rpt.complianceFetchingKB': 'Buscando remediações na Knowledge Base CIS',
'rpt.complianceNotGenerated': 'Report ainda não gerado',
'rpt.complianceGenerate': 'Gerar Compliance Report',
'rpt.complianceRegenerate': 'Regenerar',
'rpt.complianceDownloadZip': 'Download ZIP',
'rpt.complianceRemediation': '+ Remediation',
'rpt.complianceGeneratingShort': 'Gerando...',
'rpt.complianceTitle': 'LAD A-Team CIS Compliance Report',
// ── OCI Config ──
'oci.title': 'Credenciais OCI',
@@ -605,6 +604,7 @@ const pt: Record<string, string> = {
'mfa.activated': 'MFA ativado com sucesso!',
'mfa.deactivated': 'MFA desativado.',
'mfa.invalidCode': 'Informe um codigo de 6 digitos',
'mfa.configure': 'Configurar',
// ── Audit ──
'audit.title': 'Log de Auditoria',
@@ -634,6 +634,86 @@ const pt: Record<string, string> = {
'audit.session': 'Sessao',
'audit.source': 'Origem',
// ── Hardcoded fixes ──
'common.errorPrefix': 'Erro: ',
'common.errorSave': 'Erro ao salvar',
'common.errorDelete': 'Erro ao excluir',
'common.errorUnknown': 'Erro desconhecido',
'common.errorLoad': 'Erro ao carregar',
'oci.tableHeaders': 'Tenancy,Tipo,Region,Detalhes,Acoes',
'oci.thTenancy': 'Tenancy',
'oci.thType': 'Tipo',
'oci.thRegion': 'Region',
'oci.thDetails': 'Detalhes',
'oci.thActions': 'Acoes',
'genai.thConfig': 'Config',
'genai.thModel': 'Modelo',
'genai.thOciConfig': 'OCI Config',
'genai.thRegion': 'Regiao',
'genai.thActions': 'Acoes',
'genai.savedSuccess': 'Modelo salvo com sucesso!',
'genai.updatedSuccess': 'Modelo atualizado com sucesso!',
'genai.deletedSuccess': 'Modelo excluido com sucesso!',
'genai.editingLabel': 'Editando:',
'genai.regionFilled': 'Regiao e Compartment preenchidos de <strong>{0}</strong>',
'mcp.savedSuccess': 'Server registrado com sucesso!',
'mcp.updatedSuccess': 'Server atualizado com sucesso!',
'mcp.deletingServer': 'Excluindo server...',
'mcp.deletedSuccess': 'Server excluido com sucesso!',
'mcp.discoveredTools': '{0} tool(s) descoberta(s), {1} total',
'mcp.errorDiscoverTools': 'Erro ao descobrir tools',
'mcp.removeToolConfirm': 'Remover tool "{0}"?',
'mcp.editingLabel': 'Editando:',
'adb.thName': 'Nome',
'adb.thDsn': 'DSN',
'adb.thUser': 'User',
'adb.thTables': 'Tabelas',
'adb.thMtls': 'mTLS',
'adb.thWallet': 'Wallet',
'adb.thEmbed': 'Embed',
'adb.thActions': 'Acoes',
'adb.thTable': 'Tabela',
'adb.thDescription': 'Descricao',
'adb.thActive': 'Ativa',
'adb.thTableActions': 'Acoes',
'adb.walletParsed': 'Wallet analisado! {0} DSN(s): <strong>{1}</strong>. Arquivos: {2}',
'adb.savedSuccess': 'Conexao salva!',
'adb.updatedSuccess': 'Conexao atualizada!',
'adb.walletIncluded': ' Wallet incluido.',
'adb.deletedSuccess': 'Conexao excluida com sucesso!',
'adb.walletSending': 'Enviando wallet...',
'adb.walletSent': 'Wallet enviada! Arquivos: {0}',
'adb.enterTableName': 'Digite o nome da tabela.',
'adb.tableRegistered': 'Tabela {0} registrada!',
'adb.confirmRemoveTable': 'Excluir esta tabela do registro?',
'adb.tableRemoved': 'Tabela removida.',
'adb.editingLabel': 'Editando:',
'emb.errorLoadEmb': 'Erro ao carregar embeddings',
'emb.confirmDeleteEmb': 'Excluir este embedding?',
'emb.totalDocs': 'Total: {0} documentos',
'ec.errorPrefix': 'Erro: ',
'ec.errorUnknown': 'Erro desconhecido',
'ec.docs': 'documentos',
'usr.errorLoadUsers': 'Erro ao carregar usuarios',
'usr.errorCreateUser': 'Erro ao criar usuario',
'usr.errorUpdateRole': 'Erro ao atualizar role',
'usr.errorDeactivate': 'Erro ao desativar usuario',
'usr.mfaSelfOnly': 'MFA so pode ser ativado pelo proprio usuario.',
'ws.typeDestroyLabel': 'Digite <strong>DESTROY</strong> para confirmar:',
'exp.tempAccess': 'Acesso temporario - ',
'exp.optional': 'Opcional',
'exp.ipPrompt': 'IP para liberar acesso (CIDR):',
'exp.nsgType': 'Tipo',
// ── Common ──
'common.save': 'Salvar',
'common.cancel': 'Cancelar',