# 🛡️ Aegis — Plan de Tareas Completo (V2 + V3) ## Plataforma Avanzada de Gestión y Validación de Cobertura MITRE ATT&CK > **Instrucciones de uso**: Cada tarea (T-XXX) es una unidad de trabajo independiente que debe > resultar en un commit. Están ordenadas secuencialmente — cada tarea puede depender de las > anteriores pero nunca de las posteriores. Cada tarea incluye una sección de validación: > no hagas commit hasta que todos los checks pasen. > > **Contexto**: Este plan se ejecuta DESPUÉS de completar el MVP de Aegis (T-001 a T-036). > Se divide en dos grandes bloques: > - **V2 (T-100 a T-134)**: Flujo Red Team / Blue Team con validación dual, templates y notificaciones > - **V3 (T-200 a T-237)**: Plataforma enterprise con múltiples fuentes, threat actors, scoring, > compliance, campañas y heatmap avanzado --- # PARTE 1 — AEGIS V2: Sistema de Tests de Validación Red Team / Blue Team --- ## Visión General del Flujo de Validación ``` ┌─────────────────────────────────────────────────────────────────────────┐ │ CICLO DE VIDA DE UN TEST │ │ │ │ ┌──────┐ ┌──────────────┐ ┌─────────────────┐ ┌───────────┐ │ │ │ DRAFT│───▶│RED_EXECUTING │───▶│ BLUE_EVALUATING │───▶│ IN_REVIEW │ │ │ └──────┘ └──────────────┘ └─────────────────┘ └───────────┘ │ │ │ │ │ ┌────────────────────┤ │ │ ▼ ▼ │ │ ┌──────────┐ ┌──────────┐ │ │ │ REJECTED │ │VALIDATED │ │ │ └──────────┘ └──────────┘ │ │ │ │ │ └──────▶ Vuelve a DRAFT │ └─────────────────────────────────────────────────────────────────────────┘ Estados del Test: - draft: Creado, pendiente de ejecución por Red Team - red_executing: Red Team documenta ataque y sube evidencias - blue_evaluating: Blue Team documenta detección y sube evidencias - in_review: Ambos managers revisan evidencias - validated: Aprobado por ambos managers - rejected: Rechazado — vuelve a draft para rehacer Estados editables por equipo: - Red Team puede editar en: draft, red_executing - Blue Team puede editar en: blue_evaluating - Evidencias Red se pueden subir/borrar en: draft, red_executing - Evidencias Blue se pueden subir/borrar en: blue_evaluating - Managers validan/rechazan en: in_review Roles involucrados: - red_tech: Crea tests, documenta ataques, sube evidencias de ataque - blue_tech: Documenta detección, sube evidencias de detección - red_lead: Valida/rechaza la parte de Red Team - blue_lead: Valida/rechaza la parte de Blue Team - admin: Acceso total ``` --- ## Catálogo de Tests Básicos por TTP Los tests básicos se obtienen de varias fuentes: 1. **Atomic Red Team** (Red Canary): repositorio open-source con tests atómicos mapeados a MITRE ATT&CK 2. **MITRE ATT&CK procedures**: procedimientos documentados en la propia base de datos de MITRE 3. **Tests personalizados**: creados manualmente por los equipos según su entorno --- ## FASE 10 — Evolución del Modelo de Datos para Red/Blue Team ### T-100: Ampliar estados del Test (TestState) **Objetivo:** Añadir los nuevos estados al ciclo de vida del test que permitan diferenciar las fases de Red Team ejecutando, Blue Team evaluando, y revisión por managers. **Archivos a modificar:** - `backend/app/models/enums.py` **Cambios en `TestState`:** ```python class TestState(str, enum.Enum): draft = "draft" red_executing = "red_executing" # NUEVO: Red Team documentando ataque blue_evaluating = "blue_evaluating" # NUEVO: Blue Team evaluando detección in_review = "in_review" validated = "validated" rejected = "rejected" ``` **Generar migración Alembic** para actualizar el enum en PostgreSQL. **⚠️ IMPORTANTE — Migración de enums en PostgreSQL:** PostgreSQL no permite modificar enums con un simple ALTER TABLE. Alembic no maneja esto bien automáticamente. La migración generada por `--autogenerate` probablemente NO funcione. Hay que escribir la migración manualmente usando: ```python from alembic import op def upgrade(): # PostgreSQL requiere ALTER TYPE para añadir valores a un enum existente op.execute("ALTER TYPE teststate ADD VALUE IF NOT EXISTS 'red_executing' AFTER 'draft'") op.execute("ALTER TYPE teststate ADD VALUE IF NOT EXISTS 'blue_evaluating' AFTER 'red_executing'") def downgrade(): # Downgrade de enums en PostgreSQL es complejo — requiere recrear el tipo # Solo implementar si es estrictamente necesario pass ``` No usar `--autogenerate` para esta migración. Crearla manualmente con `alembic revision -m "add_new_test_states"`. **Validación:** - [ ] `alembic upgrade head` aplica la migración sin errores - [ ] Los tests existentes con estados antiguos siguen funcionando - [ ] Se pueden crear tests con los nuevos estados vía SQL directo: `INSERT INTO tests (..., state) VALUES (..., 'red_executing')` - [ ] `SELECT enum_range(NULL::teststate)` en psql muestra todos los valores incluyendo los nuevos --- ### T-101: Modelo EvidenceTeam — separar evidencias Red/Blue **Objetivo:** Añadir un campo `team` a las evidencias para distinguir si pertenecen al Red Team (evidencia de ataque) o al Blue Team (evidencia de detección). **Archivos a modificar:** - `backend/app/models/enums.py` — añadir enum `TeamSide` - `backend/app/models/evidence.py` — añadir campos `team` y `notes` **Nuevo enum:** ```python class TeamSide(str, enum.Enum): red = "red" blue = "blue" ``` **Nuevos campos en Evidence:** | Campo | Tipo | Restricciones | |-----------|-------------------|----------------------------------| | team | Enum(TeamSide) | not null, default "red" | | notes | Text | nullable (notas sobre la evidencia) | **⚠️ Migración:** Usar la misma técnica de T-100 para crear el enum `teamside` manualmente en PostgreSQL, luego añadir la columna. El default `red` asegura que las evidencias existentes se asignen correctamente. **Generar migración.** **Validación:** - [ ] `alembic upgrade head` añade la columna `team` y `notes` a la tabla `evidences` - [ ] Las evidencias existentes tienen `team = 'red'` por defecto - [ ] Se puede insertar una evidencia con `team = 'blue'` - [ ] La columna `notes` acepta texto largo --- ### T-102: Campos de validación dual en Test (red_lead + blue_lead) **Objetivo:** Extender el modelo Test para soportar validación independiente por Red Lead y Blue Lead, de manera que un test solo pase a `validated` cuando ambos managers lo aprueban. **Archivos a modificar:** - `backend/app/models/test.py` **Deprecar campos existentes del MVP:** Los campos `validated_by` y `validated_at` del MVP quedan obsoletos con la validación dual. La migración debe: 1. Renombrar `validated_by` → `legacy_validated_by` y `validated_at` → `legacy_validated_at` (preservar datos) 2. O bien eliminarlos directamente si no hay datos de producción relevantes Si se decide eliminar, añadir en la migración: ```python op.drop_column('tests', 'validated_by') op.drop_column('tests', 'validated_at') ``` **Nuevos campos:** | Campo | Tipo | Restricciones | |----------------------|----------|----------------------------------------| | red_validated_by | UUID | FK → users.id, nullable | | red_validated_at | DateTime | nullable | | red_validation_status| String | nullable (pending/approved/rejected) | | red_validation_notes | Text | nullable | | blue_validated_by | UUID | FK → users.id, nullable | | blue_validated_at | DateTime | nullable | | blue_validation_status| String | nullable (pending/approved/rejected) | | blue_validation_notes| Text | nullable | | red_summary | Text | nullable (resumen del ataque por red) | | blue_summary | Text | nullable (resumen de detección por blue)| | detection_result | Enum(TestResult) | nullable (resultado de detección blue) | | attack_success | Boolean | nullable (si el ataque tuvo éxito) | **Relaciones nuevas:** ```python red_validator = relationship("User", foreign_keys=[red_validated_by]) blue_validator = relationship("User", foreign_keys=[blue_validated_by]) ``` **Generar migración.** **Validación:** - [ ] `alembic upgrade head` crea las nuevas columnas y elimina/renombra las antiguas sin errores - [ ] Los tests existentes tienen los nuevos campos como `null` - [ ] Se puede actualizar `red_validation_status` y `blue_validation_status` independientemente - [ ] Las FKs a `users.id` funcionan correctamente - [ ] No quedan referencias en el código a los campos `validated_by`/`validated_at` antiguos --- ### T-103: Modelo TestTemplate — catálogo de tests predefinidos **Objetivo:** Crear un modelo para almacenar plantillas de tests predefinidos (basados en Atomic Red Team, MITRE procedures, etc.) que los usuarios pueden instanciar como tests reales. **Archivo a crear:** `backend/app/models/test_template.py` **Campos:** | Campo | Tipo | Restricciones | |--------------------|----------|--------------------------------------------| | id | UUID | PK, default uuid4 | | mitre_technique_id | String | not null (ej: "T1059.001") | | name | String | not null | | description | Text | nullable | | source | String | not null (ej: "atomic_red_team", "mitre", "custom") | | source_url | String | nullable (URL al test original) | | attack_procedure | Text | nullable (procedimiento de ataque sugerido)| | expected_detection | Text | nullable (qué debería detectar blue team) | | platform | String | nullable (windows, linux, macos) | | tool_suggested | String | nullable (herramienta sugerida) | | severity | String | nullable (low, medium, high, critical) | | atomic_test_id | String | nullable (ID del test en Atomic Red Team) | | is_active | Boolean | default True | | created_at | DateTime | default utcnow | **Índices a crear:** ```python Index('ix_test_templates_mitre_technique_id', TestTemplate.mitre_technique_id) Index('ix_test_templates_source', TestTemplate.source) Index('ix_test_templates_platform', TestTemplate.platform) Index('ix_test_templates_severity', TestTemplate.severity) ``` **Actualizar** `models/__init__.py` para importar TestTemplate. **Generar migración.** **Validación:** - [ ] `alembic upgrade head` crea la tabla `test_templates` con los índices - [ ] Se puede insertar un template con todos los campos - [ ] El campo `source` acepta los valores esperados - [ ] La tabla soporta múltiples templates para la misma técnica MITRE - [ ] `EXPLAIN` de una query filtrando por `mitre_technique_id` muestra uso del índice --- ### T-104: Schemas Pydantic para los nuevos modelos **Objetivo:** Crear schemas de request/response para los modelos modificados y nuevos. **Archivos a crear/modificar:** - `backend/app/schemas/test.py` — actualizar con nuevos campos - `backend/app/schemas/evidence.py` — añadir `team` y `notes` - `backend/app/schemas/test_template.py` — nuevo **Schemas de Test actualizados:** - `TestOut`: añadir campos de validación dual (`red_validated_by`, `blue_validated_by`, `red_validation_status`, `blue_validation_status`, `red_summary`, `blue_summary`, etc.). Eliminar referencias a los campos `validated_by`/`validated_at` antiguos. - `TestRedUpdate`: name, description, procedure_text, tool_used, attack_success, red_summary (campos que rellena Red Team) - `TestBlueUpdate`: detection_result, blue_summary (campos que rellena Blue Team) - `TestRedValidate`: red_validation_status (approved/rejected), red_validation_notes - `TestBlueValidate`: blue_validation_status (approved/rejected), blue_validation_notes **Schemas de Evidence actualizados:** - `EvidenceOut`: añadir `team` y `notes` - `EvidenceUpload`: añadir `team` (requerido) y `notes` (opcional) **Schemas de TestTemplate:** - `TestTemplateOut`: todos los campos - `TestTemplateCreate`: para crear templates personalizados - `TestTemplateSummary`: id, mitre_technique_id, name, source, platform, severity (para listados) - `TestTemplateInstantiate`: template_id, technique_id (para crear un test real desde un template) **Validación:** - [ ] Todos los schemas se importan sin errores - [ ] `TestOut` incluye los campos de validación dual y NO incluye los antiguos - [ ] `TestTemplateCreate` valida correctamente los campos requeridos - [ ] `EvidenceOut` incluye `team` y `notes` --- ### T-105: Índices de base de datos para V2 **Objetivo:** Crear índices para los campos que se usarán frecuentemente en filtros y consultas, evitando queries lentas a medida que crece el volumen de datos. **Archivo a crear:** migración Alembic manual **Índices a crear:** ```python # Tests Index('ix_tests_state', Test.state) Index('ix_tests_technique_id', Test.technique_id) Index('ix_tests_created_by', Test.created_by) Index('ix_tests_red_validation_status', Test.red_validation_status) Index('ix_tests_blue_validation_status', Test.blue_validation_status) # Evidences Index('ix_evidences_test_id', Evidence.test_id) Index('ix_evidences_team', Evidence.team) # Techniques (si no existen ya del MVP) Index('ix_techniques_tactic', Technique.tactic) Index('ix_techniques_status_global', Technique.status_global) Index('ix_techniques_review_required', Technique.review_required) ``` **Validación:** - [ ] `alembic upgrade head` crea todos los índices - [ ] `\di` en psql lista los nuevos índices - [ ] `EXPLAIN ANALYZE` de una query filtrando tests por `state` muestra Index Scan --- ## FASE 11 — Lógica de Negocio del Flujo Red/Blue ### T-106: Servicio de transiciones de estado del Test **Objetivo:** Crear un servicio que controle las transiciones de estado válidas del test y garantice que solo se puedan hacer los cambios permitidos. **Archivo a crear:** `backend/app/services/test_workflow_service.py` **Transiciones válidas:** ```python VALID_TRANSITIONS = { TestState.draft: [TestState.red_executing], TestState.red_executing: [TestState.blue_evaluating], TestState.blue_evaluating: [TestState.in_review], TestState.in_review: [TestState.validated, TestState.rejected], TestState.rejected: [TestState.draft], TestState.validated: [], # estado final (o puede reabrirse) } ``` **Funciones a implementar:** - `can_transition(test: Test, target_state: TestState) -> bool` - `transition_state(db, test, target_state, user) -> Test` — valida transición, cambia estado, log de auditoría - `start_execution(db, test, user) -> Test` — mueve de `draft` a `red_executing` - `submit_red_evidence(db, test, user) -> Test` — marca como `blue_evaluating` cuando Red Team termina - `submit_blue_evidence(db, test, user) -> Test` — marca como `in_review` cuando Blue Team termina - `validate_as_red_lead(db, test, user, status, notes) -> Test` — valida parte Red - `validate_as_blue_lead(db, test, user, status, notes) -> Test` — valida parte Blue - `check_dual_validation(db, test) -> Test` — si ambos aprobaron, pasa a validated; si alguno rechazó, pasa a rejected - `reopen_test(db, test, user) -> Test` — mueve de `rejected` a `draft`, limpia campos de validación **Validación:** - [ ] Transición draft → red_executing funciona - [ ] Transición draft → validated falla (no permitida) - [ ] Transición red_executing → blue_evaluating funciona - [ ] `check_dual_validation` pasa a validated solo si ambos managers aprobaron - [ ] `check_dual_validation` pasa a rejected si algún manager rechazó - [ ] `reopen_test` limpia `red_validation_status`, `blue_validation_status` y campos asociados - [ ] Cada transición genera un log de auditoría --- ### T-107: Actualizar servicio de recalculación de status **Objetivo:** Mejorar `status_service.py` para tener en cuenta los nuevos estados y la validación dual. **Archivo a modificar:** `backend/app/services/status_service.py` **Nueva lógica:** ```python def recalculate_technique_status(db, technique): tests = technique.tests if not tests: technique.status_global = TechniqueStatus.not_evaluated elif all(t.state == TestState.validated for t in tests): # Todos validados — revisar resultados de detección results = [t.detection_result for t in tests if t.detection_result] if all(r == "detected" for r in results): technique.status_global = TechniqueStatus.validated elif any(r == "partially_detected" for r in results): technique.status_global = TechniqueStatus.partial else: technique.status_global = TechniqueStatus.not_covered elif any(t.state == TestState.validated for t in tests): technique.status_global = TechniqueStatus.partial else: technique.status_global = TechniqueStatus.in_progress db.commit() ``` **Validación:** - [ ] Sin tests → `not_evaluated` - [ ] Todos validated con detection=detected → `validated` - [ ] Algunos validated, otros en progreso → `partial` - [ ] Todos en estados intermedios → `in_progress` - [ ] Todos validated con detection=not_detected → `not_covered` --- ### T-108: Servicio de importación de Atomic Red Team **Objetivo:** Crear un servicio que importe tests predefinidos desde el repositorio de Atomic Red Team de Red Canary y los almacene como TestTemplates. **Archivo a crear:** `backend/app/services/atomic_import_service.py` **⚠️ Estrategia de descarga desde GitHub:** La API de GitHub sin autenticación solo permite 60 requests/hora. El repositorio de Atomic Red Team tiene 1500+ archivos YAML, por lo que NO se puede hacer un request por archivo. La estrategia correcta es: 1. **Opción preferida:** Descargar el ZIP del repositorio completo via `https://github.com/redcanaryco/atomic-red-team/archive/refs/heads/master.zip` 2. Descomprimir en memoria o en directorio temporal 3. Parsear todos los ficheros YAML de `atomics/T*/T*.yaml` 4. Limpiar el directorio temporal al finalizar Alternativamente, si se quiere usar la API de GitHub, configurar un token de acceso personal en settings (`GITHUB_TOKEN`) para tener 5000 requests/hora. **Lógica:** 1. Descargar ZIP del repositorio de Atomic Red Team 2. Descomprimir y localizar ficheros YAML en `atomics/` 3. Para cada archivo YAML (organizados por técnica MITRE `atomics/T1059.001/T1059.001.yaml`): - Parsear el YAML que contiene una lista de `atomic_tests` - Cada test atómico tiene: `name`, `description`, `supported_platforms`, `executor` (tipo y command) 4. Por cada test atómico: - Crear un `TestTemplate` con `source = "atomic_red_team"` - Setear `atomic_test_id` con el ID del test (formato `{technique_id}-{index}`) - Setear `platform` desde `supported_platforms` - Setear `attack_procedure` desde `executor.command` - Mapear a la técnica MITRE correspondiente 5. No duplicar templates que ya existen (comparar por `atomic_test_id`) 6. Log de auditoría con resumen **Validación:** - [ ] Ejecutar la importación crea TestTemplates en la BD - [ ] Cada template tiene `source = "atomic_red_team"` y datos válidos - [ ] Ejecutar dos veces no duplica templates - [ ] Los templates se mapean correctamente a técnicas MITRE existentes - [ ] Se importan al menos 500+ templates - [ ] La descarga del ZIP funciona sin alcanzar rate limits --- ## FASE 12 — Endpoints API Red/Blue ### T-109: Endpoints actualizados de Tests con flujo Red/Blue **Objetivo:** Modificar y añadir endpoints al router de tests para soportar el nuevo flujo de trabajo. **Archivo a modificar:** `backend/app/routers/tests.py` **Endpoints nuevos/modificados:** | Método | Ruta | Auth | Descripción | |--------|-----------------------------------|----------------------|------------------------------------------------| | GET | /tests | autenticado | Listar tests con filtros (state, technique_id) | | POST | /tests | red_tech, admin | Crear test (nuevo o desde template) | | POST | /tests/from-template | red_tech, admin | Crear test instanciando un template | | GET | /tests/{id} | autenticado | Detalle con evidencias separadas red/blue | | PATCH | /tests/{id}/red | red_tech, admin | Red Team actualiza su parte | | PATCH | /tests/{id}/blue | blue_tech, admin | Blue Team actualiza su parte | | POST | /tests/{id}/start-execution | red_tech, admin | Mover de draft → red_executing | | POST | /tests/{id}/submit-red | red_tech, admin | Red Team finaliza → pasa a blue_evaluating | | POST | /tests/{id}/submit-blue | blue_tech, admin | Blue Team finaliza → pasa a in_review | | POST | /tests/{id}/validate-red | red_lead, admin | Red Lead valida/rechaza parte red | | POST | /tests/{id}/validate-blue | blue_lead, admin | Blue Lead valida/rechaza parte blue | | POST | /tests/{id}/reopen | red_lead, blue_lead, admin | Reabrir test rechazado → draft | | GET | /tests/{id}/timeline | autenticado | Timeline de cambios de estado del test | **Estados permitidos para edición:** - `PATCH /tests/{id}/red`: permitido en `draft` y `red_executing` (Red Team prepara y ejecuta) - `PATCH /tests/{id}/blue`: permitido solo en `blue_evaluating` - `POST /tests/{id}/start-execution`: solo desde `draft` - `POST /tests/{id}/submit-red`: solo desde `red_executing` - `POST /tests/{id}/submit-blue`: solo desde `blue_evaluating` **Detalle del endpoint GET /tests/{id}:** La respuesta debe incluir: ```json { "id": "...", "name": "...", "state": "blue_evaluating", "red_evidences": [], "blue_evidences": [], "red_summary": "...", "blue_summary": "...", "attack_success": true, "detection_result": "detected", "red_validation_status": "approved", "blue_validation_status": "pending", "timeline": [] } ``` **Validación:** - [ ] `POST /tests` crea un test en estado `draft` - [ ] `POST /tests/from-template` crea un test con datos pre-rellenados del template - [ ] `POST /tests/{id}/start-execution` mueve de draft a red_executing - [ ] `PATCH /tests/{id}/red` funciona en `draft` y `red_executing` - [ ] `PATCH /tests/{id}/red` falla en `blue_evaluating` (400) - [ ] `PATCH /tests/{id}/blue` solo funciona en `blue_evaluating` - [ ] `POST /tests/{id}/submit-red` cambia estado a `blue_evaluating` - [ ] `POST /tests/{id}/submit-blue` cambia estado a `in_review` - [ ] `POST /tests/{id}/validate-red` solo accesible por red_lead/admin - [ ] `POST /tests/{id}/validate-blue` solo accesible por blue_lead/admin - [ ] Cuando ambos validan como approved → test pasa a `validated` - [ ] Cuando alguno rechaza → test pasa a `rejected` - [ ] `POST /tests/{id}/reopen` solo funciona en tests `rejected` - [ ] `GET /tests/{id}/timeline` retorna el historial ordenado cronológicamente - [ ] Cada operación genera audit log --- ### T-110: Endpoints de Evidence con separación Red/Blue **Objetivo:** Modificar el router de evidencias para soportar la separación por equipo. **Archivo a modificar:** `backend/app/routers/evidence.py` **Endpoints modificados:** | Método | Ruta | Auth | Descripción | |--------|-----------------------------------|-----------------|----------------------------------------------| | POST | /tests/{test_id}/evidence | autenticado | Subir evidencia indicando team (red/blue) | | GET | /tests/{test_id}/evidence | autenticado | Listar evidencias del test, filtrable por team | | GET | /evidence/{id} | autenticado | Obtener URL pre-firmada | | DELETE | /evidence/{id} | creador o admin | Eliminar evidencia (solo en estados editables)| **Lógica de control explícita:** - Red Team (`red_tech`) solo puede subir evidencias con `team=red` cuando el test está en `draft` o `red_executing` - Blue Team (`blue_tech`) solo puede subir evidencias con `team=blue` cuando el test está en `blue_evaluating` - Admin puede subir en cualquier momento con cualquier `team` - DELETE de evidencias Red: permitido en `draft` y `red_executing` - DELETE de evidencias Blue: permitido en `blue_evaluating` - DELETE en estados `in_review`, `validated`, `rejected`: NO permitido (403) **Validación:** - [ ] Un `red_tech` puede subir evidencia con `team=red` en estado `red_executing` - [ ] Un `red_tech` puede subir evidencia con `team=red` en estado `draft` - [ ] Un `red_tech` NO puede subir evidencia con `team=blue` (403) - [ ] Un `blue_tech` puede subir evidencia con `team=blue` en estado `blue_evaluating` - [ ] Un `blue_tech` NO puede subir evidencia con `team=red` (403) - [ ] `GET /tests/{id}/evidence?team=red` filtra correctamente - [ ] `DELETE /evidence/{id}` en estado `in_review` → 403 - [ ] `DELETE /evidence/{id}` en estado `red_executing` para evidencia red → 200 - [ ] Admin puede subir cualquier tipo de evidencia en cualquier momento --- ### T-111: Endpoints CRUD de TestTemplates **Objetivo:** Crear endpoints para gestionar el catálogo de templates de tests. **Archivo a crear:** `backend/app/routers/test_templates.py` **Endpoints:** | Método | Ruta | Auth | Descripción | |--------|-----------------------------------|-----------------|----------------------------------------------| | GET | /test-templates | autenticado | Listar templates con filtros | | GET | /test-templates/{id} | autenticado | Detalle de un template | | POST | /test-templates | admin | Crear template personalizado | | PATCH | /test-templates/{id} | admin | Actualizar template | | DELETE | /test-templates/{id} | admin | Desactivar template (soft delete) | | GET | /test-templates/by-technique/{mitre_id} | autenticado | Templates para una técnica MITRE específica | **Filtros del GET /test-templates:** - `source`: atomic_red_team, mitre, custom - `platform`: windows, linux, macos - `severity`: low, medium, high, critical - `mitre_technique_id`: filtrar por técnica - `search`: búsqueda por nombre/descripción - Paginación: `offset` + `limit` (default limit=50) **Validación:** - [ ] `GET /test-templates` retorna lista paginada - [ ] `GET /test-templates?source=atomic_red_team` filtra por fuente - [ ] `GET /test-templates?platform=windows` filtra por plataforma - [ ] `GET /test-templates/by-technique/T1059.001` retorna templates para esa técnica - [ ] `POST /test-templates` solo accesible por admin - [ ] `DELETE /test-templates/{id}` hace soft delete (is_active=False) - [ ] El filtro `search` busca en name y description --- ### T-112: Endpoint de importación de Atomic Red Team **Objetivo:** Exponer la importación de Atomic Red Team como endpoint del sistema. **Archivo a modificar:** `backend/app/routers/system.py` **Endpoint:** ``` POST /api/v1/system/import-atomic-tests Auth: admin only Response: {"message": "Import completed", "imported": X, "skipped": Y, "errors": Z} ``` **Validación:** - [ ] `POST /system/import-atomic-tests` ejecuta la importación y retorna estadísticas - [ ] Solo admin puede ejecutar - [ ] Audit log registra la importación - [ ] Ejecutar dos veces no duplica — incrementa `skipped` --- ## FASE 13 — Frontend: Tipos y API Clients ### T-113: Actualizar tipos TypeScript **Objetivo:** Actualizar los tipos del frontend para reflejar los cambios del backend. **Archivo a modificar:** `frontend/src/types/models.ts` **Tipos a añadir/modificar:** ```typescript // Actualizar TestState export type TestState = | "draft" | "red_executing" | "blue_evaluating" | "in_review" | "validated" | "rejected"; // Nuevo tipo TeamSide export type TeamSide = "red" | "blue"; // Estados editables por equipo export const RED_EDITABLE_STATES: TestState[] = ["draft", "red_executing"]; export const BLUE_EDITABLE_STATES: TestState[] = ["blue_evaluating"]; // Actualizar Evidence export interface Evidence { id: string; test_id: string; file_name: string; file_path: string; sha256_hash: string; uploaded_by: string | null; uploaded_at: string; team: TeamSide; notes: string | null; } // Actualizar Test con campos duales export interface Test { id: string; technique_id: string; name: string; description: string | null; platform: string | null; procedure_text: string | null; tool_used: string | null; state: TestState; created_by: string | null; created_at: string; red_summary: string | null; blue_summary: string | null; attack_success: boolean | null; detection_result: TestResult | null; red_validation_status: ValidationStatus | null; blue_validation_status: ValidationStatus | null; red_validation_notes: string | null; blue_validation_notes: string | null; red_validated_by: string | null; blue_validated_by: string | null; red_evidences: Evidence[]; blue_evidences: Evidence[]; } export type ValidationStatus = "pending" | "approved" | "rejected"; // Nuevo tipo TestTemplate export interface TestTemplate { id: string; mitre_technique_id: string; name: string; description: string | null; source: string; source_url: string | null; attack_procedure: string | null; expected_detection: string | null; platform: string | null; tool_suggested: string | null; severity: string | null; atomic_test_id: string | null; is_active: boolean; created_at: string; } // Timeline export interface TestTimelineEntry { id: string; action: string; user: string; timestamp: string; details: Record; } ``` **Validación:** - [ ] TypeScript compila sin errores - [ ] Todos los tipos nuevos están exportados - [ ] Los tipos coinciden con los schemas del backend - [ ] No hay referencias a los tipos antiguos `validated_by`/`validated_at` --- ### T-114: Nuevos API clients **Objetivo:** Crear/actualizar los clientes API del frontend para los nuevos endpoints. **Archivos a crear/modificar:** - `frontend/src/api/tests.ts` — actualizar con nuevos endpoints - `frontend/src/api/evidence.ts` — actualizar con parámetro `team` - `frontend/src/api/test-templates.ts` — nuevo **Funciones nuevas en tests.ts:** ```typescript export const createTestFromTemplate = (templateId: string, techniqueId: string) => ... export const updateTestRed = (testId: string, data: RedUpdateData) => ... export const updateTestBlue = (testId: string, data: BlueUpdateData) => ... export const startExecution = (testId: string) => ... export const submitRedEvidence = (testId: string) => ... export const submitBlueEvidence = (testId: string) => ... export const validateAsRedLead = (testId: string, data: RedValidation) => ... export const validateAsBlueLead = (testId: string, data: BlueValidation) => ... export const reopenTest = (testId: string) => ... export const getTestTimeline = (testId: string) => ... ``` **Funciones nuevas en evidence.ts:** ```typescript export const uploadEvidence = (testId: string, file: File, team: TeamSide, notes?: string) => ... export const getTestEvidences = (testId: string, team?: TeamSide) => ... export const deleteEvidence = (evidenceId: string) => ... ``` **Funciones en test-templates.ts:** ```typescript export const getTemplates = (filters?: TemplateFilters) => ... export const getTemplateById = (id: string) => ... export const getTemplatesByTechnique = (mitreId: string) => ... export const createTemplate = (data: CreateTemplate) => ... export const importAtomicTests = () => ... ``` **Validación:** - [ ] Todos los imports funcionan sin errores TypeScript - [ ] Cada función envía la petición al endpoint correcto - [ ] `uploadEvidence` incluye el campo `team` en FormData - [ ] `getTestEvidences` envía el query param `team` correctamente --- ## FASE 14 — Frontend: Página de Test Rediseñada con Pestañas Red/Blue ### T-115: Componente TestDetailHeader **Objetivo:** Crear el header del detalle del test con información del estado, progreso y acciones contextuales. **Archivo a crear:** `frontend/src/components/test-detail/TestDetailHeader.tsx` **Contenido:** - Nombre del test y badge de estado con color - Barra de progreso visual (5 pasos: draft → red → blue → review → validated) - Nombre de la técnica asociada (link) - Botones de acción contextuales según rol y estado: - Red Tech en `draft`: botón "Start Execution" - Red Tech en `red_executing`: botón "Submit to Blue Team" - Blue Tech en `blue_evaluating`: botón "Submit for Review" - Red Lead en `in_review`: botón "Approve/Reject Red" - Blue Lead en `in_review`: botón "Approve/Reject Blue" - Indicadores de validación dual (checkmarks para red_lead y blue_lead) **Validación:** - [ ] El header muestra toda la información correcta - [ ] La barra de progreso refleja el estado actual - [ ] Los botones aparecen solo cuando el rol y estado lo permiten - [ ] El botón "Start Execution" aparece solo en draft para red_tech - [ ] Los indicadores de validación dual se actualizan correctamente --- ### T-116: Componente de pestañas Red Team / Blue Team **Objetivo:** Crear el sistema de pestañas que separa las evidencias y el contenido entre Red Team y Blue Team. **Archivo a crear:** `frontend/src/components/test-detail/TeamTabs.tsx` **Estructura de pestañas:** ``` ┌──────────────────────────────────────────────────────────────┐ │ [🔴 Red Team] [🔵 Blue Team] [📋 Summary] [📜 Timeline] │ ├──────────────────────────────────────────────────────────────┤ │ │ │ Contenido de la pestaña seleccionada │ │ │ └──────────────────────────────────────────────────────────────┘ ``` **Pestaña Red Team:** - Procedimiento de ataque (editable en `draft` y `red_executing`) - Herramienta utilizada (editable en `draft` y `red_executing`) - Indicador de éxito del ataque (switch: sí/no) - Resumen del Red Team (textarea) - Lista de evidencias Red con upload (solo en `draft` y `red_executing` para red_tech) - Estado de validación del Red Lead (si aplica) **Pestaña Blue Team:** - Resultado de detección (detected/not_detected/partially_detected) - Resumen del Blue Team (textarea) - Lista de evidencias Blue con upload (solo en `blue_evaluating` para blue_tech) - Estado de validación del Blue Lead (si aplica) **Pestaña Summary:** - Vista resumen con ambos lados lado a lado - Comparativa visual: ataque vs detección - Resultado final **Pestaña Timeline:** - Historial cronológico de todos los cambios del test - Cada entrada con usuario, acción, fecha y detalles **Validación:** - [ ] Las pestañas se renderizan correctamente - [ ] Cambiar de pestaña muestra el contenido correcto - [ ] Los campos son editables solo en el estado y rol apropiados - [ ] Upload de evidencias funciona dentro de cada pestaña - [ ] La pestaña Summary muestra comparativa correcta --- ### T-117: Página TestDetailPage rediseñada **Objetivo:** Integrar los nuevos componentes en la página de detalle del test, reemplazando el diseño actual. **Archivo a modificar:** `frontend/src/pages/TestDetailPage.tsx` **Estructura:** ``` ┌─────────────────────────────────────────────────────────┐ │ TestDetailHeader (estado, progreso, acciones) │ ├─────────────────────────────────────────────────────────┤ │ │ │ TeamTabs │ │ ┌─────────────────────────────────────────────────────┐│ │ │ Pestaña seleccionada (Red/Blue/Summary/Timeline) ││ │ └─────────────────────────────────────────────────────┘│ │ │ ├─────────────────────────────────────────────────────────┤ │ Sidebar: Metadata del test │ │ - Técnica asociada │ │ - Plataforma │ │ - Creador │ │ - Fechas │ │ - Template origen (si aplica) │ └─────────────────────────────────────────────────────────┘ ``` **Interacciones:** - Toda acción usa mutations de react-query con invalidación - Modales de confirmación para validar/rechazar - Toast notifications para feedback - Loading states en todas las operaciones **Validación:** - [ ] La página carga y muestra todos los datos del test - [ ] Las pestañas Red/Blue/Summary/Timeline funcionan - [ ] Las acciones de validación dual funcionan correctamente - [ ] La transición de estado se refleja en tiempo real tras cada acción - [ ] Los permisos de edición se respetan según rol y estado - [ ] La subida de evidencias funciona dentro de las pestañas --- ### T-118: Modal de Validación Dual **Objetivo:** Crear un modal de validación que permita a los managers aprobar o rechazar su parte del test, con notas obligatorias en caso de rechazo. **Archivo a crear:** `frontend/src/components/test-detail/ValidationModal.tsx` **Contenido:** - Título: "Validate as Red Lead" / "Validate as Blue Lead" - Resumen de evidencias del equipo correspondiente - Opciones: Approve / Reject - Textarea para notas (obligatorio en rechazo) - Indicador visual del estado de la otra validación - Botón de confirmar con loading state **Validación:** - [ ] El modal aparece al hacer click en Validate - [ ] Se puede seleccionar Approve o Reject - [ ] Reject requiere notas obligatorias — botón deshabilitado sin notas - [ ] Approve envía la petición y cierra el modal - [ ] Se muestra el estado de la validación del otro manager - [ ] Loading state funciona durante la petición --- ## FASE 15 — Frontend: Catálogo de Tests y Creación desde Templates ### T-119: Página de catálogo de TestTemplates **Objetivo:** Crear una página donde los usuarios puedan explorar el catálogo de tests disponibles, filtrar por técnica, plataforma y fuente, y ver el detalle de cada template. **Archivo a crear:** `frontend/src/pages/TestCatalogPage.tsx` **Componentes necesarios:** - Barra de búsqueda y filtros (source, platform, severity, technique) - Grid/lista de templates con cards - Cada card muestra: nombre, técnica MITRE, plataforma, severidad, fuente (badge), botón "Use Template" - Paginación **Ruta:** `/test-catalog` — añadir al router y al sidebar. **Validación:** - [ ] La página carga y muestra templates del backend - [ ] Los filtros funcionan (source, platform, severity, search) - [ ] Cada card muestra la información correcta - [ ] El botón "Use Template" navega o abre modal de instanciación - [ ] Responsive en móvil y desktop --- ### T-120: Modal/Página de instanciación de Template **Objetivo:** Permitir crear un test real a partir de un template, pre-rellenando los campos y permitiendo modificaciones. **Archivo a crear:** `frontend/src/components/TestFromTemplateForm.tsx` **Flujo:** 1. El usuario selecciona un template (desde el catálogo o desde la vista de técnica) 2. Se abre un formulario pre-rellenado con los datos del template 3. El usuario puede modificar los campos 4. Al guardar, se crea un test real con `state=draft` **Campos del formulario:** - Nombre (pre-rellenado) - Descripción (pre-rellenado) - Técnica asociada (pre-rellenado si se viene de una técnica) - Plataforma (pre-rellenado) - Procedimiento de ataque sugerido (pre-rellenado, editable) - Herramienta sugerida (pre-rellenado, editable) - Detección esperada (pre-rellenado, readonly — referencia para blue team) **Validación:** - [ ] El formulario se pre-rellena con datos del template - [ ] Se puede modificar cualquier campo editable - [ ] Submit crea el test y redirige al detalle - [ ] El test creado tiene referencia al template origen - [ ] Campos requeridos se validan antes de submit --- ### T-121: Integrar catálogo en vista de Técnica **Objetivo:** Desde la página de detalle de una técnica, permitir ver los templates disponibles y crear tests directamente. **Archivo a modificar:** `frontend/src/pages/TechniqueDetailPage.tsx` **Cambios:** - Añadir sección "Available Test Templates" debajo de los tests existentes - Mostrar cards resumidas de templates disponibles para esa técnica - Botón "Run This Test" en cada template que abre el formulario de instanciación - Si no hay templates, mostrar mensaje y link al catálogo general **Validación:** - [ ] La sección de templates aparece en la página de técnica - [ ] Se muestran solo los templates para esa técnica MITRE - [ ] "Run This Test" pre-rellena correctamente el formulario - [ ] Si no hay templates se muestra mensaje apropiado - [ ] La creación del test actualiza la lista de tests de la técnica --- ## FASE 16 — Frontend: Vistas de Gestión y Dashboard Mejorado ### T-122: Vista de Tests mejorada con filtros por estado y equipo **Objetivo:** Mejorar la página de listado de tests con filtros avanzados y vistas específicas por equipo. **Archivo a modificar:** `frontend/src/pages/TestsPage.tsx` **Mejoras:** - Filtros: por estado (todos los nuevos estados), por equipo asignado, por técnica, por plataforma - Vista de "Mis tareas pendientes" según rol: - Red Tech: tests en `draft` o `red_executing` creados por mí - Blue Tech: tests en `blue_evaluating` - Red Lead: tests en `in_review` pendientes de validación red - Blue Lead: tests en `in_review` pendientes de validación blue - Estadísticas rápidas: contadores por estado (cards superiores) - Tabla con columnas: nombre, técnica, estado, equipo actual, última actualización, acciones **Validación:** - [ ] Los filtros por estado funcionan con los nuevos estados - [ ] "Mis tareas pendientes" filtra correctamente según el rol del usuario - [ ] Los contadores por estado son correctos - [ ] La tabla muestra toda la información necesaria - [ ] Click en un test navega al detalle --- ### T-123: Dashboard mejorado con métricas Red/Blue **Objetivo:** Añadir al dashboard métricas específicas del flujo de validación Red/Blue. **Archivos a modificar:** - `backend/app/routers/metrics.py` — añadir nuevos endpoints - `backend/app/schemas/metrics.py` — añadir nuevos schemas - `frontend/src/pages/DashboardPage.tsx` — añadir nuevas secciones **Nuevos endpoints de métricas:** ``` GET /metrics/test-pipeline → contadores por estado del pipeline GET /metrics/team-activity → actividad por equipo (tests completados, pendientes) GET /metrics/validation-rate → tasa de aprobación/rechazo por manager ``` **Nuevas secciones del dashboard:** 1. **Pipeline de Tests**: gráfico de funnel mostrando cuántos tests hay en cada estado 2. **Actividad por equipo**: Red Team vs Blue Team — tests completados, tiempo medio 3. **Tasa de validación**: porcentaje de aprobación por Red Lead y Blue Lead 4. **Tests recientes**: tabla con los últimos 10 tests actualizados **Validación:** - [ ] Los nuevos endpoints retornan datos correctos - [ ] El dashboard muestra las nuevas secciones - [ ] El pipeline de tests refleja los estados reales - [ ] Las métricas de equipo se calculan correctamente - [ ] La sección de tests recientes se actualiza --- ### T-124: Panel de administración de Templates **Objetivo:** Añadir al panel de sistema la gestión de templates: importar Atomic Red Team, crear templates personalizados, ver estadísticas del catálogo. **Archivo a modificar:** `frontend/src/pages/SystemPage.tsx` **Nuevas secciones:** 1. **Importar Atomic Red Team**: botón para ejecutar importación, con progreso y resultado 2. **Estadísticas del catálogo**: total templates, por fuente, por plataforma 3. **Crear template personalizado**: formulario inline o modal 4. **Gestionar templates**: tabla con opción de activar/desactivar **Validación:** - [ ] Botón de importación ejecuta y muestra resultados - [ ] Las estadísticas del catálogo se muestran correctamente - [ ] Se puede crear un template personalizado - [ ] Se puede desactivar un template - [ ] Solo admin puede acceder a estas funciones --- ## FASE 17 — Backend Tests Automatizados ### T-125: Tests del flujo de trabajo Red/Blue **Objetivo:** Crear tests automatizados que verifiquen todo el ciclo de vida de un test de seguridad. **Archivo a crear:** `backend/tests/test_workflow.py` **Tests a implementar:** ```python class TestWorkflow: def test_full_happy_path(): """draft → red_executing → blue_evaluating → in_review → validated""" def test_rejection_and_reopen(): """in_review → rejected → draft → red_executing → ...""" def test_invalid_transitions(): """Verificar que transiciones no válidas fallan""" def test_red_tech_cannot_access_blue_phase(): """Red tech no puede editar en blue_evaluating""" def test_blue_tech_cannot_access_red_phase(): """Blue tech no puede editar en red_executing""" def test_dual_validation_both_approve(): """Ambos managers aprueban → validated""" def test_dual_validation_one_rejects(): """Un manager rechaza → rejected""" def test_evidence_team_separation(): """Evidencias red y blue se separan correctamente""" def test_red_edit_allowed_in_draft_and_red_executing(): """PATCH /tests/{id}/red funciona en draft y red_executing""" def test_reopen_clears_validation_fields(): """Reopen limpia red/blue_validation_status y campos asociados""" ``` **Validación:** - [ ] `pytest tests/test_workflow.py` ejecuta todos los tests - [ ] Todos los tests pasan (verde) - [ ] Cobertura del flujo completo --- ### T-126: Tests de TestTemplates **Objetivo:** Tests automatizados para el CRUD de templates y la instanciación. **Archivo a crear:** `backend/tests/test_templates.py` **Tests:** ```python class TestTemplates: def test_create_template(): """Admin puede crear un template""" def test_list_templates_with_filters(): """Filtros de source, platform, severity funcionan""" def test_get_templates_by_technique(): """Filtrar templates por técnica MITRE""" def test_instantiate_template(): """Crear test desde template pre-rellena campos""" def test_soft_delete_template(): """Desactivar template no lo borra físicamente""" def test_non_admin_cannot_create_template(): """Solo admin puede crear templates""" ``` **Validación:** - [ ] `pytest tests/test_templates.py` pasa todos los tests - [ ] Cobertura de CRUD y filtros - [ ] Cobertura de permisos --- ### T-127: Tests de métricas actualizadas **Objetivo:** Tests automatizados para los nuevos endpoints de métricas. **Archivo a crear:** `backend/tests/test_metrics_v2.py` **Tests:** ```python class TestMetricsV2: def test_pipeline_metrics(): """Contadores por estado del pipeline correctos""" def test_team_activity_metrics(): """Actividad por equipo calculada correctamente""" def test_technique_status_recalculation_with_new_states(): """Recalculación funciona con los nuevos estados""" def test_coverage_with_dual_validation(): """Cobertura correcta tras validación dual""" ``` **Validación:** - [ ] `pytest tests/test_metrics_v2.py` pasa todos los tests - [ ] Las métricas coinciden con los datos de prueba --- ## FASE 18 — Notificaciones y Sidebar de Actividad ### T-128: Modelo de notificaciones **Objetivo:** Crear un sistema básico de notificaciones in-app para alertar a los usuarios cuando necesitan actuar. **Archivo a crear:** `backend/app/models/notification.py` **Campos:** | Campo | Tipo | Restricciones | |-----------|----------|------------------------------------| | id | UUID | PK, default uuid4 | | user_id | UUID | FK → users.id, not null | | type | String | not null (test_assigned, validation_needed, test_rejected, etc.) | | title | String | not null | | message | Text | nullable | | entity_type | String | nullable (test, technique) | | entity_id | UUID | nullable | | read | Boolean | default False | | created_at| DateTime | default utcnow | **Índices:** ```python Index('ix_notifications_user_id', Notification.user_id) Index('ix_notifications_read', Notification.read) Index('ix_notifications_created_at', Notification.created_at) ``` **Generar migración.** **Servicio** `backend/app/services/notification_service.py`: ```python def create_notification(db, user_id, type, title, message, entity_type, entity_id) def mark_as_read(db, notification_id, user_id) def mark_all_as_read(db, user_id) def get_unread_count(db, user_id) -> int def cleanup_old_notifications(db, days=90) -> int # Elimina notificaciones leídas > 90 días ``` **Disparar notificaciones automáticamente:** - Cuando un test pasa a `red_executing` → notificar al creador (confirmación) - Cuando un test pasa a `blue_evaluating` → notificar a todos los `blue_tech` - Cuando un test pasa a `in_review` → notificar a `red_lead` y `blue_lead` - Cuando un test es rechazado → notificar al creador - Cuando un test es validado → notificar al creador **Job de limpieza:** Programar un job APScheduler diario que ejecute `cleanup_old_notifications(db, days=90)`. **Validación:** - [ ] Se crea una notificación cuando un test cambia a `blue_evaluating` - [ ] Se crea una notificación para managers cuando un test llega a `in_review` - [ ] Se crea una notificación al creador cuando un test es rechazado - [ ] Se crea una notificación al creador cuando un test es validado - [ ] `get_unread_count` retorna el número correcto - [ ] `cleanup_old_notifications` elimina notificaciones antiguas leídas --- ### T-129: Endpoints y frontend de notificaciones **Objetivo:** Endpoints API y UI de notificaciones. **Archivos a crear:** - `backend/app/routers/notifications.py` - `frontend/src/api/notifications.ts` - `frontend/src/components/NotificationBell.tsx` - `frontend/src/components/NotificationDropdown.tsx` **Endpoints:** | Método | Ruta | Auth | Descripción | |--------|-----------------------------|-------------|-------------------------------| | GET | /notifications | autenticado | Listar notificaciones del user (paginado, limit=20, offset) | | GET | /notifications/unread-count | autenticado | Contador de no leídas | | PATCH | /notifications/{id}/read | autenticado | Marcar como leída | | POST | /notifications/read-all | autenticado | Marcar todas como leídas | **Paginación obligatoria** en GET /notifications: `limit` (default 20, max 100) y `offset`. **Frontend:** - `NotificationBell`: icono de campana en el header con badge de conteo - `NotificationDropdown`: dropdown con lista de notificaciones (últimas 20) - Click en notificación navega a la entidad correspondiente y marca como leída - Polling cada 30 segundos para actualizar conteo (usar react-query con `refetchInterval: 30000`) - Botón "Mark all as read" en el dropdown **Validación:** - [ ] La campana muestra el conteo correcto de no leídas - [ ] El dropdown lista las notificaciones ordenadas por fecha - [ ] Click en una notificación navega correctamente y marca como leída - [ ] "Mark all as read" limpia el conteo - [ ] Las notificaciones se generan automáticamente con los cambios de estado - [ ] El polling actualiza el conteo sin refrescar la página --- ## FASE 19 — Mejoras de Remediación y Reportes ### T-130: Campo de remediación en tests y templates **Objetivo:** Añadir campos de remediación y recomendaciones, inspirados en el enfoque de Validato de "step-by-step remediation". **Archivos a modificar:** - `backend/app/models/test.py` — nuevos campos - `backend/app/models/test_template.py` — nuevo campo - Schemas correspondientes **Nuevos campos en Test:** | Campo | Tipo | Restricciones | |----------------------|--------|---------------| | remediation_steps | Text | nullable | | remediation_status | String | nullable (pending, in_progress, completed, not_applicable) | | remediation_assignee | UUID | FK → users.id, nullable | **Nuevo campo en TestTemplate:** | Campo | Tipo | Restricciones | |---------------------------|--------|---------------| | suggested_remediation | Text | nullable | **Generar migración.** **Validación:** - [ ] Los nuevos campos se crean en la BD - [ ] Se pueden asignar pasos de remediación a un test - [ ] Se puede asignar un responsable de remediación - [ ] El template puede sugerir remediación al instanciar --- ### T-131: Endpoint y UI de reportes **Objetivo:** Crear un sistema básico de reportes que permita exportar el estado de cobertura en diferentes formatos. **Archivos a crear:** - `backend/app/routers/reports.py` - `frontend/src/pages/ReportsPage.tsx` **Endpoints:** | Método | Ruta | Auth | Descripción | |--------|--------------------------------|-------------|-----------------------------------| | GET | /reports/coverage-summary | autenticado | Reporte JSON completo | | GET | /reports/coverage-csv | autenticado | Export CSV de cobertura | | GET | /reports/test-results | autenticado | Reporte de resultados de tests | | GET | /reports/remediation-status | autenticado | Reporte de estado de remediación | **Página de reportes:** - Selector de tipo de reporte - Filtros (rango de fechas, tácticas, plataformas) - Preview del reporte - Botones de descarga (CSV, JSON) - Resumen visual con métricas clave **Ruta:** `/reports` — añadir al router y sidebar. **Validación:** - [ ] Cada endpoint retorna datos correctos - [ ] El CSV se descarga y abre correctamente en Excel - [ ] Los filtros funcionan en el frontend - [ ] La preview del reporte se muestra correctamente - [ ] Solo usuarios autenticados pueden acceder --- ## FASE 20 — Pulido Final V2 y Documentación ### T-132: Actualizar navegación y routing **Objetivo:** Integrar todas las nuevas páginas en la navegación de la aplicación. **Archivos a modificar:** - `frontend/src/App.tsx` — nuevas rutas - `frontend/src/components/Sidebar.tsx` — nuevos items **Nuevas rutas:** ``` /test-catalog → TestCatalogPage /tests/:testId → TestDetailPage (rediseñada) /reports → ReportsPage ``` **Items del sidebar:** - Dashboard - ATT&CK Matrix (Techniques) - Tests (con submenu) - All Tests - My Pending Tasks - Test Catalog - Reports - System (admin) - MITRE Sync - Intel Scan - Templates Management - Users - Audit Log **Validación:** - [ ] Todas las rutas nuevas funcionan - [ ] El sidebar muestra los items correctos según el rol - [ ] La navegación entre páginas es fluida - [ ] No hay rutas rotas o 404 --- ### T-133: Error handling y edge cases **Objetivo:** Asegurar que todos los nuevos flujos manejan errores correctamente. **Backend:** - Todos los endpoints nuevos tienen manejo de 404, 400, 403 - Las transiciones de estado inválidas retornan errores descriptivos con el formato: ```json {"detail": "Cannot transition from 'draft' to 'validated'. Valid transitions: ['red_executing']", "code": "INVALID_TRANSITION"} ``` - Los permisos de equipo se validan en cada endpoint **Frontend:** - Loading states en todas las operaciones nuevas - Error messages descriptivos en validaciones y transiciones - Confirmación antes de acciones destructivas (rechazar, reabrir) - Feedback visual tras cada acción exitosa (toast) **Validación:** - [ ] Intentar transición inválida muestra error descriptivo con las transiciones válidas - [ ] Permisos incorrectos muestran 403 con mensaje claro - [ ] Loading states aparecen en todas las operaciones - [ ] Toast de éxito tras cada acción exitosa - [ ] Modal de confirmación antes de rechazar un test --- ### T-134: Backend tests finales de integración V2 **Objetivo:** Suite final de tests que verifica el sistema completo end-to-end. **Archivo a crear:** `backend/tests/test_integration_v2.py` **Tests:** ```python class TestIntegrationV2: def test_full_e2e_flow(): """ 1. Admin importa Atomic Red Team templates 2. Red Tech crea test desde template 3. Red Tech inicia ejecución (start-execution) 4. Red Tech sube evidencias y submite 5. Blue Tech evalúa y sube evidencias 6. Blue Tech submite para review 7. Red Lead y Blue Lead validan 8. Verificar que la técnica cambia de estado """ def test_rejection_recovery_flow(): """Flujo completo con rechazo y recuperación""" def test_notification_flow(): """Verificar que las notificaciones se generan correctamente""" def test_metrics_accuracy(): """Verificar que las métricas son correctas tras operaciones""" def test_report_generation(): """Verificar generación de reportes""" ``` **Validación:** - [ ] `pytest tests/test_integration_v2.py` pasa todos los tests - [ ] El flujo E2E completo funciona sin errores - [ ] Las métricas son consistentes tras todas las operaciones --- ### T-135: Actualizar documentación V2 **Objetivo:** Actualizar README y documentación API para reflejar todos los cambios. **Archivos a modificar:** - `README.md` — actualizar con nuevas funcionalidades - `docs/API.md` — documentar nuevos endpoints **Secciones nuevas en README:** - Descripción del flujo Red Team / Blue Team - Descripción de los roles y permisos - Diagrama del ciclo de vida del test - Cómo importar tests de Atomic Red Team - Cómo usar el catálogo de templates - Explicación del flujo de validación dual **Documentación API:** - Nuevos endpoints de tests (flujo Red/Blue) - Endpoints de templates - Endpoints de notificaciones - Endpoints de reportes - Nuevos endpoints de métricas **Validación:** - [ ] El README refleja todas las funcionalidades nuevas - [ ] La documentación API cubre todos los endpoints nuevos - [ ] Swagger UI en /docs muestra todos los endpoints correctamente - [ ] Siguiendo el README, un nuevo desarrollador puede entender el flujo completo --- ## Resumen de Fases V2 | Fase | Tareas | Descripción | |------|------------------|-------------------------------------------------------| | 10 | T-100 a T-105 | Evolución del modelo de datos para Red/Blue Team | | 11 | T-106 a T-108 | Lógica de negocio del flujo Red/Blue | | 12 | T-109 a T-112 | Endpoints API Red/Blue | | 13 | T-113 a T-114 | Frontend: tipos y API clients | | 14 | T-115 a T-118 | Frontend: página de test con pestañas Red/Blue | | 15 | T-119 a T-121 | Frontend: catálogo de tests y templates | | 16 | T-122 a T-124 | Frontend: vistas de gestión y dashboard mejorado | | 17 | T-125 a T-127 | Backend tests automatizados | | 18 | T-128 a T-129 | Notificaciones in-app | | 19 | T-130 a T-131 | Remediación y reportes | | 20 | T-132 a T-135 | Pulido final y documentación | > **Total V2: 36 tareas = 36 commits mínimo** --- --- # PARTE 2 — AEGIS V3: Plataforma Avanzada de Validación de Seguridad --- ## Lo que aporta V3 sobre V2 | Área | V2 ya cubre | V3 añade | |------|-------------|----------| | Fuentes de tests | Atomic Red Team | +Sigma Rules, +LOLBAS, +GTFOBins, +CALDERA, +Adversary Emulation Library, +Elastic Detection Rules | | Defensa | Evidencias Blue Team | +MITRE D3FEND mapping, +Sigma rule sugerida por test, +detection rule validation | | Threat actors | Ninguno | Perfiles de grupo APT, campañas, priorización por sector/geografía | | Métricas | Pipeline y cobertura | +MTTD, +MTTR, +Detection Efficacy, +tendencias temporales | | Visualización | Matriz ATT&CK básica | +Heatmap estilo Navigator, +capas superpuestas, +export de layers | | Compliance | Ninguno | Mapeo a NIST 800-53, DORA, NIS2, ISO 27001, reportes de compliance | | Kill chain | Tests individuales | +Campañas (cadenas de tests), +attack path visualization | | Scoring | Estados binarios | +Score de cobertura por técnica, +score global, +benchmark | | Comparativa | Ninguna | +Comparar snapshots temporales, +antes/después de remediación | | Automatización | Manual | +Scheduling de campañas, +re-test automático post-remediación | --- ## Fuentes de Tests Adicionales ### Fuentes para Red Team (Procedimientos de Ataque) | Fuente | Descripción | Formato | Tests aprox. | URL | |--------|-------------|---------|--------------|-----| | **Atomic Red Team** | Tests atómicos individuales por técnica | YAML | 1,500+ | [GitHub](https://github.com/redcanaryco/atomic-red-team) | | **MITRE CALDERA** | Abilities (acciones) ejecutables por agente | YAML | 400+ | [GitHub](https://github.com/mitre/caldera) | | **Adversary Emulation Library** | Planes completos de emulación de APTs | YAML/JSON/PDF | 15+ planes | [GitHub](https://github.com/center-for-threat-informed-defense/adversary_emulation_library) | | **LOLBAS** | Binarios legítimos de Windows abusables | YAML/JSON | 400+ | [GitHub](https://github.com/LOLBAS-Project/LOLBAS) | | **GTFOBins** | Binarios legítimos de Unix/Linux abusables | Markdown/JSON | 350+ | [GitHub](https://gtfobins.github.io/) | | **MITRE ATT&CK Procedures** | Procedimientos documentados en la propia framework | STIX/JSON | 1,000+ | [TAXII Server](https://cti-taxii.mitre.org/) | ### Fuentes para Blue Team (Reglas de Detección) | Fuente | Descripción | Formato | Reglas aprox. | URL | |--------|-------------|---------|---------------|-----| | **SigmaHQ** | Reglas de detección genéricas para SIEM | YAML | 3,000+ | [GitHub](https://github.com/SigmaHQ/sigma) | | **Elastic Detection Rules** | Reglas de detección de Elastic SIEM | TOML | 1,000+ | [GitHub](https://github.com/elastic/detection-rules) | | **MITRE D3FEND** | Framework de contramedidas defensivas | OWL/JSON | 200+ técnicas | [d3fend.mitre.org](https://d3fend.mitre.org/) | | **Splunk Security Content** | Reglas de detección para Splunk | YAML | 1,500+ | [GitHub](https://github.com/splunk/security_content) | ### Fuentes de Threat Intelligence | Fuente | Descripción | Formato | URL | |--------|-------------|---------|-----| | **MITRE CTI** | Datos de ATT&CK en STIX 2.0 (grupos, software, campañas) | STIX/JSON | [GitHub](https://github.com/mitre/cti) | | **MITRE ATT&CK Groups** | Perfiles de 140+ grupos APT con sus TTPs | STIX | [attack.mitre.org/groups](https://attack.mitre.org/groups/) | --- ## FASE 21 — Seed de Datos de Demo y Modelo de Fuentes ### T-200: Seed de datos de demo para V3 **Objetivo:** Crear un script de seed que genere un volumen realista de datos para poder validar las funcionalidades de V3 (heatmaps, scoring, compliance). Sin datos suficientes, muchas tareas de V3 no se pueden validar. **Archivo a crear:** `backend/app/seed_demo.py` **Datos a generar:** 1. **5 usuarios** de cada rol (red_tech, blue_tech, red_lead, blue_lead, admin) 2. **50 técnicas** con diferentes estados (validated, partial, not_covered, in_progress, not_evaluated) — distribuidas entre varias tácticas 3. **100 tests** en diferentes estados del pipeline (draft, red_executing, blue_evaluating, in_review, validated, rejected) 4. **50 evidencias** (archivos dummy) asociadas a tests 5. **20 audit logs** variados 6. **30 notificaciones** para diferentes usuarios 7. **10 templates** manuales (además de los de Atomic Red Team) **Ejecutable con:** `python -m app.seed_demo` **⚠️ Requisito:** Solo ejecutar sobre una BD con el sync MITRE ya completado (necesita técnicas reales). **Validación:** - [ ] El seed genera todos los datos sin errores - [ ] Las métricas del dashboard muestran datos variados - [ ] El heatmap tiene técnicas de diferentes colores - [ ] Los tests están en diferentes estados del pipeline - [ ] Ejecutar el seed dos veces no falla (limpia o usa upsert) --- ### T-201: Modelo unificado de fuente de datos (DataSource) **Objetivo:** Crear un sistema de gestión de fuentes de datos que permita registrar, configurar y monitorizar las distintas fuentes de tests y reglas de detección. **Archivo a crear:** `backend/app/models/data_source.py` **Campos:** | Campo | Tipo | Restricciones | |--------------------|----------|-------------------------------------------------| | id | UUID | PK, default uuid4 | | name | String | unique, not null (ej: "atomic_red_team") | | display_name | String | not null (ej: "Atomic Red Team") | | type | String | not null (attack_procedure / detection_rule / threat_intel / defensive_technique) | | url | String | nullable (URL base del repositorio/API) | | description | Text | nullable | | is_enabled | Boolean | default True | | last_sync_at | DateTime | nullable | | last_sync_status | String | nullable (success/error/in_progress) | | last_sync_stats | JSONB | nullable ({"imported": X, "updated": Y, ...}) | | sync_frequency | String | nullable (daily/weekly/monthly/manual) | | config | JSONB | nullable (configuración específica de la fuente) | | created_at | DateTime | default utcnow | **Generar migración.** **Seed de fuentes iniciales:** crear un script que registre todas las fuentes conocidas: - atomic_red_team (attack_procedure) - sigma (detection_rule) - lolbas (attack_procedure) - gtfobins (attack_procedure) - caldera (attack_procedure) - elastic_rules (detection_rule) - d3fend (defensive_technique) - mitre_cti (threat_intel) **Validación:** - [ ] `alembic upgrade head` crea la tabla `data_sources` - [ ] El seed crea las fuentes iniciales con tipos, URLs y configuración correctos - [ ] Se pueden activar/desactivar fuentes individualmente --- ### T-202: Modelo DetectionRule **Objetivo:** Crear el modelo para almacenar reglas de detección de múltiples fuentes (Sigma, Elastic, Splunk, custom). **Archivo a crear:** `backend/app/models/detection_rule.py` **Campos:** | Campo | Tipo | Restricciones | |--------------------|----------|-------------------------------------------------| | id | UUID | PK, default uuid4 | | mitre_technique_id | String | not null | | title | String | not null | | description | Text | nullable | | source | String | not null (sigma, elastic, splunk, custom) | | source_id | String | nullable (ID en la fuente original) | | source_url | String | nullable | | rule_content | Text | not null (contenido YAML/KQL de la regla) | | rule_format | String | not null (sigma_yaml, kql, spl, custom) | | severity | String | nullable (informational, low, medium, high, critical) | | platforms | JSONB | nullable, default [] | | log_sources | JSONB | nullable (ej: {"product": "windows", "service": "sysmon"}) | | false_positive_rate| String | nullable (low, medium, high) | | is_active | Boolean | default True | | created_at | DateTime | default utcnow | **Índices:** ```python Index('ix_detection_rules_mitre_technique_id', DetectionRule.mitre_technique_id) Index('ix_detection_rules_source', DetectionRule.source) Index('ix_detection_rules_severity', DetectionRule.severity) ``` **Generar migración.** **Validación:** - [ ] La tabla se crea con los índices correctos - [ ] Se puede insertar una regla con todos los campos - [ ] El campo `rule_content` acepta YAML largo --- ## FASE 22 — Importación de Fuentes de Tests ### T-203: Servicio de importación de Sigma Rules **Objetivo:** Importar reglas de detección Sigma del repositorio SigmaHQ y almacenarlas como DetectionRules. **Archivo a crear:** `backend/app/services/sigma_import_service.py` **Dependencia a añadir:** `pySigma` en requirements.txt (para parsear YAML de Sigma correctamente, ya que algunos tienen formatos edge-case que un parser YAML genérico no maneja bien). **⚠️ Estrategia de descarga desde GitHub:** El repositorio SigmaHQ tiene 3000+ archivos YAML. Usar la misma estrategia que Atomic Red Team: 1. Descargar ZIP del repositorio completo vía `https://github.com/SigmaHQ/sigma/archive/refs/heads/main.zip` 2. Descomprimir en directorio temporal 3. Parsear todos los ficheros YAML dentro de `rules/` 4. Limpiar al finalizar **Lógica:** 1. Descargar y descomprimir el repositorio 2. Para cada regla `.yml` en `rules/`: - Parsear YAML usando pySigma (título, descripción, logsource, detection, tags, level) - Extraer tags de ATT&CK: `attack.t1059.001` → `T1059.001` (normalizar a uppercase) - Ignorar reglas sin tags de ATT&CK (no se pueden mapear) - Extraer severidad del campo `level` - Extraer logsource para el campo `log_sources` - Almacenar como `DetectionRule` con `source = "sigma"`, `rule_format = "sigma_yaml"` - Usar el path relativo del fichero como `source_id` para deduplicación 3. No duplicar reglas existentes (comparar por `source` + `source_id`) 4. Actualizar `data_source.last_sync_at` y stats **Validación:** - [ ] La importación crea DetectionRules en la BD - [ ] Cada regla tiene su técnica MITRE mapeada correctamente - [ ] El contenido YAML de la regla se almacena completo - [ ] Ejecutar dos veces no duplica - [ ] Se importan al menos 2000+ reglas (las que tienen tags ATT&CK) - [ ] Las severidades se mapean correctamente - [ ] La descarga del ZIP funciona sin rate limiting --- ### T-204: Servicio de importación de LOLBAS y GTFOBins **Objetivo:** Importar binarios y técnicas de "living off the land" desde LOLBAS (Windows) y GTFOBins (Linux) como templates de ataque. **Archivo a crear:** `backend/app/services/lolbas_import_service.py` **⚠️ Estrategia de descarga:** - LOLBAS: Descargar ZIP del repositorio `https://github.com/LOLBAS-Project/LOLBAS/archive/refs/heads/master.zip` y parsear los YAMLs de `yml/OSBinaries/`, `yml/OSLibraries/`, `yml/OSScripts/` - GTFOBins: Descargar ZIP de `https://github.com/GTFOBins/GTFOBins.github.io/archive/refs/heads/master.zip` y parsear los markdowns de `_gtfobins/` **Lógica para LOLBAS:** 1. Descargar y descomprimir el repositorio 2. Cada YAML contiene: Name, Description, Commands (lista con Description, Command, Usecase, MitreID), Paths 3. Por cada binario y cada comando con MitreID: - Crear TestTemplate con `source = "lolbas"`, `platform = "windows"` - El `attack_procedure` incluye el Command documentado - El `tool_suggested` es el nombre del binario - El `mitre_technique_id` viene del campo MitreID 4. Usar `source + Name + MitreID` como clave de deduplicación **Lógica para GTFOBins:** 1. Descargar y descomprimir el repositorio 2. Cada markdown en `_gtfobins/` contiene front-matter YAML con funciones (shell, file-upload, file-download, sudo, suid, etc.) 3. Por cada binario y función: - Crear TestTemplate con `source = "gtfobins"`, `platform = "linux"` - Mapear funciones a técnicas MITRE cuando sea posible (shell → T1059, file-download → T1105, etc.) - El `attack_procedure` incluye los ejemplos de comandos 4. **Nota:** GTFOBins no tiene mapeos directos a MITRE — crear un diccionario de mapeo estático de función → técnica MITRE **Validación:** - [ ] LOLBAS importa templates para Windows - [ ] GTFOBins importa templates para Linux - [ ] Cada template tiene su técnica MITRE mapeada - [ ] Los comandos de ejemplo se almacenan en `attack_procedure` - [ ] No se duplican en ejecuciones posteriores - [ ] Las descargas de ZIP funcionan sin rate limiting --- ### T-205: Servicio de importación de MITRE CALDERA abilities **Objetivo:** Importar abilities (acciones ejecutables) del framework CALDERA como templates de tests. **Archivo a crear:** `backend/app/services/caldera_import_service.py` **⚠️ Estrategia de descarga:** Descargar ZIP del repositorio CALDERA: `https://github.com/mitre/caldera/archive/refs/heads/master.zip`. Las abilities están en `data/abilities/` organizadas por táctica, cada una es un fichero YAML. **Lógica:** 1. Descargar y descomprimir el repositorio 2. Navegar `data/abilities/{tactic}/` — cada subdirectorio corresponde a una táctica MITRE 3. Cada YAML de ability contiene: `id`, `name`, `description`, `tactic`, `technique.attack_id`, `platforms` (dict con OS → executors) 4. Por cada ability: - Crear TestTemplate con `source = "caldera"` - Setear `mitre_technique_id` desde `technique.attack_id` - Setear `platform` desde las keys de `platforms` (windows, linux, darwin) - Extraer los comandos de ejecución de `platforms.{os}.{executor}.command` - Setear `attack_procedure` con los comandos - Usar el `id` de la ability como `atomic_test_id` para deduplicación 5. No duplicar abilities existentes **Validación:** - [ ] Se importan abilities de CALDERA - [ ] Cada template tiene la técnica MITRE correcta - [ ] Las plataformas soportadas se registran - [ ] Los comandos de ejecución se almacenan - [ ] Se importan al menos 300+ templates --- ### T-206: Servicio de importación de Elastic Detection Rules **Objetivo:** Importar reglas de detección del repositorio open-source de Elastic como DetectionRules. **Archivo a crear:** `backend/app/services/elastic_import_service.py` **Dependencia a añadir:** `toml` en requirements.txt **⚠️ Estrategia de descarga:** Descargar ZIP del repositorio: `https://github.com/elastic/detection-rules/archive/refs/heads/main.zip`. Las reglas están en `rules/` organizadas por OS/plataforma. **Lógica:** 1. Descargar y descomprimir el repositorio 2. Parsear cada fichero `.toml` en `rules/` 3. Cada regla TOML contiene secciones: - `[metadata]` — creation_date, maturity, etc. - `[rule]` — name, description, query (KQL), severity, type - `[[rule.threat]]` — array con framework="MITRE ATT&CK", technique (id, name) 4. Por cada regla: - Extraer mappings de ATT&CK del campo `rule.threat` - Crear DetectionRule con `source = "elastic"`, `rule_format = "kql"` - Almacenar el query KQL en `rule_content` - Usar el nombre del fichero TOML como `source_id` 5. No duplicar en re-ejecuciones **Validación:** - [ ] Se importan reglas de Elastic - [ ] Cada regla tiene su técnica MITRE mapeada - [ ] El KQL se almacena completo y correctamente - [ ] Las severidades se mapean - [ ] Se importan al menos 500+ reglas --- ### T-207: Endpoint unificado de importación y panel de fuentes **Objetivo:** Crear un panel de administración centralizado para gestionar todas las fuentes de datos. **Archivos a crear/modificar:** - `backend/app/routers/data_sources.py` - `frontend/src/pages/DataSourcesPage.tsx` **Endpoints:** | Método | Ruta | Auth | Descripción | |--------|-----------------------------------|-------|------------------------------------| | GET | /data-sources | admin | Listar todas las fuentes | | PATCH | /data-sources/{id} | admin | Activar/desactivar, cambiar config | | POST | /data-sources/{id}/sync | admin | Ejecutar importación de una fuente | | POST | /data-sources/sync-all | admin | Importar de todas las fuentes activas | | GET | /data-sources/{id}/stats | admin | Estadísticas de la fuente | **Backend — Dispatcher de sync:** Crear un dispatcher que mapee cada `data_source.name` a su servicio de importación: ```python SYNC_HANDLERS = { "atomic_red_team": atomic_import_service.sync, "sigma": sigma_import_service.sync, "lolbas": lolbas_import_service.sync, "gtfobins": lolbas_import_service.sync_gtfobins, "caldera": caldera_import_service.sync, "elastic_rules": elastic_import_service.sync, # d3fend y mitre_cti se añaden en fases posteriores } ``` **Frontend — Panel de fuentes:** - Tabla con todas las fuentes: nombre, tipo, estado (badge), última sync, stats - Toggle para activar/desactivar - Botón de sync individual con loading state y resultado - Botón de "Sync All" con progreso (ejecuta secuencialmente) - Estadísticas: total de items importados por fuente, última fecha, errores **Validación:** - [ ] El panel muestra todas las fuentes registradas - [ ] Se puede activar/desactivar cada fuente - [ ] Sync individual ejecuta la importación correcta y muestra resultado - [ ] "Sync All" ejecuta todas las fuentes activas secuencialmente - [ ] Las estadísticas se actualizan tras cada sync - [ ] Solo admin puede acceder --- ## FASE 23 — Perfiles de Amenaza (Threat Actor Profiles) ### T-208: Modelo ThreatActor **Objetivo:** Crear un modelo para almacenar perfiles de grupos de amenaza (APTs) con sus TTPs asociadas. **Archivo a crear:** `backend/app/models/threat_actor.py` **Campos de ThreatActor:** | Campo | Tipo | Restricciones | |--------------------|----------|-------------------------------------------------| | id | UUID | PK, default uuid4 | | mitre_id | String | unique, nullable (ej: "G0016" para APT29) | | name | String | not null | | aliases | JSONB | nullable, default [] | | description | Text | nullable | | country | String | nullable | | target_sectors | JSONB | nullable, default [] | | target_regions | JSONB | nullable, default [] | | motivation | String | nullable (espionage, financial, destruction, etc.)| | sophistication | String | nullable (low, medium, high, advanced) | | first_seen | String | nullable | | last_seen | String | nullable | | references | JSONB | nullable, default [] | | mitre_url | String | nullable | | is_active | Boolean | default True | | created_at | DateTime | default utcnow | **Modelo ThreatActorTechnique** (tabla intermedia): | Campo | Tipo | Restricciones | |--------------------|----------|-------------------------------------------------| | id | UUID | PK, default uuid4 | | threat_actor_id | UUID | FK → threat_actors.id, not null | | technique_id | UUID | FK → techniques.id, not null | | usage_description | Text | nullable | | first_seen_using | String | nullable | **Índices:** ```python Index('ix_threat_actor_techniques_actor', ThreatActorTechnique.threat_actor_id) Index('ix_threat_actor_techniques_technique', ThreatActorTechnique.technique_id) UniqueConstraint('threat_actor_id', 'technique_id', name='uq_actor_technique') ``` **Generar migración.** **Validación:** - [ ] Las tablas se crean correctamente con índices - [ ] Se puede asociar un threat actor a múltiples técnicas - [ ] Una técnica puede estar asociada a múltiples threat actors - [ ] No se permite duplicar la misma relación actor-técnica (unique constraint) --- ### T-209: Importación de Threat Actors desde MITRE CTI **Objetivo:** Importar perfiles de grupos de amenaza desde el repositorio MITRE CTI (STIX 2.0). **Archivo a crear:** `backend/app/services/threat_actor_import_service.py` **⚠️ Estrategia de descarga:** Descargar ZIP de `https://github.com/mitre/cti/archive/refs/heads/master.zip`. Los datos están en `enterprise-attack/`. **⚠️ Complejidad del formato STIX 2.0:** Los datos STIX no son triviales de parsear. Los threat actors (grupos) no contienen directamente sus técnicas. La estructura es: 1. **Objetos `intrusion-set`** = grupos APT (lo que queremos como ThreatActor) 2. **Objetos `relationship`** de tipo `uses` = conectan un `intrusion-set` con un `attack-pattern` (técnica) 3. **Objetos `attack-pattern`** = técnicas MITRE (ya las tenemos en la BD) **Lógica detallada:** 1. Descargar y descomprimir el repositorio 2. Cargar el JSON bundle principal: `enterprise-attack/enterprise-attack.json` 3. **Paso 1 — Parsear intrusion-sets:** Filtrar objetos donde `type == "intrusion-set"` - Para cada grupo: extraer `name`, `description`, `aliases`, `external_references` - De `external_references` extraer el MITRE ID (donde `source_name == "mitre-attack"`) - Crear ThreatActor en BD 4. **Paso 2 — Parsear relationships:** Filtrar objetos donde `type == "relationship"` y `relationship_type == "uses"` - Filtrar relaciones donde `source_ref` apunte a un `intrusion-set` y `target_ref` apunte a un `attack-pattern` - Para cada relación: - Resolver `source_ref` → encontrar el ThreatActor en BD - Resolver `target_ref` → extraer el MITRE ID del attack-pattern y encontrar la Technique en BD - Crear ThreatActorTechnique con `usage_description` del campo `description` de la relación 5. No duplicar en re-ejecuciones (comparar por `mitre_id`) **Validación:** - [ ] Se importan 140+ threat actors - [ ] Cada actor tiene sus técnicas asociadas - [ ] Las relaciones actor-técnica son correctas (verificar APT29/G0016 con datos de MITRE) - [ ] Los aliases y descriptions se importan - [ ] Re-ejecutar no duplica - [ ] El campo `usage_description` contiene la descripción de cómo el grupo usa la técnica --- ### T-210: Endpoints de Threat Actors **Objetivo:** API para gestionar y consultar threat actors con sus técnicas y cobertura. **Archivo a crear:** `backend/app/routers/threat_actors.py` **Endpoints:** | Método | Ruta | Auth | Descripción | |--------|-----------------------------------------|-------------|----------------------------------------| | GET | /threat-actors | autenticado | Listar con filtros | | GET | /threat-actors/{id} | autenticado | Detalle con técnicas | | GET | /threat-actors/{id}/coverage | autenticado | Porcentaje de cobertura contra este actor | | GET | /threat-actors/{id}/gaps | autenticado | Técnicas del actor sin tests validados | **Filtros del listado:** - `country`, `target_sectors`, `motivation`, `sophistication` - `search` (busca en name, aliases, description) - Paginación: `offset` + `limit` **Lógica de `/coverage`:** - Obtener todas las técnicas del actor - Contar cuántas tienen `status_global` = validated o partial - Retornar porcentaje y desglose **Lógica de `/gaps`:** - Obtener técnicas del actor donde `status_global` NOT IN (validated) - Retornar lista con info de cada técnica y templates disponibles **Validación:** - [ ] El listado muestra threat actors con filtros funcionales - [ ] El detalle incluye las técnicas del actor - [ ] El coverage calcula correctamente el porcentaje - [ ] El gap analysis identifica técnicas sin tests validados - [ ] La paginación funciona --- ### T-211: Frontend de Threat Actors — Listado **Objetivo:** Página de listado de threat actors con filtros y cards. **Archivos a crear:** - `frontend/src/api/threat-actors.ts` - `frontend/src/pages/ThreatActorsPage.tsx` **Contenido:** - Grid de cards con: nombre, país (bandera), sectores, motivación, nº técnicas, cobertura % - Filtros laterales por sector, región, motivación - Buscador - Paginación **Ruta:** `/threat-actors` — añadir al router y al sidebar. **Validación:** - [ ] La página carga y muestra threat actors del backend - [ ] Los filtros funcionan - [ ] Cada card muestra la información correcta - [ ] Click en un actor navega al detalle - [ ] La ruta aparece en el sidebar --- ### T-212: Frontend de Threat Actors — Detalle con heatmap y gap analysis **Objetivo:** Página de detalle de un threat actor con su perfil, heatmap de técnicas y gap analysis. **Archivo a crear:** `frontend/src/pages/ThreatActorDetailPage.tsx` **Secciones:** 1. **Header**: nombre, aliases, country, motivación, sophistication 2. **Description**: texto descriptivo del grupo 3. **Heatmap de técnicas**: mini-matriz ATT&CK mostrando solo las técnicas de este actor, coloreadas por estado de cobertura 4. **Coverage gap analysis**: tabla de técnicas NO cubiertas, con templates disponibles 5. **Lista de tests existentes** vinculados a técnicas de este actor **Validación:** - [ ] El perfil completo se muestra - [ ] El heatmap renderiza solo las técnicas del actor - [ ] Los colores corresponden al estado de cobertura - [ ] El gap analysis lista técnicas sin cobertura - [ ] Si hay templates disponibles para una gap, se muestra un indicador --- ## FASE 24 — MITRE D3FEND: Contramedidas Defensivas ### T-213: Modelo y importación de D3FEND **Objetivo:** Integrar el framework MITRE D3FEND para mapear cada técnica ATT&CK a las contramedidas defensivas recomendadas. **Archivo a crear:** `backend/app/models/defensive_technique.py` **Campos de DefensiveTechnique:** | Campo | Tipo | Restricciones | |--------------------|----------|-------------------------------------------------| | id | UUID | PK, default uuid4 | | d3fend_id | String | unique, not null (ej: "D3-AL") | | name | String | not null | | description | Text | nullable | | tactic | String | nullable (D3FEND tactic: Detect, Isolate, etc.) | | d3fend_url | String | nullable | | created_at | DateTime | default utcnow | **Modelo DefensiveTechniqueMapping** (mapeo ATT&CK → D3FEND): | Campo | Tipo | Restricciones | |------------------------|----------|-------------------------------------------------| | id | UUID | PK, default uuid4 | | attack_technique_id | UUID | FK → techniques.id, not null | | defensive_technique_id | UUID | FK → defensive_techniques.id, not null | **Servicio de importación** `backend/app/services/d3fend_import_service.py`: 1. Usar la API de D3FEND (`https://d3fend.mitre.org/api/`) para obtener técnicas defensivas 2. Usar el endpoint de mappings ATT&CK-D3FEND (`/api/offensive-technique/{attack_id}.json`) para establecer relaciones 3. Almacenar técnicas defensivas y sus mapeos **Validación:** - [ ] Se importan 200+ técnicas defensivas D3FEND - [ ] Los mappings ATT&CK → D3FEND se crean correctamente - [ ] Desde una técnica ATT&CK se pueden consultar sus contramedidas D3FEND --- ### T-214: UI de contramedidas en vista de técnica y test **Objetivo:** Mostrar las contramedidas D3FEND recomendadas en la vista de detalle de técnica y en la pestaña Blue Team del test. **Archivos a modificar:** - `frontend/src/pages/TechniqueDetailPage.tsx` — nueva sección "Recommended Defenses" - `frontend/src/components/test-detail/TeamTabs.tsx` — en pestaña Blue, mostrar contramedidas **Sección en TechniqueDetailPage:** - Lista de contramedidas D3FEND recomendadas para esta técnica - Cada contramedida con: nombre, descripción, tactic D3FEND, link a documentación **En pestaña Blue Team del test:** - Panel "Recommended Detection Approaches" - Lista de contramedidas D3FEND aplicables - Reglas de detección Sigma/Elastic disponibles para esta técnica (del catálogo) **Validación:** - [ ] La vista de técnica muestra contramedidas D3FEND - [ ] La pestaña Blue Team muestra las contramedidas y reglas de detección - [ ] Los links a documentación D3FEND funcionan --- ## FASE 25 — Reglas de Detección Sugeridas por Test ### T-215: Asociar DetectionRules a tests y templates **Objetivo:** Vincular reglas de detección a los tests y templates para que el Blue Team sepa qué regla debería haber detectado el ataque. **Modelo a crear:** tabla intermedia `test_template_detection_rules`: | Campo | Tipo | Restricciones | |----------------------|----------|-------------------------------------------------| | id | UUID | PK, default uuid4 | | test_template_id | UUID | FK → test_templates.id, nullable | | detection_rule_id | UUID | FK → detection_rules.id, not null | | is_primary | Boolean | default False | **Lógica de auto-asociación:** Al importar templates y reglas de detección, asociar automáticamente por técnica MITRE: - Un template de ataque `T1059.001` se asocia a todas las reglas Sigma/Elastic para `T1059.001` - Marcar como `is_primary` las reglas cuya severidad sea >= high **Endpoints nuevos:** ``` GET /test-templates/{id}/detection-rules → reglas de detección sugeridas GET /detection-rules?technique={mitre_id} → reglas para una técnica GET /detection-rules?source={source} → reglas por fuente ``` **Validación:** - [ ] Los templates se asocian automáticamente a sus reglas de detección - [ ] `GET /test-templates/{id}/detection-rules` retorna las reglas correctas - [ ] Las reglas primarias se marcan correctamente - [ ] Filtrar por técnica y fuente funciona --- ### T-216: UI de reglas de detección y checklist en pestaña Blue Team **Objetivo:** Cuando el Blue Team evalúa un test, mostrarle las reglas de detección que deberían haber saltado, permitiéndole marcar cuáles detectaron y cuáles no. **Archivos a crear:** - `frontend/src/components/test-detail/DetectionRuleChecklist.tsx` - `backend/app/models/test_detection_result.py` **Modelo TestDetectionResult:** | Campo | Tipo | Restricciones | |--------------------|----------|-------------------------------------------------| | id | UUID | PK, default uuid4 | | test_id | UUID | FK → tests.id, not null | | detection_rule_id | UUID | FK → detection_rules.id, not null | | triggered | Boolean | nullable (null = not evaluated) | | notes | Text | nullable | | evaluated_by | UUID | FK → users.id, nullable | | evaluated_at | DateTime | nullable | **Componente DetectionRuleChecklist:** - Lista de reglas de detección asociadas al test/template - Cada regla con: título, severidad (badge color), fuente (Sigma/Elastic), contenido expandible - Checkbox: "Triggered" / "Not triggered" / "Not applicable" - Campo de notas por regla - Resumen: X/Y reglas detectaron (con porcentaje) **Validación:** - [ ] El checklist muestra las reglas de detección correctas - [ ] Se puede marcar cada regla como triggered/not triggered/N.A. - [ ] Las notas se guardan correctamente - [ ] El resumen X/Y se calcula - [ ] Los resultados se persisten en la BD --- ## FASE 26 — Campañas de Tests (Attack Chains) ### T-217: Modelo Campaign **Objetivo:** Crear campañas que agrupen múltiples tests en una secuencia que simula una cadena de ataque completa (kill chain). **Archivo a crear:** `backend/app/models/campaign.py` **Campos de Campaign:** | Campo | Tipo | Restricciones | |--------------------|----------|-------------------------------------------------| | id | UUID | PK, default uuid4 | | name | String | not null | | description | Text | nullable | | type | String | not null (custom, apt_emulation, kill_chain, compliance) | | threat_actor_id | UUID | FK → threat_actors.id, nullable | | status | String | default "draft" (draft, active, completed, archived) | | created_by | UUID | FK → users.id, nullable | | scheduled_at | DateTime | nullable | | completed_at | DateTime | nullable | | target_platform | String | nullable | | tags | JSONB | nullable, default [] | | created_at | DateTime | default utcnow | **Campos de CampaignTest** (tests de la campaña, con orden): | Campo | Type | Restricciones | |--------------------|----------|-------------------------------------------------| | id | UUID | PK, default uuid4 | | campaign_id | UUID | FK → campaigns.id, not null | | test_id | UUID | FK → tests.id, not null | | order_index | Integer | not null (posición en la cadena) | | depends_on | UUID | FK → campaign_tests.id, nullable (test previo) | | phase | String | nullable (initial_access, execution, persistence, etc.) | **⚠️ Prevención de dependencias circulares:** El campo `depends_on` es una FK self-referencial que podría crear ciclos (A depende de B que depende de A). Implementar validación: ```python def validate_no_circular_dependency(db, campaign_id, test_id, depends_on_id): """Recorrer la cadena de depends_on y verificar que no se forma un ciclo.""" visited = set() current = depends_on_id while current is not None: if current in visited or current == test_id: raise HTTPException(400, "Circular dependency detected") visited.add(current) parent = db.query(CampaignTest).filter_by(id=current).first() current = parent.depends_on if parent else None ``` **Generar migración.** **Validación:** - [ ] Las tablas se crean correctamente - [ ] Una campaña puede contener múltiples tests ordenados - [ ] Los tests pueden tener dependencias - [ ] Intentar crear una dependencia circular falla con error descriptivo - [ ] El campo `phase` acepta las fases del kill chain --- ### T-218: Endpoints y lógica de Campañas **Archivos a crear:** - `backend/app/routers/campaigns.py` - `backend/app/services/campaign_service.py` **Endpoints:** | Método | Ruta | Auth | Descripción | |--------|-------------------------------------|-----------------|------------------------------------------| | GET | /campaigns | autenticado | Listar campañas con filtros | | POST | /campaigns | red_tech, admin | Crear campaña | | GET | /campaigns/{id} | autenticado | Detalle con tests y progreso | | PATCH | /campaigns/{id} | creador, admin | Actualizar campaña | | POST | /campaigns/{id}/tests | red_tech, admin | Añadir test a campaña | | DELETE | /campaigns/{id}/tests/{test_id} | creador, admin | Quitar test de campaña | | POST | /campaigns/{id}/activate | red_tech, admin | Activar campaña | | POST | /campaigns/{id}/complete | red_lead, admin | Marcar como completada | | GET | /campaigns/{id}/progress | autenticado | Progreso: tests por estado | | POST | /campaigns/from-threat-actor/{actor_id} | red_tech, admin | Auto-generar campaña desde gaps | **Servicio de generación automática:** `generate_campaign_from_threat_actor(db, actor_id, user)`: 1. Obtener técnicas del actor no cubiertas (via `/threat-actors/{id}/gaps`) 2. Para cada técnica sin test validado, buscar el mejor template disponible (priorizar por severity) 3. Crear test desde template 4. Crear campaña con los tests ordenados por kill chain (tactic order: reconnaissance → initial_access → execution → ... → exfiltration) 5. Retornar la campaña con sus tests **Validación:** - [ ] CRUD de campañas funciona - [ ] Se pueden añadir/quitar tests con orden - [ ] Activar campaña cambia status y notifica - [ ] El progreso se calcula correctamente - [ ] La generación automática desde threat actor crea una campaña coherente - [ ] Los tests se ordenan por kill chain --- ### T-219: UI de Campañas — Listado **Archivo a crear:** `frontend/src/pages/CampaignsPage.tsx` **Contenido:** - Grid de cards con: nombre, tipo (badge), threat actor (si aplica), status, progreso %, nº tests - Filtros: tipo, status, threat actor - Botón "New Campaign" y "Generate from Threat Actor" **Ruta:** `/campaigns` — añadir al router y sidebar. **Validación:** - [ ] El listado muestra campañas con filtros - [ ] Cada card muestra la información correcta - [ ] Los botones de creación funcionan - [ ] La ruta aparece en el sidebar --- ### T-220: UI de Campañas — Detalle con Kill Chain Timeline **Archivos a crear:** - `frontend/src/pages/CampaignDetailPage.tsx` - `frontend/src/components/CampaignTimeline.tsx` **CampaignDetailPage:** - Header: nombre, descripción, status, threat actor linkado, dates - **Kill Chain Timeline**: visualización horizontal mostrando los tests agrupados por fase (Initial Access → Execution → Persistence → ...) - Cada nodo es un test con color según su estado - Flechas de dependencia entre tests - Click en un nodo abre el detalle del test - **Progress Panel**: barra de progreso + contadores por estado - **Tests Table**: tabla con todos los tests de la campaña, reordenable **Validación:** - [ ] El timeline visual renderiza correctamente los tests por fase - [ ] El progreso se actualiza al cambiar estado de tests - [ ] Se pueden añadir/quitar tests desde la UI - [ ] Click en nodos navega al detalle del test --- ## FASE 27 — Heatmap ATT&CK Avanzado (estilo Navigator) ### T-221: Backend de layers para heatmap **Objetivo:** Crear un sistema de "layers" (capas) que permitan visualizar la matriz ATT&CK con diferentes datos superpuestos, similar al MITRE ATT&CK Navigator. **Archivo a crear:** `backend/app/routers/heatmap.py` **Endpoints:** | Método | Ruta | Auth | Descripción | |--------|-----------------------------------|-------------|--------------------------------------------| | GET | /heatmap/coverage | autenticado | Capa de cobertura (status de cada técnica) | | GET | /heatmap/threat-actor/{actor_id} | autenticado | Capa de técnicas usadas por un actor | | GET | /heatmap/detection-rules | autenticado | Capa de cobertura de reglas de detección | | GET | /heatmap/campaign/{campaign_id} | autenticado | Capa de progreso de una campaña | | GET | /heatmap/export-navigator | autenticado | Exportar como JSON del ATT&CK Navigator | **Formato de respuesta:** Todas las capas retornan el mismo formato base, compatible con ATT&CK Navigator: ```json { "name": "Aegis Coverage", "versions": {"attack": "15", "navigator": "5.0", "layer": "4.5"}, "domain": "enterprise-attack", "description": "Coverage layer generated by Aegis", "filters": { "platforms": ["windows", "linux", "macos"] }, "gradient": { "colors": ["#ff6666", "#ffff66", "#66ff66"], "minValue": 0, "maxValue": 100 }, "techniques": [ { "techniqueID": "T1059.001", "tactic": "execution", "color": "#00ff00", "score": 100, "comment": "Validated - 3 tests passed, 5 detection rules active", "enabled": true, "metadata": [ {"name": "tests_count", "value": "3"}, {"name": "detection_rules", "value": "5"}, {"name": "last_validated", "value": "2026-01-15"} ] } ] } ``` **Lógica por endpoint:** - `/heatmap/coverage`: score basado en `status_global` (validated=100, partial=60, in_progress=30, not_covered=10, not_evaluated=0). Color derivado del score. - `/heatmap/threat-actor/{id}`: técnicas del actor con color de cobertura, técnicas no del actor con `enabled=false`. - `/heatmap/detection-rules`: score basado en ratio de reglas de detección disponibles vs evaluadas para cada técnica. - `/heatmap/campaign/{id}`: solo técnicas de la campaña, color basado en estado del test asociado. - `/heatmap/export-navigator`: acepta query param `layer` (coverage, threat-actor, detection-rules, campaign) y `layer_id` (actor_id o campaign_id si aplica). Retorna fichero JSON descargable con header `Content-Disposition: attachment`. **Query params comunes** para filtrar todas las capas: - `platforms`: filtrar por plataforma (windows, linux, macos) - `tactics`: filtrar por táctica - `min_score`: score mínimo para incluir **Validación:** - [ ] `/heatmap/coverage` retorna datos para todas las técnicas con scores correctos - [ ] `/heatmap/threat-actor/{id}` resalta solo las técnicas del actor - [ ] `/heatmap/detection-rules` calcula correctamente la cobertura de reglas - [ ] `/heatmap/campaign/{id}` muestra solo técnicas de la campaña - [ ] `/heatmap/export-navigator` genera un JSON descargable - [ ] El JSON exportado se puede importar en ATT&CK Navigator real (verificar manualmente en https://mitre-attack.github.io/attack-navigator/) - [ ] Los filtros de platform y tactic funcionan en todas las capas --- ### T-222: Frontend de heatmap — Componente base **Objetivo:** Crear el componente de heatmap reutilizable con renderizado eficiente de la matriz ATT&CK. **Archivos a crear:** - `frontend/src/components/heatmap/AdvancedHeatmap.tsx` - `frontend/src/components/heatmap/HeatmapCell.tsx` - `frontend/src/components/heatmap/HeatmapTooltip.tsx` - `frontend/src/components/heatmap/HeatmapLegend.tsx` **⚠️ Rendimiento con 3000+ técnicas:** No renderizar toda la matriz al DOM. Usar virtualización: 1. **Opción preferida:** Usar `react-window` (o `@tanstack/react-virtual`) para virtualizar tanto filas como columnas 2. Las columnas son las tácticas (14 columnas en Enterprise ATT&CK — se renderizan todas) 3. Las filas son las técnicas dentro de cada táctica (esto es lo que necesita virtualización — algunas tácticas tienen 100+ técnicas) 4. Implementar un layout CSS Grid donde cada columna de táctica tiene scroll virtual independiente **Añadir dependencia:** `@tanstack/react-virtual` o `react-window` a package.json **Componente AdvancedHeatmap:** Props: ```typescript interface HeatmapProps { techniques: HeatmapTechnique[]; // datos de la capa activa onCellClick: (techniqueId: string) => void; colorScale: (score: number) => string; // función de color } ``` Funcionalidades: - Grid con columnas = tácticas (14 columnas de Enterprise ATT&CK) - Dentro de cada columna, lista virtualizada de técnicas - Cada celda muestra: mitre_id + nombre truncado, coloreada por score - Header de columna con nombre de la táctica y conteo de técnicas - Zoom: slider que controla el tamaño de las celdas (compact/normal/expanded) - Scroll horizontal para ver todas las tácticas **Componente HeatmapCell:** - Renderiza una celda individual - Color de fondo según score/status - Borde especial si `review_required = true` - Indicadores opcionales (iconos pequeños): 🔴 sin tests, ⚠️ review requerida, ✅ validado **Componente HeatmapTooltip:** Al hacer hover sobre una celda: ``` ┌─────────────────────────────────┐ │ T1059.001 - PowerShell │ │ Status: Validated ✅ │ │ Score: 85/100 │ │ Tests: 3 validated │ │ Detection Rules: 12 available │ │ Last validated: 2026-01-15 │ │ Threat Actors: APT29, APT32 │ └─────────────────────────────────┘ ``` **Componente HeatmapLegend:** - Muestra gradiente de colores con labels - Se adapta según la capa activa - Para coverage: rojo → amarillo → verde - Para threat actor: gris (no aplica) → rojo (no cubierto) → verde (cubierto) **Validación:** - [ ] El heatmap renderiza todas las técnicas agrupadas por táctica - [ ] Los colores corresponden al status/score correcto - [ ] Los tooltips muestran información completa - [ ] Zoom in/out cambia el tamaño de las celdas - [ ] Scroll horizontal funciona para ver todas las tácticas - [ ] Con 3000+ técnicas no hay lag visible (virtualización funciona) - [ ] Click en celda ejecuta el callback correctamente --- ### T-223: Frontend de heatmap — Selector de capas, filtros y export **Archivos a crear/modificar:** - `frontend/src/components/heatmap/HeatmapLayerSelector.tsx` - `frontend/src/components/heatmap/HeatmapFilters.tsx` - `frontend/src/pages/MatrixPage.tsx` — rediseñar la página existente de técnicas **Componente HeatmapLayerSelector:** - Radio buttons o tabs para seleccionar la capa activa: - 🛡️ Coverage (default) - 👤 Threat Actor (al seleccionar, aparece un dropdown para elegir el actor) - 🔍 Detection Rules - 📋 Campaign (al seleccionar, aparece un dropdown para elegir la campaña) - Al cambiar de capa, se hace fetch al endpoint correspondiente de `/heatmap/` **Componente HeatmapFilters:** - Filtros inline (horizontal, encima de la matriz): - Plataforma: checkboxes (Windows, Linux, macOS) - Táctica: multi-select - Status: multi-select - Score mínimo: slider (0-100) **Página MatrixPage rediseñada:** Layout: ``` ┌──────────────────────────────────────────────────────────┐ │ [Layer Selector] [Filters] [Export ▼] [Zoom ⊕⊖] │ ├──────────────────────────────────────────────────────────┤ │ │ │ AdvancedHeatmap │ │ ┌──────┬──────┬──────┬──────┬───────────────────────┐ │ │ │Recon │Init │Exec │Pers │ ...más tácticas │ │ │ │ │Access│ │ │ │ │ │ │ T1595│ T1190│ T1059│ T1547│ │ │ │ │ T1592│ T1133│ T1203│ T1053│ │ │ │ │ ... │ ... │ ... │ ... │ │ │ │ └──────┴──────┴──────┴──────┴───────────────────────┘ │ │ │ ├──────────────────────────────────────────────────────────┤ │ HeatmapLegend │ └──────────────────────────────────────────────────────────┘ ``` **Botón Export:** Dropdown con opciones: - "Export Navigator JSON" → descarga el fichero JSON - "Copy Navigator URL" → copia URL que abre el layer en ATT&CK Navigator web **Validación:** - [ ] Seleccionar capas diferentes cambia la visualización - [ ] Seleccionar "Threat Actor" muestra dropdown de actores y cambia el heatmap - [ ] Los filtros reducen las técnicas mostradas en tiempo real - [ ] Export genera un JSON descargable - [ ] El JSON exportado se puede importar en ATT&CK Navigator real - [ ] La leyenda se actualiza según la capa activa - [ ] El zoom funciona con el slider --- ## FASE 28 — Scoring y Métricas Avanzadas ### T-224: Sistema de scoring de cobertura **Objetivo:** Implementar un sistema de puntuación granular de 0-100 por técnica, táctica, actor y organización. **Archivos a crear:** - `backend/app/services/scoring_service.py` - `backend/app/models/scoring_config.py` (opcional, para pesos en BD) **⚠️ Pesos configurables — NO hardcodear:** Los pesos del scoring deben ser configurables. Dos opciones: **Opción A — Variables de entorno / config.py** (más simple): ```python # config.py class Settings(BaseSettings): # ... existentes ... SCORING_WEIGHT_TESTS: int = 40 SCORING_WEIGHT_DETECTION_RULES: int = 20 SCORING_WEIGHT_D3FEND: int = 15 SCORING_WEIGHT_FRESHNESS: int = 15 SCORING_WEIGHT_PLATFORM_DIVERSITY: int = 10 ``` **Opción B — Tabla en BD** (más flexible, permite cambiar sin restart): ```python class ScoringConfig(Base): __tablename__ = "scoring_configs" id = Column(UUID, primary_key=True, default=uuid4) key = Column(String, unique=True, not null) # ej: "weight_tests" value = Column(Integer, not null) # ej: 40 description = Column(String, nullable=True) updated_at = Column(DateTime, default=utcnow) ``` **Usar Opción A para el MVP.** Migrar a Opción B si se necesita cambiar pesos frecuentemente. **Lógica de scoring por técnica:** ```python def calculate_technique_score(technique, db) -> dict: """ Retorna: { "total_score": 75, "breakdown": { "tests_validated": {"score": 35, "max": 40, "detail": "3/4 tests detected"}, "detection_rules": {"score": 15, "max": 20, "detail": "8/12 rules triggered"}, "d3fend_coverage": {"score": 10, "max": 15, "detail": "2/3 countermeasures"}, "freshness": {"score": 10, "max": 15, "detail": "Last test 45 days ago"}, "platform_diversity": {"score": 5, "max": 10, "detail": "2/3 platforms covered"} } } """ weights = settings # o cargar de BD # Tests validados con detección validated_tests = [t for t in technique.tests if t.state == "validated"] detected = [t for t in validated_tests if t.detection_result == "detected"] if validated_tests: test_score = (len(detected) / len(validated_tests)) * weights.SCORING_WEIGHT_TESTS else: test_score = 0 # Reglas de detección: ratio de reglas triggered vs total # (requiere datos de TestDetectionResult) # D3FEND: ratio de contramedidas verificadas # (requiere datos de DefensiveTechniqueMapping) # Frescura: tests más recientes = más puntos # < 90 días = 100%, 90-180 = 50%, > 180 = 0% # Diversidad de plataformas # Contar plataformas únicas cubiertas vs totales disponibles total = min(test_score + detection_score + d3fend_score + freshness_score + diversity_score, 100) return {"total_score": round(total, 1), "breakdown": {...}} ``` **Lógica de scoring por threat actor:** ```python def calculate_actor_coverage_score(actor, db) -> dict: """ Promedio ponderado de scores de las técnicas del actor. Retorna score global + desglose por técnica. """ techniques = [mapping.technique for mapping in actor.technique_mappings] scores = [calculate_technique_score(t, db)["total_score"] for t in techniques] return { "total_score": round(sum(scores) / len(scores), 1) if scores else 0, "techniques_count": len(techniques), "techniques_covered": len([s for s in scores if s > 50]), "techniques_detail": [...] } ``` **Lógica de scoring global:** ```python def calculate_organization_score(db) -> dict: """ Score global de la organización: { "overall_score": 62.5, "total_coverage": 58.0, # promedio de todas las técnicas evaluadas "critical_coverage": 71.0, # técnicas con severity >= high "detection_maturity": 45.0, # basado en reglas de detección "response_readiness": 30.0, # basado en remediaciones completadas "techniques_evaluated": 450, "techniques_total": 650 } """ ``` **Endpoints:** | Método | Ruta | Auth | Descripción | |--------|-----------------------------------|-------------|---------------------------------------| | GET | /scores/technique/{mitre_id} | autenticado | Score detallado con breakdown | | GET | /scores/tactic/{tactic} | autenticado | Score promedio por táctica | | GET | /scores/threat-actor/{id} | autenticado | Score de cobertura contra actor | | GET | /scores/organization | autenticado | Score global de la organización | | GET | /scores/history | autenticado | Historial de scores (query: period=30d/90d/1y) | | GET | /scores/config | admin | Ver pesos actuales | | PATCH | /scores/config | admin | Modificar pesos | **Validación:** - [ ] El score de técnica se calcula correctamente (0-100) con breakdown detallado - [ ] Cambiar los pesos via config cambia los scores resultantes - [ ] El score de threat actor refleja la cobertura real (verificar con datos de demo) - [ ] El score de organización agrega correctamente - [ ] El historial muestra la evolución temporal con puntos de datos - [ ] `GET /scores/config` retorna los pesos actuales --- ### T-225: Métricas operativas (MTTD, MTTR, Detection Efficacy) **Objetivo:** Implementar métricas operativas del equipo de seguridad. **Archivo a crear:** `backend/app/services/operational_metrics_service.py` **Métricas a calcular:** 1. **MTTD (Mean Time to Detect):** - Calcular para cada test validado: tiempo entre que el test entra en `red_executing` y entra en `blue_evaluating` - Usar timestamps del audit_log para extraer las fechas de cada transición - Retornar media, mediana, min, max 2. **MTTR (Mean Time to Respond/Remediate):** - Para tests con `remediation_status = completed`: tiempo entre `detection_result` seteado y `remediation_status = completed` - Solo calculable para tests que tienen remediación documentada - Retornar media, mediana, min, max 3. **Detection Efficacy:** - `detected_count / total_validated_tests * 100` - Desglosar: detected, partially_detected, not_detected 4. **Alert Fidelity:** - Ratio de `TestDetectionResult.triggered = True` vs total evaluados - Solo calculable si hay datos de evaluación de reglas 5. **Coverage Velocity:** - Contar técnicas que cambiaron a `validated` o `partial` por semana - Query: `GROUP BY date_trunc('week', last_review_date) ORDER BY week` 6. **Validation Throughput:** - Tests que pasaron a `validated` o `rejected` por semana - Query: `GROUP BY date_trunc('week', validated_at/rejected_at)` 7. **Rejection Rate:** - `rejected_count / (validated_count + rejected_count) * 100` - Desglosar por red_lead y blue_lead **Endpoints:** | Método | Ruta | Auth | Descripción | |--------|-----------------------------------|-------------|-------------------------------------------------| | GET | /metrics/operational | autenticado | Todas las métricas operativas actuales | | GET | /metrics/operational/trend | autenticado | Tendencia temporal. Query: `period=30d|90d|1y` | | GET | /metrics/operational/by-team | autenticado | Métricas desglosadas por equipo (red vs blue) | **Formato de respuesta de `/metrics/operational`:** ```json { "mttd": {"mean_hours": 12.5, "median_hours": 8.0, "min_hours": 1.2, "max_hours": 72.0, "sample_size": 45}, "mttr": {"mean_hours": 48.0, "median_hours": 36.0, "sample_size": 20}, "detection_efficacy": {"percentage": 72.5, "detected": 29, "partially": 8, "not_detected": 3, "total": 40}, "alert_fidelity": {"percentage": 65.0, "triggered": 130, "not_triggered": 70, "total_evaluated": 200}, "coverage_velocity": {"techniques_per_week": 5.2, "trend": "improving"}, "validation_throughput": {"tests_per_week": 8.3, "trend": "stable"}, "rejection_rate": {"percentage": 15.0, "by_red_lead": 10.0, "by_blue_lead": 20.0} } ``` **Validación:** - [ ] MTTD se calcula correctamente a partir de timestamps del audit_log - [ ] MTTR incluye solo tests con remediación completada - [ ] Detection Efficacy es un porcentaje correcto con desglose - [ ] Las tendencias muestran evolución temporal (array de puntos por semana) - [ ] El desglose por equipo separa métricas red vs blue correctamente - [ ] Si no hay datos suficientes para una métrica, retorna `null` en lugar de error --- ### T-226: Dashboard ejecutivo con scores y métricas **Objetivo:** Crear una vista de dashboard ejecutivo pensada para presentar a dirección. **Archivo a crear:** `frontend/src/pages/ExecutiveDashboardPage.tsx` **Dependencia a añadir:** `recharts` en package.json (para gráficos) **Secciones del dashboard:** 1. **Score Card Principal:** - Gauge circular (tipo velocímetro) con el score global de la organización - Color: rojo (0-30), naranja (30-50), amarillo (50-70), verde (70-100) - Texto central: score numérico - Debajo: desglose en sub-scores (coverage, detection maturity, response readiness) 2. **Trend Chart:** - Gráfico de línea (recharts `LineChart`) mostrando evolución del score en los últimos 90 días - Línea principal: score global - Líneas secundarias opcionales: sub-scores - Tooltip con fecha y valor 3. **Top 5 Threat Actors más relevantes:** - Cards horizontales con: nombre, bandera de país, % cobertura con barra de progreso - Ordenados por relevancia (sectores target que coinciden con la organización) 4. **Operational KPIs:** - 4 cards en fila: MTTD, MTTR, Detection Efficacy, Validation Throughput - Cada card con: valor actual, tendencia (↑ mejorando / ↓ empeorando / → estable), sparkline mini 5. **Coverage por táctica:** - Barras horizontales (recharts `BarChart` horizontal) con % de cobertura por táctica - Color de barra según porcentaje 6. **Critical Gaps:** - Tabla con las top 10 técnicas de alta severidad sin cobertura - Columnas: MITRE ID, nombre, táctica, nº threat actors que la usan, templates disponibles - Click en fila navega al detalle de la técnica 7. **Team Performance:** - Dos columnas: Red Team | Blue Team - Cada columna con: tests completados esta semana, tiempo medio de respuesta, rejection rate **Ruta:** `/executive-dashboard` — accesible para roles `admin`, `red_lead`, `blue_lead`. **Validación:** - [ ] El dashboard carga con datos reales del backend - [ ] El gauge del score global funciona y se colorea correctamente - [ ] El gráfico de tendencia renderiza con datos históricos - [ ] Los KPIs muestran valores correctos con tendencias - [ ] Los critical gaps enlazan al detalle de la técnica - [ ] Solo roles de liderazgo y admin pueden acceder - [ ] El dashboard es responsive (se adapta a pantallas pequeñas) --- ## FASE 29 — Compliance y Reportes Avanzados ### T-227: Modelo de mapeo a frameworks de compliance **Objetivo:** Mapear técnicas ATT&CK y controles de seguridad a frameworks de compliance. **Archivo a crear:** `backend/app/models/compliance.py` **Campos de ComplianceFramework:** | Campo | Tipo | Restricciones | |--------------------|----------|-------------------------------------------------| | id | UUID | PK, default uuid4 | | name | String | unique, not null (ej: "NIST 800-53") | | version | String | nullable | | description | Text | nullable | | url | String | nullable | | is_active | Boolean | default True | | created_at | DateTime | default utcnow | **Campos de ComplianceControl:** | Campo | Tipo | Restricciones | |--------------------|----------|-------------------------------------------------| | id | UUID | PK, default uuid4 | | framework_id | UUID | FK → compliance_frameworks.id, not null | | control_id | String | not null (ej: "AC-2", "PR.AC-1") | | title | String | not null | | description | Text | nullable | | category | String | nullable | **Campos de ComplianceControlMapping** (mapeo a técnicas ATT&CK): | Campo | Tipo | Restricciones | |-------------------------|----------|-------------------------------------------------| | id | UUID | PK, default uuid4 | | compliance_control_id | UUID | FK → compliance_controls.id, not null | | technique_id | UUID | FK → techniques.id, not null | **Índices:** ```python Index('ix_compliance_controls_framework', ComplianceControl.framework_id) Index('ix_compliance_mappings_control', ComplianceControlMapping.compliance_control_id) Index('ix_compliance_mappings_technique', ComplianceControlMapping.technique_id) UniqueConstraint('compliance_control_id', 'technique_id', name='uq_control_technique') ``` **⚠️ Fuente de datos para mappings NIST → ATT&CK:** Los mappings oficiales están en el repositorio del Center for Threat-Informed Defense de MITRE: `https://github.com/center-for-threat-informed-defense/attack_to_nist_mapping` El formato es un STIX bundle JSON con objetos `relationship` que conectan controles NIST a técnicas ATT&CK. El servicio de importación debe: 1. Descargar ZIP del repositorio 2. Parsear el JSON de mappings 3. Crear ComplianceFramework, ComplianceControls, y ComplianceControlMappings **Servicio de importación** `backend/app/services/compliance_import_service.py`: ```python def import_nist_800_53_mappings(db): """ 1. Descargar ZIP de https://github.com/center-for-threat-informed-defense/attack_to_nist_mapping 2. Parsear el STIX bundle JSON 3. Crear framework 'NIST 800-53 Rev 5' 4. Para cada control: crear ComplianceControl 5. Para cada relationship: crear ComplianceControlMapping vinculando control → técnica """ ``` **Generar migración.** **Validación:** - [ ] Las tablas se crean correctamente con índices - [ ] El import de NIST 800-53 crea framework, controles y mappings - [ ] Se puede consultar qué controles aplican a una técnica - [ ] Se puede consultar qué técnicas cubren un control - [ ] No se permite duplicar la misma relación control-técnica (unique constraint) - [ ] Re-ejecutar la importación no duplica datos --- ### T-228: Endpoints y generación de reportes de compliance **Archivo a crear:** `backend/app/routers/compliance.py` **Endpoints:** | Método | Ruta | Auth | Descripción | |--------|-----------------------------------------------|-------------|--------------------------------------------| | GET | /compliance/frameworks | autenticado | Listar frameworks disponibles | | GET | /compliance/frameworks/{id}/status | autenticado | Estado de cada control | | GET | /compliance/frameworks/{id}/report | autenticado | Reporte completo de compliance | | GET | /compliance/frameworks/{id}/report/csv | autenticado | Export CSV del reporte | | GET | /compliance/frameworks/{id}/gaps | autenticado | Controles con técnicas no cubiertas | **Lógica del status de cada control:** Para cada control del framework: 1. Obtener las técnicas ATT&CK mapeadas via ComplianceControlMapping 2. Para cada técnica, obtener su `status_global` y su score (de scoring_service) 3. Clasificar el control: - **covered** (verde): todas las técnicas mapeadas tienen score >= 70 - **partially_covered** (amarillo): al menos una técnica tiene score >= 30 pero alguna tiene score < 70 - **not_covered** (rojo): todas las técnicas tienen score < 30 - **not_evaluated** (gris): ninguna técnica tiene tests 4. Calcular score del control: promedio de scores de sus técnicas **Formato de respuesta de `/frameworks/{id}/status`:** ```json { "framework": {"id": "...", "name": "NIST 800-53 Rev 5"}, "summary": { "total_controls": 150, "covered": 85, "partially_covered": 35, "not_covered": 20, "not_evaluated": 10, "compliance_percentage": 56.7 }, "controls": [ { "control_id": "AC-2", "title": "Account Management", "category": "Access Control", "status": "partially_covered", "score": 55.0, "techniques_count": 5, "techniques_covered": 3, "techniques": [ {"mitre_id": "T1078", "name": "Valid Accounts", "score": 80.0, "status": "validated"}, {"mitre_id": "T1136", "name": "Create Account", "score": 30.0, "status": "in_progress"} ] } ] } ``` **Formato CSV export:** ``` control_id,title,category,status,score,techniques_total,techniques_covered,technique_ids AC-2,Account Management,Access Control,partially_covered,55.0,5,3,"T1078,T1136,T1098,T1087,T1069" ``` **Lógica de `/gaps`:** Retornar solo controles con status `not_covered` o `partially_covered`, incluyendo para cada uno: - Las técnicas que faltan por cubrir - Templates disponibles para esas técnicas - Número de threat actors que usan esas técnicas (para priorizar) **Validación:** - [ ] El estado de cada control se calcula correctamente según la lógica de scoring - [ ] El reporte incluye todos los controles del framework - [ ] El compliance_percentage es correcto: `(covered + partially_covered*0.5) / total * 100` - [ ] El export CSV se descarga y abre correctamente en Excel - [ ] Los gaps listan controles con técnicas no cubiertas - [ ] Las técnicas dentro de cada control están ordenadas por score (ascendente = prioridad) --- ### T-229: UI de Compliance **Archivos a crear:** - `frontend/src/pages/CompliancePage.tsx` - `frontend/src/components/compliance/ComplianceGauge.tsx` - `frontend/src/components/compliance/ControlsTable.tsx` **CompliancePage:** Layout: ``` ┌──────────────────────────────────────────────────────────────┐ │ [Framework Selector ▼ NIST 800-53] [Export CSV] [Export PDF] │ ├──────────────────────────────────────────────────────────────┤ │ │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │ 56.7% │ │ 85 │ │ 35 │ │ 20 │ │ │ │ Overall │ │ Covered │ │ Partial │ │ Not Cov │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ │ │ │ ┌───────────────────────────────────────────────────────┐ │ │ │ Filtros: [Status ▼] [Category ▼] [Search...] │ │ │ ├───────────────────────────────────────────────────────┤ │ │ │ Control │ Title │ Status │ Score │ Tech │ │ │ │ AC-2 │ Account Management │ ●Partial│ 55.0 │ 3/5 │ │ │ │ AC-3 │ Access Enforcement │ ●Covered│ 82.0 │ 4/4 │ │ │ │ AC-4 │ Information Flow │ ●NotCov │ 12.0 │ 0/3 │ │ │ │ ... │ ... │ ... │ ... │ ... │ │ │ └───────────────────────────────────────────────────────┘ │ │ │ │ Expandir un control muestra sus técnicas con detalle │ └──────────────────────────────────────────────────────────────┘ ``` **Interacciones:** - **Selector de framework**: dropdown con frameworks disponibles - **Cards superiores**: resumen con conteos y porcentaje global (gauge circular) - **Tabla de controles**: expandible — click en un control muestra sus técnicas con status y score - **Filtros**: status (covered/partial/not_covered), categoría, búsqueda por ID o título - **Export**: CSV y JSON (el PDF se puede implementar en una fase futura) - Click en una técnica dentro de un control navega al detalle de la técnica **Ruta:** `/compliance` — añadir al sidebar. **Validación:** - [ ] La página muestra frameworks con métricas correctas - [ ] El selector de framework cambia los datos - [ ] La tabla de controles se filtra correctamente - [ ] Expandir un control muestra sus técnicas con status - [ ] El CSV se descarga y es correcto - [ ] Los datos de compliance son consistentes con los scores - [ ] La ruta aparece en el sidebar --- ## FASE 30 — Comparación Temporal y Re-testing ### T-230: Snapshots de cobertura **Objetivo:** Crear snapshots periódicos del estado de cobertura para comparar en el tiempo. **Archivo a crear:** `backend/app/models/coverage_snapshot.py` **⚠️ Evitar JSONB gigante:** Almacenar el estado de 3000+ técnicas como JSONB en una sola fila generaría registros de varios MB. Con snapshots semanales automáticos, crece muy rápido. En su lugar, normalizar el almacenamiento: **Campos de CoverageSnapshot:** | Campo | Tipo | Restricciones | |--------------------|----------|-------------------------------------------------| | id | UUID | PK, default uuid4 | | name | String | nullable (ej: "Pre-remediación Q1") | | organization_score | Float | not null | | total_techniques | Integer | not null | | validated_count | Integer | not null | | partial_count | Integer | not null | | not_covered_count | Integer | not null | | in_progress_count | Integer | not null | | not_evaluated_count| Integer | not null | | created_by | UUID | FK → users.id, nullable | | created_at | DateTime | default utcnow | **Campos de SnapshotTechniqueState** (tabla normalizada, una fila por técnica por snapshot): | Campo | Tipo | Restricciones | |--------------------|----------|-------------------------------------------------| | id | UUID | PK, default uuid4 | | snapshot_id | UUID | FK → coverage_snapshots.id, not null, ON DELETE CASCADE | | technique_id | UUID | FK → techniques.id, not null | | mitre_id | String | not null (desnormalizado para queries rápidos) | | status | String | not null | | score | Float | nullable | **Índices:** ```python Index('ix_snapshot_technique_states_snapshot', SnapshotTechniqueState.snapshot_id) Index('ix_snapshot_technique_states_technique', SnapshotTechniqueState.technique_id) ``` **Generar migración.** **Servicio** `backend/app/services/snapshot_service.py`: ```python def create_snapshot(db, name=None, user_id=None) -> CoverageSnapshot: """ 1. Obtener todas las técnicas con su status y score 2. Crear CoverageSnapshot con conteos agregados 3. Crear SnapshotTechniqueState para cada técnica 4. Retornar el snapshot """ def compare_snapshots(db, snapshot_a_id, snapshot_b_id) -> dict: """ Retorna: { "snapshot_a": {...}, "snapshot_b": {...}, "score_delta": +5.2, "improved": [{"mitre_id": "T1059", "old_status": "not_covered", "new_status": "validated", "old_score": 0, "new_score": 85}], "worsened": [...], "unchanged_count": 580, "summary": {"improved_count": 12, "worsened_count": 3, "new_count": 5} } """ def cleanup_old_snapshots(db, keep_last=52): """Mantener solo los últimos 52 snapshots (1 año de semanales). Eliminar los más antiguos.""" ``` **Job:** Programar job APScheduler semanal (domingos a las 00:00) que ejecute `create_snapshot(db, name="Auto-weekly")`. Incluir `cleanup_old_snapshots` al final del job. **Endpoints:** | Método | Ruta | Auth | Descripción | |--------|-----------------------------------|----------------------------|---------------------------------------| | GET | /snapshots | autenticado | Listar snapshots (paginado) | | POST | /snapshots | red_lead, blue_lead, admin | Crear snapshot manual con nombre | | GET | /snapshots/{id} | autenticado | Detalle de un snapshot | | GET | /snapshots/compare | autenticado | Comparar dos: `?a={id}&b={id}` | | DELETE | /snapshots/{id} | admin | Eliminar snapshot | **Validación:** - [ ] Crear snapshot captura el estado actual correctamente (conteos + detalle por técnica) - [ ] Comparar dos snapshots muestra técnicas que mejoraron, empeoraron y sin cambio - [ ] El job semanal crea snapshots automáticamente - [ ] `cleanup_old_snapshots` elimina snapshots antiguos respetando el mínimo - [ ] El snapshot normalizado no genera registros gigantes (verificar tamaño con datos de demo) --- ### T-231: UI de comparación temporal **Archivo a crear:** `frontend/src/pages/ComparisonPage.tsx` **Contenido:** Layout: ``` ┌──────────────────────────────────────────────────────────────┐ │ Snapshot A: [Dropdown ▼] Snapshot B: [Dropdown ▼] │ ├──────────────────────────┬───────────────────────────────────┤ │ Score: 58.0 │ Score: 63.2 (+5.2 ↑) │ │ Validated: 120 │ Validated: 132 (+12) │ │ Partial: 85 │ Partial: 88 (+3) │ │ Not covered: 45 │ Not covered: 38 (-7) │ ├──────────────────────────┴───────────────────────────────────┤ │ │ │ [Improved (12)] [Worsened (3)] [Unchanged (585)] │ │ │ │ ┌──────────────────────────────────────────────────────┐ │ │ │ MITRE ID │ Name │ Before │ After │ Δ │ │ │ │ T1059 │ Command Line │ ●NotCov │ ●Valid │ ↑ │ │ │ │ T1078 │ Valid Accounts │ ●Partial│ ●Valid │ ↑ │ │ │ │ T1053 │ Scheduled Tasks │ ●Valid │ ●Partial│ ↓ │ │ │ └──────────────────────────────────────────────────────┘ │ │ │ │ [Mini Heatmap Diff] (opcional: verde=mejoró, rojo=empeoró)│ └──────────────────────────────────────────────────────────────┘ ``` **Interacciones:** - Dos dropdowns para seleccionar snapshots (ordenados por fecha, más reciente primero) - Cards side-by-side con scores y conteos, mostrando deltas - Tabs para filtrar la tabla: Improved, Worsened, Unchanged - Tabla con técnicas que cambiaron, mostrando estado antes/después - Click en técnica navega al detalle - Mini heatmap diff opcional (si hay menos de 200 técnicas con cambios) **Ruta:** `/comparison` — accesible desde dashboard ejecutivo y sidebar. **Validación:** - [ ] Se pueden seleccionar dos snapshots - [ ] La comparación muestra las diferencias correctamente - [ ] Los deltas se calculan y muestran con flechas ↑↓ - [ ] Los tabs Improved/Worsened/Unchanged filtran la tabla - [ ] Las métricas son correctas --- ### T-232: Sistema de re-testing automático **Objetivo:** Cuando un test se marca con remediación completada, crear automáticamente un re-test para verificar que la remediación fue efectiva. **Archivos a modificar:** - `backend/app/models/test.py` — añadir campos de re-test - `backend/app/services/test_workflow_service.py` — lógica de re-test **Nuevos campos en Test:** | Campo | Tipo | Restricciones | |-------------|---------|----------------------------------| | retest_of | UUID | FK → tests.id, nullable | | retest_count| Integer | default 0 | **⚠️ Prevención de loop infinito de re-tests:** Añadir constante configurable: ```python # config.py MAX_RETEST_COUNT: int = 3 # máximo de retests automáticos por test original ``` **Lógica:** ```python def handle_remediation_completed(db, test, user): """ Se llama cuando remediation_status cambia a 'completed'. 1. Verificar que retest_count < MAX_RETEST_COUNT 2. Si no se alcanzó el límite: - Crear nuevo test con mismos datos base (technique, platform, procedure, tool) - Setear retest_of = test.id (o el test original si este ya es un retest) - Setear retest_count = test.retest_count + 1 - Estado: draft - Notificar al creador del test original y al red_tech 3. Si se alcanzó el límite: - No crear retest - Crear notificación: "Max retests reached for test X — manual review required" - Log de auditoría """ original_test_id = test.retest_of or test.id if test.retest_count >= settings.MAX_RETEST_COUNT: create_notification(db, test.created_by, "max_retests_reached", ...) return None retest = Test( technique_id=test.technique_id, name=f"[Retest #{test.retest_count + 1}] {test.name}", description=test.description, platform=test.platform, procedure_text=test.procedure_text, tool_used=test.tool_used, state=TestState.draft, created_by=test.created_by, retest_of=original_test_id, retest_count=test.retest_count + 1, ) db.add(retest) db.commit() # Notificar return retest ``` **Endpoints nuevos:** | Método | Ruta | Auth | Descripción | |--------|---------------------------|-------------|---------------------------------------| | GET | /tests/{id}/retest-chain | autenticado | Ver cadena de retests (original + todos los retests) | **UI:** En el detalle del test, mostrar: - Si es un retest: link al test original - Si tiene retests: lista de retests con su estado - Indicador visual: "Retest 2/3" con barra de progreso **Generar migración.** **Validación:** - [ ] Completar remediación crea automáticamente un retest - [ ] El retest tiene `retest_of` apuntando al test original (no al intermedio) - [ ] El retest tiene los mismos datos base que el original - [ ] Se genera notificación del retest - [ ] Al alcanzar `MAX_RETEST_COUNT`, NO se crea retest y se notifica - [ ] La cadena de retests se puede consultar via endpoint - [ ] En la UI se muestra la cadena de retests con links --- ## FASE 31 — Scheduling y Automatización ### T-233: Sistema de scheduling de campañas **Objetivo:** Permitir programar campañas para ejecución periódica. **Archivos a modificar:** - `backend/app/models/campaign.py` — nuevos campos de scheduling - `backend/app/services/campaign_scheduler_service.py` — nuevo **Nuevos campos en Campaign:** | Campo | Tipo | Restricciones | |--------------------|----------|-------------------------------------------------| | is_recurring | Boolean | default False | | recurrence_pattern | String | nullable (weekly, monthly, quarterly) | | next_run_at | DateTime | nullable | | last_run_at | DateTime | nullable | **Generar migración.** **Servicio** `backend/app/services/campaign_scheduler_service.py`: ```python def check_and_run_recurring_campaigns(db): """ Job diario. Para cada campaña donde is_recurring=True y next_run_at <= now: 1. Clonar la campaña: - Crear nueva campaña con mismos datos base + suffix " (Run {date})" - Para cada CampaignTest de la campaña original: - Crear nuevo Test con mismos datos base, state=draft - Crear nuevo CampaignTest vinculando al nuevo test 2. Activar la nueva campaña (status=active) 3. Actualizar la campaña original: last_run_at=now, next_run_at=calcular_siguiente(recurrence_pattern) 4. Notificar a los equipos 5. Log de auditoría """ def calculate_next_run(current_date, pattern): """ weekly: +7 días monthly: +30 días quarterly: +90 días """ ``` **Job:** Programar job APScheduler diario que ejecute `check_and_run_recurring_campaigns`. **Endpoints:** | Método | Ruta | Auth | Descripción | |--------|-------------------------------|----------------|---------------------------------------| | PATCH | /campaigns/{id}/schedule | creador, admin | Configurar recurrencia | | GET | /campaigns/{id}/history | autenticado | Historial de ejecuciones (campañas hijas) | **Formato de PATCH /campaigns/{id}/schedule:** ```json { "is_recurring": true, "recurrence_pattern": "monthly", "next_run_at": "2026-03-01T00:00:00Z" } ``` **Validación:** - [ ] Se puede configurar una campaña como recurrente con patrón y fecha - [ ] El job diario detecta campañas que deben ejecutarse - [ ] La clonación crea nueva campaña con tests nuevos en draft - [ ] Los tests clonados tienen los mismos datos base pero IDs nuevos - [ ] `last_run_at` y `next_run_at` se actualizan correctamente - [ ] El historial lista todas las ejecuciones pasadas (campañas hijas) - [ ] Las notificaciones se generan al crear nueva ejecución --- ### T-234: UI de scheduling **Archivo a modificar:** `frontend/src/pages/CampaignDetailPage.tsx` **Nuevas funcionalidades:** - **Toggle "Recurring Campaign"**: switch que activa/desactiva recurrencia - Al activar, aparece: - Selector de frecuencia: Weekly / Monthly / Quarterly - Date picker para "Next run at" - **Indicador de próxima ejecución**: badge en el header "Next run: March 1, 2026" - **Tab "Execution History"**: tabla con ejecuciones pasadas - Columnas: fecha, nombre, nº tests, progreso %, score obtenido, link - Click en una ejecución navega al detalle de esa campaña **Validación:** - [ ] El toggle de recurrencia funciona (guarda via PATCH) - [ ] Se puede seleccionar la frecuencia - [ ] El date picker funciona para next_run_at - [ ] La próxima ejecución se muestra en el header - [ ] El historial lista ejecuciones pasadas con datos correctos - [ ] Desactivar recurrencia limpia next_run_at --- ## FASE 32 — Tests Automatizados V3 ### T-235: Tests de importación de fuentes **Archivo a crear:** `backend/tests/test_data_sources.py` **⚠️ Nota sobre tests de importación externa:** Los tests que dependen de descargar repositorios de GitHub son lentos e inestables (dependen de red). Implementar dos niveles: 1. **Tests unitarios** (rápidos, sin red): mockear las descargas, testear solo la lógica de parsing 2. **Tests de integración** (lentos, con red): marcados con `@pytest.mark.integration`, excluidos por defecto ```python import pytest class TestDataSourcesParsing: """Tests unitarios — sin acceso a red, usando fixtures de YAML/TOML de ejemplo""" def test_sigma_yaml_parsing(): """Parsear un YAML de Sigma de ejemplo y verificar extracción de campos""" def test_lolbas_yaml_parsing(): """Parsear un YAML de LOLBAS y verificar extracción de MitreID y commands""" def test_caldera_yaml_parsing(): """Parsear un YAML de CALDERA ability y verificar campos""" def test_elastic_toml_parsing(): """Parsear un TOML de Elastic y verificar extracción de KQL y threat mappings""" def test_stix_threat_actor_parsing(): """Parsear un bundle STIX de ejemplo y verificar extracción de intrusion-sets y relationships""" def test_d3fend_api_response_parsing(): """Parsear una respuesta mock de la API D3FEND""" def test_no_duplicates_on_reimport(): """Verificar que la lógica de deduplicación funciona con datos mock""" @pytest.mark.integration class TestDataSourcesIntegration: """Tests de integración — requieren acceso a red. Ejecutar con: pytest -m integration""" def test_sigma_full_import(): """Importar desde GitHub real y verificar volumen""" def test_lolbas_full_import(): """Importar LOLBAS completo""" def test_caldera_full_import(): """Importar CALDERA completo""" def test_elastic_full_import(): """Importar Elastic rules completo""" ``` **Crear fixtures:** `backend/tests/fixtures/` con archivos de ejemplo: - `sample_sigma_rule.yml` - `sample_lolbas_entry.yml` - `sample_caldera_ability.yml` - `sample_elastic_rule.toml` - `sample_stix_bundle.json` (con 2-3 intrusion-sets y relationships) **Validación:** - [ ] `pytest tests/test_data_sources.py` (sin flag integration) pasa rápido (<10s) - [ ] `pytest tests/test_data_sources.py -m integration` pasa (puede tardar minutos) - [ ] Cada parsing se verifica independientemente con fixtures locales --- ### T-236: Tests de scoring, métricas y compliance **Archivo a crear:** `backend/tests/test_scoring_and_compliance.py` **Tests:** ```python class TestScoring: def test_technique_score_all_detected(): """Técnica con todos los tests detected → score alto""" def test_technique_score_no_tests(): """Técnica sin tests → score 0""" def test_technique_score_partial_detection(): """Técnica con detección parcial → score intermedio""" def test_technique_score_freshness_penalty(): """Tests > 180 días → penalización en freshness""" def test_scoring_weights_configurable(): """Cambiar pesos cambia el score resultante""" def test_threat_actor_coverage_score(): """Score de cobertura contra un actor con datos conocidos""" def test_organization_score_aggregation(): """Score global agrega correctamente los scores de técnicas""" class TestOperationalMetrics: def test_mttd_calculation(): """MTTD se calcula desde timestamps del audit_log""" def test_mttr_calculation(): """MTTR incluye tiempo de remediación""" def test_detection_efficacy(): """Detection efficacy con datos de prueba conocidos""" def test_metrics_with_no_data(): """Métricas retornan null cuando no hay datos suficientes""" class TestCompliance: def test_control_fully_covered(): """Control con todas las técnicas validated → covered""" def test_control_partially_covered(): """Control con técnicas mixtas → partially_covered""" def test_control_not_covered(): """Control con todas las técnicas sin tests → not_covered""" def test_compliance_percentage(): """Porcentaje global de compliance calculado correctamente""" def test_compliance_gaps(): """Gaps retorna solo controles no cubiertos con sus técnicas""" ``` **Validación:** - [ ] `pytest tests/test_scoring_and_compliance.py` pasa todos los tests - [ ] Los cálculos son correctos con datos conocidos - [ ] Los edge cases (sin datos, datos parciales) se manejan sin errores --- ### T-237: Tests de campañas, snapshots y re-testing **Archivo a crear:** `backend/tests/test_campaigns_and_snapshots.py` **Tests:** ```python class TestCampaigns: def test_create_campaign_with_tests(): """CRUD básico de campaña con tests ordenados""" def test_campaign_progress_calculation(): """Progreso se calcula según estado de tests""" def test_generate_from_threat_actor(): """Generación automática de campaña desde actor cubre los gaps""" def test_circular_dependency_prevention(): """Intentar crear dependencia circular en campaign_tests falla""" def test_campaign_cloning(): """Clonación de campaña recurrente crea tests nuevos con datos correctos""" def test_campaign_scheduling_next_run(): """next_run_at se calcula correctamente para weekly/monthly/quarterly""" class TestSnapshots: def test_create_snapshot(): """Snapshot captura estado actual correctamente""" def test_compare_snapshots_improvements(): """Comparación detecta técnicas que mejoraron""" def test_compare_snapshots_regressions(): """Comparación detecta técnicas que empeoraron""" def test_snapshot_cleanup(): """Cleanup mantiene solo los últimos N snapshots""" def test_snapshot_normalized_storage(): """Verificar que el almacenamiento normalizado funciona correctamente""" class TestRetesting: def test_retest_created_on_remediation(): """Completar remediación crea retest automáticamente""" def test_retest_points_to_original(): """Retest de un retest apunta al test original, no al intermedio""" def test_retest_max_limit(): """Al alcanzar MAX_RETEST_COUNT no se crea retest""" def test_retest_chain_query(): """Endpoint /tests/{id}/retest-chain retorna cadena completa""" def test_retest_has_correct_data(): """Retest tiene mismos datos base que el original""" ``` **Validación:** - [ ] `pytest tests/test_campaigns_and_snapshots.py` pasa todos los tests - [ ] El flujo completo de campañas funciona - [ ] Los snapshots y comparaciones son correctos - [ ] El re-testing respeta el límite máximo --- ## FASE 33 — Pulido Final V3 ### T-238: Actualizar navegación completa **Objetivo:** Integrar todas las nuevas páginas en la navegación. **Archivos a modificar:** - `frontend/src/App.tsx` - `frontend/src/components/Sidebar.tsx` **Sidebar actualizado:** ``` 📊 Dashboard 📊 Executive Dashboard (leads + admin) 🔲 ATT&CK Matrix (heatmap avanzado) 🧪 Tests ├─ All Tests ├─ My Pending Tasks └─ Test Catalog 📋 Campaigns 👤 Threat Actors 📜 Compliance 📈 Comparison (leads + admin) 📄 Reports ⚙️ System (admin) ├─ Data Sources ├─ MITRE Sync ├─ Users └─ Audit Log ``` **Nuevas rutas:** ``` /executive-dashboard → ExecutiveDashboardPage /campaigns → CampaignsPage /campaigns/:id → CampaignDetailPage /threat-actors → ThreatActorsPage /threat-actors/:id → ThreatActorDetailPage /compliance → CompliancePage /comparison → ComparisonPage /system/data-sources → DataSourcesPage ``` **Visibilidad por rol:** | Ruta | admin | red_lead | blue_lead | red_tech | blue_tech | |-----------------------|-------|----------|-----------|----------|-----------| | Dashboard | ✅ | ✅ | ✅ | ✅ | ✅ | | Executive Dashboard | ✅ | ✅ | ✅ | ❌ | ❌ | | ATT&CK Matrix | ✅ | ✅ | ✅ | ✅ | ✅ | | Tests (all) | ✅ | ✅ | ✅ | ✅ | ✅ | | Test Catalog | ✅ | ✅ | ✅ | ✅ | ✅ | | Campaigns | ✅ | ✅ | ✅ | ✅ | ✅ | | Threat Actors | ✅ | ✅ | ✅ | ✅ | ✅ | | Compliance | ✅ | ✅ | ✅ | ✅ | ✅ | | Comparison | ✅ | ✅ | ✅ | ❌ | ❌ | | Reports | ✅ | ✅ | ✅ | ✅ | ✅ | | System / Data Sources | ✅ | ❌ | ❌ | ❌ | ❌ | **Validación:** - [ ] Todas las rutas nuevas funcionan y cargan la página correcta - [ ] El sidebar muestra items según el rol del usuario logueado - [ ] La navegación es consistente (breadcrumbs o back links donde aplique) - [ ] No hay rutas rotas o 404 - [ ] Un usuario red_tech no ve Executive Dashboard ni Comparison en el sidebar - [ ] Un admin ve todo --- ### T-239: Optimización de rendimiento **Objetivo:** Asegurar que la plataforma rinde bien con volúmenes grandes de datos (3000+ técnicas, 5000+ templates, 10000+ detection rules). **Optimizaciones backend:** 1. **Índices adicionales** — Crear migración con índices que falten tras analizar queries lentas: ```python # Verificar con EXPLAIN ANALYZE las queries más frecuentes # Candidatos probables: Index('ix_detection_rules_technique_source', DetectionRule.mitre_technique_id, DetectionRule.source) Index('ix_snapshot_technique_states_snapshot_technique', SnapshotTechniqueState.snapshot_id, SnapshotTechniqueState.technique_id) Index('ix_campaign_tests_campaign', CampaignTest.campaign_id) ``` 2. **Paginación cursor-based** en listados grandes: - Test templates (5000+) - Detection rules (10000+) - Audit logs - Reemplazar offset-based por cursor-based donde el volumen supere 1000 registros habituales 3. **Caché de métricas y scores:** - Los scores de organización y métricas operativas son costosos de calcular - Implementar caché in-memory simple con TTL (diccionario con timestamp): ```python _score_cache = {} CACHE_TTL = 300 # 5 minutos def get_organization_score_cached(db): now = time.time() if "org_score" in _score_cache and now - _score_cache["org_score"]["ts"] < CACHE_TTL: return _score_cache["org_score"]["data"] result = calculate_organization_score(db) _score_cache["org_score"] = {"data": result, "ts": now} return result ``` - Invalidar caché cuando se valida un test o cambia un score 4. **Queries optimizadas:** - Usar `selectinload` para relaciones que siempre se necesitan (test.evidences, technique.tests) - Usar `subqueryload` para relaciones grandes - Evitar N+1 queries en endpoints de listado **Optimizaciones frontend:** 1. **Virtualización de tablas grandes:** - Añadir `@tanstack/react-virtual` (ya añadido en T-222 para el heatmap) - Aplicar también a: tabla de test templates, tabla de detection rules, tabla de audit logs - Umbral: virtualizar tablas que puedan superar 100 filas 2. **Lazy loading de páginas:** ```typescript // App.tsx const ExecutiveDashboard = React.lazy(() => import('./pages/ExecutiveDashboardPage')); const CompliancePage = React.lazy(() => import('./pages/CompliancePage')); // etc. para todas las páginas de V3 ``` - Envolver en `}>` 3. **Memoización:** - `React.memo` para HeatmapCell (se renderiza 3000+ veces) - `useMemo` para cálculos de colores y filtros en el heatmap - `useCallback` para handlers en componentes que se renderizan muchas veces 4. **Debounce en buscadores:** - Todos los campos de búsqueda con debounce de 300ms - Usar hook custom `useDebounce(value, delay)` **Validación:** - [ ] El heatmap con 3000+ técnicas renderiza sin lag perceptible (<1s para render inicial) - [ ] Las tablas con 5000+ filas scrollean suavemente (60fps) - [ ] Los endpoints de listado responden en < 500ms con volúmenes grandes - [ ] El dashboard ejecutivo carga en < 3 segundos - [ ] `EXPLAIN ANALYZE` de las queries principales muestra uso de índices - [ ] El caché de scores funciona (segunda petición es instantánea) - [ ] Lazy loading funciona (verificar en Network tab que los chunks se cargan bajo demanda) --- ### T-240: Documentación completa V3 **Archivos a crear/modificar:** - `README.md` — actualizar con todas las funcionalidades V3 - `docs/API.md` — documentar todos los endpoints nuevos - `docs/ARCHITECTURE.md` — nuevo - `docs/DATA_SOURCES.md` — nuevo - `docs/SCORING.md` — nuevo **README actualizado:** Secciones a añadir: - Descripción completa de todas las funcionalidades V3 - Diagrama de arquitectura simplificado (texto ASCII) - Guía de inicio rápido actualizada - Cómo importar datos de todas las fuentes (Data Sources) - Cómo configurar campañas y threat actors - Cómo generar reportes de compliance - Cómo usar el heatmap avanzado - Cómo configurar pesos de scoring - Variables de entorno nuevas **docs/ARCHITECTURE.md:** - Diagrama de la base de datos completa (todas las tablas y relaciones) - Diagrama de flujo de datos entre servicios - Descripción de cada servicio y su responsabilidad - Diagrama del pipeline de tests (draft → validated) - Diagrama de jobs programados (APScheduler) **docs/DATA_SOURCES.md:** Para cada fuente (Atomic Red Team, Sigma, LOLBAS, GTFOBins, CALDERA, Elastic, D3FEND, MITRE CTI): - Descripción de la fuente - URL del repositorio - Formato de datos (YAML, TOML, STIX, etc.) - Cómo se parsea y qué campos se extraen - Frecuencia de actualización recomendada - Volumen aproximado de datos - Troubleshooting: qué hacer si la importación falla (rate limits, formato cambiado, etc.) **docs/SCORING.md:** - Explicación del sistema de scoring - Descripción de cada componente del score con su peso - Cómo modificar los pesos - Ejemplos de cálculo - Cómo se agregan scores por táctica, actor y organización - Explicación de cada métrica operativa (MTTD, MTTR, etc.) **Validación:** - [ ] Un nuevo desarrollador puede entender la arquitectura leyendo ARCHITECTURE.md - [ ] DATA_SOURCES.md cubre todas las fuentes con instrucciones claras - [ ] SCORING.md explica el sistema de scoring con ejemplos - [ ] El README refleja todas las funcionalidades V3 - [ ] Swagger UI en /docs muestra todos los endpoints - [ ] Siguiendo el README desde cero se puede levantar todo el proyecto con datos importados --- ## Resumen de Fases V3 | Fase | Tareas | Descripción | |------|------------------|-------------------------------------------------------| | 21 | T-200 a T-202 | Seed de demo, modelo de fuentes y detection rules | | 22 | T-203 a T-207 | Importación de fuentes de tests y panel de gestión | | 23 | T-208 a T-212 | Perfiles de amenaza (Threat Actor Profiles) | | 24 | T-213 a T-214 | MITRE D3FEND: contramedidas defensivas | | 25 | T-215 a T-216 | Reglas de detección sugeridas por test | | 26 | T-217 a T-220 | Campañas de tests (attack chains / kill chain) | | 27 | T-221 a T-223 | Heatmap ATT&CK avanzado (estilo Navigator) | | 28 | T-224 a T-226 | Scoring y métricas avanzadas (MTTD, MTTR, etc.) | | 29 | T-227 a T-229 | Compliance y reportes (NIST, DORA, NIS2, ISO 27001) | | 30 | T-230 a T-232 | Comparación temporal y re-testing automático | | 31 | T-233 a T-234 | Scheduling y automatización de campañas | | 32 | T-235 a T-237 | Tests automatizados V3 | | 33 | T-238 a T-240 | Pulido final y documentación V3 | > **Total V3: 41 tareas = 41 commits mínimo** > Cada tarea es autocontenida y verificable antes de hacer commit. --- ## Resumen General del Proyecto Aegis | Bloque | Tareas | Commits | Descripción | |--------|-----------|---------|---------------------------------------| | MVP | T-001–036 | 36 | Plataforma base funcional | | V2 | T-100–135 | 36 | Flujo Red/Blue, templates, notificaciones | | V3 | T-200–240 | 41 | Enterprise: fuentes, scoring, compliance | | **Total** | **113 tareas** | **113 commits** | **Plataforma completa** | --- ## Análisis Competitivo: Qué Copiamos de Cada Plataforma ### De [Validato](https://validato.io/) - Step-by-step remediation (V2: T-130) - Mapeo a MITRE D3FEND (V3: T-213) - Re-testing post-remediación (V3: T-232) - Validación continua con campañas recurrentes (V3: T-233) - Resultados mapeados a frameworks de compliance (V3: T-227) ### De [Cymulate](https://cymulate.com/) - Full kill chain campaigns (V3: T-217) - Reglas de detección sugeridas por test (V3: T-215) - Múltiples fuentes de tests — 100,000+ scenarios (V3: T-201–206) - Daily threat updates con sync automático (V3: T-207) - Detection heatmap avanzado (V3: T-221) - Generación de campañas desde threat actors (V3: T-218) ### De [Picus Security](https://www.picussecurity.com/) - Detection Rule Validation (V3: T-216) - Catálogo masivo de tests de múltiples fuentes (V3: T-201–206) - Filtros de threat actors por sector/región (V3: T-210) - Emulación de grupos APT específicos (V3: T-208) - Constructor de campañas desde APT profiles (V3: T-218) - Multi-framework compliance: NIST, DORA, ISO (V3: T-227) ### De [AttackIQ](https://www.attackiq.com/) - Templates pre-construidos por escenario (V2: T-103) - MITRE ATT&CK Navigator integration con export (V3: T-221) - Campañas recurrentes programadas (V3: T-233) - Purple team collaboration Red/Blue (V2: core feature) - Detection pipeline validation (V3: T-216) - Contextual risk prioritization con scoring (V3: T-224) ### Fuentes Open-Source Únicas de Aegis - **Atomic Red Team**: 1,500+ tests atómicos (V2: T-108) - **SigmaHQ**: 3,000+ reglas de detección (V3: T-203) - **LOLBAS + GTFOBins**: 750+ técnicas living-off-the-land (V3: T-204) - **MITRE CALDERA**: 400+ abilities ejecutables (V3: T-205) - **Elastic Detection Rules**: 1,000+ reglas KQL (V3: T-206) - **MITRE D3FEND**: 200+ contramedidas defensivas (V3: T-213) - **MITRE CTI**: 140+ threat actor profiles (V3: T-209) ### Lo que Aegis NO tiene (y las plataformas enterprise sí) > Estas funcionalidades requieren infraestructura de agentes/endpoints y quedan > fuera del scope de Aegis como plataforma de gestión: 1. **Ejecución automática de ataques en endpoints** (requiere agentes instalados) 2. **Integración directa con SIEMs** (Splunk, Elastic, QRadar) para verificar alertas en tiempo real 3. **Integración con EDR** (CrowdStrike, SentinelOne) para verificar detección automática 4. **Sandbox de ejecución segura** (entorno aislado para ejecutar payloads) 5. **API de ejecución remota** (ejecutar tests automáticamente en hosts) > Aegis se posiciona como **plataforma de gestión y tracking** del proceso de validación, > no como herramienta de ejecución automática. Los equipos ejecutan manualmente (o con > sus propias herramientas) y documentan resultados en Aegis.