# Análisis de Seguridad con CodeQL


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

Este notebook ejecuta un análisis de seguridad estático sobre los
repositorios clonados en `data/repos/` utilizando CodeQL, la herramienta
de análisis de código de GitHub.

## ¿Qué es CodeQL?

CodeQL es un motor de búsqueda de código que permite escribir consultas
para encontrar vulnerabilidades, problemas de seguridad y defectos de
codificación en el código fuente. Produce resultados en formato SARIF
(Static Analysis Results Interchange Format).

## Flujo de Ejecución

1.  **Descubrimiento de repositorios**: Escanea `data/repos/` para
    encontrar todos los subdirectorios
2.  **Creación de base de datos CodeQL**: Para cada repositorio, CodeQL
    crea una base de datos indexada del código
3.  **Análisis**: Se ejecutan consultas de seguridad predefinidas en la
    base de datos
4.  **Generación de resultados**: Los hallazgos se convierten a formato
    JSON normalizado y se guardan en `data/results/`

## Preparación: Importar `scripts/generate_codeql.py`

A continuación importaremos el módulo `CodeQLAnalyzer` desde el archivo
`scripts/generate_codeql.py`.

``` python
import sys
from pathlib import Path
import json
import pandas as pd

# Agregar el directorio scripts al path para importar el modulo generate_codeql
# Este módulo contiene la clase CodeQLAnalyzer que orquesta todo el análisis
project_root = Path().cwd().parent.parent
scripts_path = project_root / "scripts"
if str(scripts_path) not in sys.path:
    sys.path.insert(0, str(scripts_path))

print(f"Notebook working directory: {Path().cwd()}")
print(f"Project root: {project_root}")
print(f"Scripts path: {scripts_path}")
print(f"Importing from: generate_codeql.py")
```

    Notebook working directory: /workspaces/id_2026/nbs/vuln
    Project root: /workspaces/id_2026
    Scripts path: /workspaces/id_2026/scripts
    Importing from: generate_codeql.py

``` python
# Importar la clase CodeQLAnalyzer desde generate_codeql.py
from generate_codeql import CodeQLAnalyzer

print("✓ Importado correctamente: CodeQLAnalyzer desde scripts/generate_codeql.py")
```

    ✓ Importado correctamente: CodeQLAnalyzer desde scripts/generate_codeql.py

## Configuración

``` python
# Configurar rutas
repos_path = project_root / "data" / "repos"
output_path = project_root / "data" / "results"

# Crear analizador
analizador = CodeQLAnalyzer(
    repos_path=str(repos_path),
    output_path=str(output_path)
)

# Configurar para ejecución normal (no dry-run)
analizador.dry_run = False

print(f"Repos path: {repos_path}")
print(f"Output path: {output_path}")
print(f"Dry run: {analizador.dry_run}")
```

    Repos path: /workspaces/id_2026/data/repos
    Output path: /workspaces/id_2026/data/results
    Dry run: False

## Ejecución: Análisis CodeQL (usando `scripts/generate_codeql.py`)

Ahora ejecutaremos el análisis CodeQL sobre todos los repositorios
descubiertos. El script `generate_codeql.py` manejará automáticamente la
orquestación completa.

``` python
# Descubrir repositorios usando el método del CodeQLAnalyzer
# Este método viene de scripts/generate_codeql.py
repositorios = analizador.discover_repositories()
print(f"Repositorios encontrados: {len(repositorios)}")
for repo in repositorios:
    print(f"  - {repo}")
```

    Repositorios encontrados: 3
      - data/repos/claude-code-action
      - data/repos/genai-code-review
      - data/repos/opencode

``` python
print("Iniciando análisis CodeQL con scripts/generate_codeql.py...")
analizador.run()
print("✓ Análisis completado")
```

    INFO | Usando CodeQL CLI: /usr/local/bin/codeql
    INFO | === Diagnóstico del Entorno CodeQL ===

    Iniciando análisis CodeQL con scripts/generate_codeql.py...

    INFO | ✓ CodeQL CLI: CodeQL command-line toolchain release 2.25.1.
    INFO | ✓ Node.js: v20.20.2
    INFO | ✓ npm: 10.8.2
    INFO | Verificando query packs...
    INFO | ✓ Query pack codeql/python-queries disponible
    INFO | ✓ Query pack codeql/javascript-queries disponible
    INFO | ✓ Query pack codeql/java-queries disponible
    INFO | === Fin Diagnóstico ===

    INFO | [1/3] Procesando repositorio data/repos/claude-code-action
    INFO | Lenguaje detectado en claude-code-action: javascript
    INFO | Directorio temporal CodeQL: /tmp/codeql_analysis
    INFO | Creando base de datos CodeQL para claude-code-action (lenguaje: javascript)...
    INFO | Usando suite compilada: /home/vscode/.codeql/packages/codeql/javascript-queries/2.3.6/codeql-suites/javascript-security-and-quality.qls
    INFO | SARIF guardado en: /workspaces/id_2026/data/results/claude-code-action_temp.sarif (284762 bytes)
    INFO | SARIF output length: 284762 bytes
    INFO | parse_sarif: recibiendo 284762 bytes
    INFO | parse_sarif: 1 runs encontrados
    INFO | parse_sarif: 16 resultados en run[0]
    INFO | parse_sarif: total_issues=16
    INFO | save_analysis: claude-code-action con 16 issues
    INFO | Analisis CodeQL guardado en data/results/claude-code-action-codeql.json
    INFO | [2/3] Procesando repositorio data/repos/genai-code-review
    INFO | Lenguaje detectado en genai-code-review: python
    INFO | Creando base de datos CodeQL para genai-code-review (lenguaje: python)...
    INFO | Usando suite compilada: /home/vscode/.codeql/packages/codeql/python-queries/1.7.11/codeql-suites/python-security-and-quality.qls
    INFO | SARIF guardado en: /workspaces/id_2026/data/results/genai-code-review_temp.sarif (132815 bytes)
    INFO | SARIF output length: 132815 bytes
    INFO | parse_sarif: recibiendo 132815 bytes
    INFO | parse_sarif: 1 runs encontrados
    INFO | parse_sarif: 4 resultados en run[0]
    INFO | parse_sarif: total_issues=4
    INFO | save_analysis: genai-code-review con 4 issues
    INFO | Analisis CodeQL guardado en data/results/genai-code-review-codeql.json
    INFO | [3/3] Procesando repositorio data/repos/opencode
    INFO | Lenguaje detectado en opencode: javascript
    INFO | Creando base de datos CodeQL para opencode (lenguaje: javascript)...
    INFO | Usando suite compilada: /home/vscode/.codeql/packages/codeql/javascript-queries/2.3.6/codeql-suites/javascript-security-and-quality.qls
    INFO | SARIF guardado en: /workspaces/id_2026/data/results/opencode_temp.sarif (1454012 bytes)
    INFO | SARIF output length: 1454012 bytes
    INFO | parse_sarif: recibiendo 1454012 bytes
    INFO | parse_sarif: 1 runs encontrados
    INFO | parse_sarif: 218 resultados en run[0]
    INFO | parse_sarif: total_issues=218
    INFO | save_analysis: opencode con 218 issues
    INFO | Analisis CodeQL guardado en data/results/opencode-codeql.json
    INFO | Resumen final | total_repos=3 | repos_analizados=3 | archivos_generados=3 | omitidos=0 | errores=0

    ✓ Análisis completado

## Inspección de Resultados

``` python
# Listar archivos de resultados generados
output_path = project_root / "data" / "results"
codeql_files = sorted(output_path.glob("*-codeql.json"))

print(f"📁 Buscando en: {output_path}")
print(f"✓ Archivos de análisis CodeQL encontrados: {len(codeql_files)}")
for archivo in codeql_files:
    tamaño = archivo.stat().st_size / 1024  # KB
    print(f"  - {archivo.name} ({tamaño:.1f} KB)")
```

    📁 Buscando en: /workspaces/id_2026/data/results
    ✓ Archivos de análisis CodeQL encontrados: 3
      - claude-code-action-codeql.json (6.9 KB)
      - genai-code-review-codeql.json (1.8 KB)
      - opencode-codeql.json (84.2 KB)

``` python
# Cargar y mostrar resumen de UN análisis
results_dir = project_root / "data" / "results"
results_files = sorted(results_dir.glob("*-codeql.json"))

print(f"📂 Buscando en: {results_dir}")
print(f"📋 Archivos encontrados: {len(results_files)}")

if results_files:
    result_file = results_files[0]
    print(f"📖 Leyendo: {result_file.name}")
    
    with open(result_file, 'r', encoding='utf-8') as f:
        data_content = json.load(f)
    
    repo_name_clean = result_file.stem.replace('-codeql', '')
    total_found = data_content.get('total_issues', 0)
    
    print(f"\n📊 ANÁLISIS: {repo_name_clean}")
    print(f"{'='*50}")
    print(f"✓ Total de problemas encontrados: {total_found}")
    
    if total_found > 0:
        severity_data = data_content.get('issues_by_severity', {})
        print(f"\n🔍 Problemas por severidad:")
        for severity_type, count in severity_data.items():
            if count > 0:
                emoji = "🔴" if severity_type == "error" else "🟡" if severity_type == "warning" else "⚪"
                print(f"  {emoji} {severity_type}: {count}")
    else:
        print("⚠️  No se encontraron problemas")
else:
    print("❌ No se encontraron archivos de análisis CodeQL")
```

    📂 Buscando en: /workspaces/id_2026/data/results
    📋 Archivos encontrados: 3
    📖 Leyendo: claude-code-action-codeql.json

    📊 ANÁLISIS: claude-code-action
    ==================================================
    ✓ Total de problemas encontrados: 16

    🔍 Problemas por severidad:
      🟡 warning: 16

``` python
# Mostrar problemas detallados
output_path_det = project_root / "data" / "results"
codeql_files_det = sorted(output_path_det.glob("*-codeql.json"))

if codeql_files_det:
    archivo_det = codeql_files_det[0]
    
    with open(archivo_det, 'r', encoding='utf-8') as f:
        analisis_det = json.load(f)
    
    issues_list = analisis_det.get('issues', [])
    
    print(f"📋 Leyendo: {archivo_det.name}")
    print(f"📊 Total de issues en archivo: {len(issues_list)}")
    
    if issues_list:
        # Crear DataFrame con los problemas
        df_issues = pd.DataFrame(issues_list)
        
        # Seleccionar y reordenar columnas
        cols_mostrar = ['rule_id', 'level', 'message', 'file']
        cols_disponibles = [c for c in cols_mostrar if c in df_issues.columns]
        df_mostrar = df_issues[cols_disponibles].head(20)
        
        print(f"\n📋 Primeros 20 problemas encontrados:")
        print(f"{'='*100}")
        for idx, row in df_mostrar.iterrows():
            print(f"\n{idx+1}. [{row['level'].upper()}] {row['rule_id']}")
            print(f"   📝 {row['message'][:80]}")
            if 'file' in row and pd.notna(row['file']):
                print(f"   📂 {row['file']}")
        
        if len(issues_list) > 20:
            print(f"\n... y {len(issues_list)-20} problemas más")
    else:
        print("⚠️  No hay detalles de problemas en el archivo")
```

    📋 Leyendo: claude-code-action-codeql.json
    📊 Total de issues en archivo: 16

    📋 Primeros 20 problemas encontrados:
    ====================================================================================================

    1. [WARNING] js/incomplete-multi-character-sanitization
       📝 This string may still contain [<!--](1), which may cause an HTML element injecti
       📂 src/github/utils/sanitizer.ts

    2. [WARNING] js/xss-through-dom
       📝 [DOM text](1) is reinterpreted as HTML without escaping meta-characters.
       📂 docs/create-app.html

    3. [WARNING] js/http-to-file-access
       📝 Write to file system depends on [Untrusted data](1).
       📂 src/github/utils/image-downloader.ts

    4. [WARNING] js/file-access-to-http
       📝 Outbound network request depends on [file data](1).
       📂 src/entrypoints/post-buffered-inline-comments.ts

    5. [WARNING] js/file-access-to-http
       📝 Outbound network request depends on [file data](1).
       📂 src/mcp/github-file-ops-server.ts

    6. [WARNING] js/regex/missing-regexp-anchor
       📝 When this is used as a regular expression on a URL, it may match anywhere, and a
       📂 src/github/api/config.ts

    7. [WARNING] js/insecure-temporary-file
       📝 Insecure creation of file in [the os temp dir](1).
    Insecure creation of file in 
       📂 base-action/src/prepare-prompt.ts

    8. [WARNING] js/insecure-temporary-file
       📝 Insecure creation of file in [the os temp dir](1).
       📂 base-action/test/prepare-prompt.test.ts

    9. [WARNING] js/insecure-temporary-file
       📝 Insecure creation of file in [the os temp dir](1).
       📂 base-action/test/prepare-prompt.test.ts

    10. [WARNING] js/insecure-temporary-file
       📝 Insecure creation of file in [the os temp dir](1).
       📂 base-action/test/prepare-prompt.test.ts

    11. [WARNING] js/insecure-temporary-file
       📝 Insecure creation of file in [the os temp dir](1).
       📂 base-action/test/setup-claude-code-settings.test.ts

    12. [WARNING] js/insecure-temporary-file
       📝 Insecure creation of file in [the os temp dir](1).
       📂 src/github/utils/image-downloader.ts

    13. [WARNING] js/insecure-temporary-file
       📝 Insecure creation of file in [the os temp dir](1).
       📂 test/github-file-ops-path-validation.test.ts

    14. [WARNING] js/insecure-temporary-file
       📝 Insecure creation of file in [the os temp dir](1).
       📂 test/github-file-ops-path-validation.test.ts

    15. [WARNING] js/insecure-temporary-file
       📝 Insecure creation of file in [the os temp dir](1).
       📂 test/github-file-ops-path-validation.test.ts

    16. [WARNING] js/insecure-temporary-file
       📝 Insecure creation of file in [the os temp dir](1).
       📂 test/github-file-ops-path-validation.test.ts

## Análisis Detallado de Problemas

``` python
# Compilar estadísticas consolidadas
from collections import defaultdict

output_path_stats = project_root / "data" / "results"
codeql_files_stats = sorted(output_path_stats.glob("*-codeql.json"))

stats_consolidadas = {
    'total_repositories': len(codeql_files_stats),
    'total_issues': 0,
    'issues_by_repo': {},
    'issues_by_severity': defaultdict(int),
    'top_rules': defaultdict(int)
}

for archivo in codeql_files_stats:
    with open(archivo, 'r', encoding='utf-8') as f:
        data = json.load(f)
    
    repo_name = archivo.stem.replace('-codeql', '')
    total = data.get('total_issues', 0)
    
    stats_consolidadas['total_issues'] += total
    stats_consolidadas['issues_by_repo'][repo_name] = total
    
    # Contar por severidad
    for severity, count in data.get('issues_by_severity', {}).items():
        stats_consolidadas['issues_by_severity'][severity] += count
    
    # Contar top rules
    for issue in data.get('issues', []):
        rule = issue.get('rule_id', 'unknown')
        stats_consolidadas['top_rules'][rule] += 1

# Convertir defaultdicts a dicts para visualización
stats_consolidadas['issues_by_severity'] = dict(stats_consolidadas['issues_by_severity'])
stats_consolidadas['top_rules'] = dict(sorted(
    stats_consolidadas['top_rules'].items(), 
    key=lambda x: x[1], 
    reverse=True
)[:10])

print("\n📊 ESTADÍSTICAS CONSOLIDADAS DE CODEQL")
print(f"{'='*60}")
print(f"\n📁 Repositorios analizados: {stats_consolidadas['total_repositories']}")
print(f"🔴 Total de problemas: {stats_consolidadas['total_issues']}")

print(f"\n📋 Problemas por repositorio:")
for repo, count in stats_consolidadas['issues_by_repo'].items():
    print(f"  • {repo}: {count}")

print(f"\n⚠️  Problemas por severidad:")
for severity, count in sorted(stats_consolidadas['issues_by_severity'].items()):
    emoji = "🔴" if severity == "error" else "🟡" if severity == "warning" else "⚪"
    print(f"  {emoji} {severity}: {count}")

print(f"\n🎯 Top 10 reglas más comunes:")
for rule, count in list(stats_consolidadas['top_rules'].items())[:10]:
    print(f"  • {rule}: {count}")
```


    📊 ESTADÍSTICAS CONSOLIDADAS DE CODEQL
    ============================================================

    📁 Repositorios analizados: 3
    🔴 Total de problemas: 238

    📋 Problemas por repositorio:
      • claude-code-action: 16
      • genai-code-review: 4
      • opencode: 218

    ⚠️  Problemas por severidad:
      🔴 error: 0
      ⚪ note: 0
      🟡 warning: 238

    🎯 Top 10 reglas más comunes:
      • js/unused-local-variable: 112
      • js/trivial-conditional: 33
      • js/property-access-on-non-object: 20
      • js/insecure-temporary-file: 14
      • js/http-to-file-access: 6
      • js/incomplete-sanitization: 5
      • js/syntax-error: 4
      • js/useless-expression: 4
      • js/useless-assignment-to-local: 4
      • py/unused-import: 3

## Próximos Pasos

Los resultados del análisis CodeQL se han guardado en `data/results/`
con el patrón `{repo-name}-codeql.json`.

### Cómo usar estos resultados:

1.  **Revisar vulnerabilidades críticas**: Filtrar por `level: "error"`
    para identificar problemas de seguridad críticos
2.  **Seguimiento**: Integrar con sistemas de seguimiento de mermas
    (issues, PRs) para gestionar remediación
3.  **Análisis de tendencias**: Comparar resultados entre repositorios y
    períodos de tiempo
4.  **Automatizar**: Integrar estos análisis en CI/CD para detectar
    problemas continuamente

#### Para agregar nuevos repositorios:

1.  **Edita `data/repos.json`** y agrega nuevos repositorios:

``` json
{
    "repositories": [
        {
            "url": "https://github.com/owner/repo-name.git",
            "path": "data/repos/repo-name",
            "ref": "v1.0.0"
        }
    ]
}
```

2.  **Ejecuta en la terminal** (esto clonará los repositorios y los
    agregará como submódulos):

``` bash
uv run scripts/add_submodules.py
```

3.  **Ejecuta el análisis** nuevamente desde el notebook o la terminal:

``` bash
uv run scripts/generate_codeql.py
```
