feat(devsecops): agregar Semgrep SAST en modo auditoría al pipeline
Escanea workloads/ecommerce con rulesets públicos del registro de Semgrep (p/typescript, p/react, p/nextjs, p/security-audit) vía la imagen oficial semgrep/semgrep:1.173.0. Sin --error a propósito: siempre termina en exit 0, solo reporta — primera vuelta para revisar juntos qué reglas deberían pasar a bloquear más adelante. Validado contra el código real: 0 hallazgos en 91 reglas / 72 archivos. Documenta la herramienta en docs/devsecops/sast.md, incluyendo la diferencia con gitleaks/trivy y qué significa (y qué no) un scan limpio.
This commit is contained in:
@@ -260,6 +260,51 @@ jobs:
|
||||
--exit-code 0 \
|
||||
"${MANIFEST_FILE}"
|
||||
|
||||
# Modo auditoría: sin --error a propósito, Semgrep siempre termina
|
||||
# con exit 0 aunque reporte hallazgos. Es la primera vuelta — se
|
||||
# revisan los resultados en conjunto antes de decidir qué reglas
|
||||
# deberían pasar a bloquear el pipeline más adelante.
|
||||
- name: Escaneo SAST (Semgrep) — modo auditoría, no bloquea
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
SEMGREP_IMAGE="semgrep/semgrep:1.173.0"
|
||||
|
||||
docker run --rm \
|
||||
-v "${{ github.workspace }}:/src" \
|
||||
-w /src \
|
||||
"${SEMGREP_IMAGE}" \
|
||||
semgrep scan \
|
||||
--config=p/typescript \
|
||||
--config=p/react \
|
||||
--config=p/nextjs \
|
||||
--config=p/security-audit \
|
||||
--json \
|
||||
--output=semgrep-report.json \
|
||||
"${APP_DIR}"
|
||||
|
||||
echo "=== Resumen Semgrep ==="
|
||||
docker run --rm \
|
||||
-v "${{ github.workspace }}:/src" \
|
||||
-w /src \
|
||||
"${SEMGREP_IMAGE}" \
|
||||
python3 -c "
|
||||
import json
|
||||
data = json.load(open('semgrep-report.json'))
|
||||
results = data.get('results', [])
|
||||
print(f'Hallazgos: {len(results)}')
|
||||
for r in results:
|
||||
print(f\" [{r['extra']['severity']}] {r['check_id']} - {r['path']}:{r['start']['line']}\")
|
||||
"
|
||||
|
||||
- name: Publicar reporte de Semgrep
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: semgrep-report
|
||||
path: semgrep-report.json
|
||||
if-no-files-found: ignore
|
||||
|
||||
- name: Login en Gitea Registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
# SAST (Semgrep) — análisis estático de código
|
||||
|
||||
!!! info "Qué problema resuelve"
|
||||
SAST significa *Static Application Security Testing*: analizar el
|
||||
**código fuente** en busca de patrones de programación inseguros, sin
|
||||
ejecutar la aplicación. Semgrep lee cada archivo `.ts`/`.tsx` y lo
|
||||
compara contra un catálogo de reglas — cada regla describe una forma
|
||||
de escribir código que suele terminar en una vulnerabilidad conocida
|
||||
(inyección, XSS, uso inseguro de una API, etc.).
|
||||
|
||||
## En qué se diferencia de Gitleaks y Trivy
|
||||
|
||||
Las tres herramientas ya integradas a este pipeline analizan cosas
|
||||
completamente distintas — vale la pena tenerlo claro porque a primera
|
||||
vista "escaneo de seguridad" suena como una sola categoría:
|
||||
|
||||
| Herramienta | Qué mira | Pregunta que responde |
|
||||
|---|---|---|
|
||||
| [Gitleaks](gitleaks.md) | El texto de los archivos y el historial de git | "¿Hay una credencial commiteada?" |
|
||||
| [Trivy](trivy.md) | Paquetes instalados (imagen) y configuración (YAML) | "¿Alguna dependencia tiene una CVE conocida? ¿El manifiesto de Kubernetes es inseguro?" |
|
||||
| **Semgrep (SAST)** | La **lógica** del código que escribimos nosotros | "¿Esta función, tal como está escrita, abre una vulnerabilidad?" |
|
||||
|
||||
Ninguna de las tres reemplaza a las otras. Una dependencia puede estar
|
||||
100% al día (sin CVEs, Trivy contento) y aun así el código propio puede
|
||||
construir una URL con un string sin sanitizar y quedar abierto a SSRF —
|
||||
eso solo lo detecta un análisis de la lógica del código, que es
|
||||
exactamente lo que hace Semgrep.
|
||||
|
||||
## Qué tipo de bugs detecta (ejemplos genéricos)
|
||||
|
||||
Los rulesets usados (`p/typescript`, `p/react`, `p/nextjs`,
|
||||
`p/security-audit`) cubren, entre otras cosas:
|
||||
|
||||
- **Inyección**: construir queries, comandos de shell o URLs concatenando
|
||||
strings con datos que vienen del usuario, en vez de usar una API
|
||||
parametrizada.
|
||||
- **XSS en React/Next.js**: usar `dangerouslySetInnerHTML` con contenido
|
||||
que no pasó por un sanitizador.
|
||||
- **SSRF**: hacer un `fetch()`/request server-side hacia una URL que
|
||||
construye el propio usuario, sin validar el host de destino.
|
||||
- **Criptografía insegura**: algoritmos de hash débiles (`md5`, `sha1`)
|
||||
usados para contraseñas o tokens, en vez de un KDF diseñado para eso.
|
||||
- **`eval` / `new Function()`** sobre datos no confiables.
|
||||
- **ReDoS**: expresiones regulares con backtracking exponencial que un
|
||||
input malicioso puede usar para colgar el proceso.
|
||||
- **Prototype pollution**: merges/asignaciones dinámicas de objetos que
|
||||
permiten sobrescribir `__proto__`.
|
||||
|
||||
## Resultado real de esta primera corrida
|
||||
|
||||
```text
|
||||
Scanning 72 files tracked by git with 292 Code rules:
|
||||
ts 87 rules 39 files
|
||||
js 81 rules 1 file
|
||||
json 1 rule 6 files
|
||||
|
||||
Ran 91 rules on 72 files: 0 findings.
|
||||
```
|
||||
|
||||
`workloads/ecommerce` salió limpio con estos rulesets: **0 hallazgos**.
|
||||
|
||||
!!! warning "0 hallazgos no significa 'código perfecto'"
|
||||
Significa que ningún patrón conocido de estos 91 rules hizo match —
|
||||
no es una garantía de ausencia de bugs, solo de ausencia de *estos*
|
||||
patrones específicos. SAST tiene falsos negativos por naturaleza (un
|
||||
bug de lógica de negocio nuevo, específico de esta app, no está en
|
||||
ningún ruleset genérico). El valor de correr esto en cada build no es
|
||||
"una vez limpio, siempre limpio" — es que si alguien introduce a
|
||||
futuro uno de estos patrones conocidos (por ejemplo, un
|
||||
`dangerouslySetInnerHTML` sin sanitizar en un componente nuevo), el
|
||||
pipeline lo va a marcar en ese mismo push.
|
||||
|
||||
## Por qué modo auditoría (no bloquea) en esta primera integración
|
||||
|
||||
El step corre **sin** la flag `--error` a propósito — Semgrep siempre
|
||||
termina con `exit 0`, reporta lo que encuentra pero nunca frena el
|
||||
pipeline. Es la primera vez que esta herramienta corre sobre el repo: la
|
||||
idea es revisar juntos qué reglas de los 91 activos generan ruido (falsos
|
||||
positivos específicos de este código) antes de decidir cuáles deberían
|
||||
pasar a bloquear.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[Semgrep scan] --> B{hallazgos?}
|
||||
B -- "sí" --> C["se reportan en el log<br/>+ artifact JSON"]
|
||||
B -- "no" --> C
|
||||
C --> D["✅ pipeline sigue<br/>(exit 0 siempre)"]
|
||||
```
|
||||
|
||||
Una vez que se decida qué reglas son suficientemente confiables para
|
||||
esta app, el paso natural es agregar `--error` **con un subconjunto**
|
||||
de reglas (no las 91 completas) usando `--config` más específico o
|
||||
`.semgrepignore` / reglas individuales marcadas como bloqueantes —
|
||||
todavía no se hizo ese recorte.
|
||||
|
||||
## Los rulesets elegidos
|
||||
|
||||
- `p/typescript` — patrones generales de TypeScript/JavaScript.
|
||||
- `p/react` — específico de componentes React (hooks mal usados, XSS vía
|
||||
props/render, etc.).
|
||||
- `p/nextjs` — patrones propios del framework (App Router, API routes,
|
||||
middlewares).
|
||||
- `p/security-audit` — catálogo transversal de seguridad (inyección,
|
||||
criptografía débil, deserialización insegura) sin atarse a un
|
||||
framework específico.
|
||||
|
||||
Son rulesets **públicos y gratuitos** del registro de Semgrep — no
|
||||
requieren cuenta ni login (`semgrep login` solo hace falta para acceder a
|
||||
reglas adicionales de pago, que no se usan acá).
|
||||
|
||||
## Dónde ver el resultado
|
||||
|
||||
El JSON completo (`semgrep-report.json`) se publica como artifact del
|
||||
pipeline (`semgrep-report`) en cada corrida, tenga o no hallazgos —
|
||||
mismo patrón que Gitleaks y Trivy.
|
||||
@@ -101,6 +101,7 @@ nav:
|
||||
- DevSecOps:
|
||||
- Gitleaks (secretos): devsecops/gitleaks.md
|
||||
- Trivy (imagen + IaC): devsecops/trivy.md
|
||||
- SAST (Semgrep): devsecops/sast.md
|
||||
|
||||
extra:
|
||||
social:
|
||||
|
||||
Reference in New Issue
Block a user