Inicio Linux & Systems Cybersecurity Cloud & DevOps Networks & Infrastructure SIEM & Monitoring DFIR & Threat Intel Development & Other Todas las categorias Herramientas

DevSecOps con OpenSpec: Integracion de Seguridad en Spec-Driven Development

DevSecOps con OpenSpec: Integracion de Seguridad en Spec-Driven Development

Tabla de contenidos

Contexto: de las specs al enforcement

Este es el tercer articulo de una serie sobre como gestionar un sitio estatico con agentes IA y especificaciones declarativas:

  1. OpenCode Enterprise: Implementacion para Platform Engineering — El agente IA que vive en tu terminal.
  2. OpenSpec: Spec-Driven Development para Platform Engineering — El framework de especificaciones que define las reglas.
  3. Este post — La capa de seguridad que hace cumplir esas reglas automaticamente.

El problema que resolvemos hoy es simple: tener especificaciones sin enforcement automatico equivale a tener specs muertas. Puedes definir la CSP perfecta en un YAML, pero si nadie valida que _headers coincide con esa spec antes de cada deploy, el YAML es documentacion decorativa.

El primer paso es establecer una base solida de validaciones locales con herramientas open-source y hooks de Git: una capa que funciona antes de que el codigo llegue al repositorio remoto y que en el futuro se complementara con CI/CD en GitHub Actions.

Antes vs despues

Para entender el impacto real de esta implementacion, veamos como era el flujo de trabajo antes y como es ahora:

Sin DevSecOps (antes):

PasoAccionValidacion
Editar postModificar markdownNinguna
Editar _headersCambiar CSP manualmenteNinguna, confianza ciega
Commitgit add . && git commitNinguna
Deploygit push origin developerNinguna
Detectar errorUn lector reporta header rotoDias o semanas despues

Con DevSecOps (ahora):

PasoAccionValidacion
Editar postModificar markdownOpenSpec valida frontmatter en pre-commit
Editar _headersCambiar CSP manualmentegenerate-headers.js --validate bloquea si diverge de spec
Commitgit add . && git commitESLint, Bandit, JSON integrity, headers check
Pre-deploy./scripts/pre-deploy-check.shGitleaks + SAST completo + 35 checks OpenSpec
Deploygit push origin developerSolo si pre-deploy pasa

La diferencia fundamental no es la cantidad de herramientas sino cuando se detecta el error: antes se descubria en produccion (o peor, no se descubria); ahora se bloquea antes de que el commit exista. El coste de corregir un problema crece exponencialmente con cada fase que avanza sin ser detectado.

Arquitectura de la solucion

La capa DevSecOps se compone de tres niveles de validacion que se ejecutan en momentos diferentes del flujo de trabajo:

Nivel 1: Pre-commit (automatico, en cada commit)

HerramientaPropositoQue valida
ESLint + eslint-plugin-securitySAST JavaScripteval(), inyeccion, timing attacks
BanditSAST Pythonpickle, subprocess, hashes inseguros
validate-json-integrity.jsIntegridad de datosURLs maliciosas, dominios no autorizados
generate-headers.jsCompliance de headers_headers contra specs YAML
OpenSpec validate:postSchema de postsFrontmatter contra post.schema.yaml

Nivel 2: Pre-deploy (manual, antes de push)

HerramientaPropositoCobertura
GitleaksDeteccion de secretosTodo el repositorio
ESLint (scan completo)SAST JavaScriptTodos los scripts JS
Bandit (scan completo)SAST PythonTodos los scripts Python
OpenSpec validate:deploy35 checksHeaders, CSP, SEO, redirects, sitemap

Nivel 3: OpenSpec compliance (bajo demanda)

BASH
node scripts/admin.js report

Genera un score de compliance del 0% al 100% validando schemas, policies, catalogos y ficheros del sitio.

Implementacion: paso a paso

1. Herramientas de seguridad

Las dependencias se dividen en tres categorias:

JavaScript (npm devDependencies):

BASH
npm install -D eslint @eslint/js eslint-plugin-security eslint-plugin-unicorn

eslint-plugin-security detecta patrones peligrosos en Node.js: uso de eval(), require() con argumentos dinamicos, RegExp con input de usuario, object injection sinks y timing attacks potenciales.

Python (pip):

BASH
pip install bandit

Bandit es el SAST estandar para Python. Analiza el AST (Abstract Syntax Tree) y detecta uso de pickle (deserializacion insegura), subprocess con shell=True, funciones hash debiles (MD5, SHA1) y eval().

Binario (Gitleaks):

BASH
curl -sSL https://github.com/gitleaks/gitleaks/releases/download/v8.21.2/gitleaks_8.21.2_linux_x64.tar.gz | tar -xz
mv gitleaks ~/.local/bin/

Gitleaks escanea el repositorio completo (incluyendo historial Git) buscando API keys, tokens, claves privadas y passwords hardcodeados.

2. Configuracion de ESLint con reglas de seguridad

El fichero eslint.config.mjs configura ESLint en formato flat config (ESLint 9+):

JAVASCRIPT
import js from "@eslint/js";
import security from "eslint-plugin-security";

export default [
  js.configs.recommended,
  security.configs.recommended,
  {
    languageOptions: {
      ecmaVersion: 2022,
      sourceType: "commonjs",
    },
    rules: {
      "security/detect-eval-with-expression": "error",
      "security/detect-non-literal-require": "error",
      "security/detect-non-literal-regexp": "warn",
      "security/detect-object-injection": "warn",
      "security/detect-possible-timing-attacks": "warn",
      "no-implied-eval": "error",
      "no-new-func": "error",
      "no-eval": "error",
    },
  },
  {
    ignores: [
      "assets/**", "posts/**", "page/**",
      "category/**", "node_modules/**", "*.min.js",
    ],
  },
];

El bloque ignores es critico: los directorios de contenido HTML generado (posts/, assets/) se excluyen del SAST porque no son codigo ejecutable en servidor. Solo se analizan los scripts en scripts/ y .openspec/.

3. Configuracion de Bandit para Python

El fichero .bandit.yaml define que tests ejecutar y cuales omitir:

YAML
exclude_dirs:
  - assets
  - posts
  - node_modules
  - .git

skips:
  - B101  # assert_used (aceptable en scripts de admin)
  - B404  # import_subprocess (necesario para build scripts)

tests:
  - B301  # pickle
  - B307  # eval
  - B310  # urllib sin validacion SSL
  - B311  # random no criptografico
  - B324  # hashlib inseguro
  - B602  # subprocess con shell=True

Se omiten B101 (uso de assert) y B404 (import de subprocess) porque son patrones legitimos en scripts de administracion. El resto de tests se enfoca en riesgos reales de ejecucion de codigo y deserializacion.

4. Configuracion de Gitleaks

El fichero .gitleaks.toml extiende las reglas por defecto y anade deteccion especifica para nuestro stack:

TOML
[extend]
useDefault = true

[[rules]]
id = "cloudflare-api-token"
description = "Cloudflare API Token"
regex = '''(?i)cloudflare[_\-]?(?:api[_\-]?)?(?:token|key)\s*[:=]\s*['"]?([a-zA-Z0-9_\-]{40,})['"]?'''
keywords = ["cloudflare"]

[[rules]]
id = "anthropic-api-key"
description = "Anthropic API Key"
regex = '''sk-ant-api[0-9a-zA-Z_\-]{30,}'''
keywords = ["sk-ant"]

[allowlist]
description = "False positives for Red Orbita"
paths = [
  '''posts/.*\.html$''',
]

El allowlist de paths es fundamental: los posts HTML contienen ejemplos de API keys en tutoriales y writeups de CTF. Sin esta exclusion, Gitleaks reportaria decenas de falsos positivos.

5. Validacion de integridad JSON

El script validate-json-integrity.js protege los ficheros JSON de mapeo contra inyecciones:

JAVASCRIPT
const CONFIG = {
  allowedDomains: [
    'red-orbita.com', 'giscus.app',
    'fonts.googleapis.com', 'youtube.com',
  ],
  maliciousPatterns: [
    /javascript:/i, /vbscript:/i,
    /<script/i, /eval\s*\(/i,
    /__proto__/i,
  ],
  filesToCheck: [
    'url-mapping.json', 'redirects-mapping.json',
    'search-index.json', 'deep-categories.json',
  ],
};

El script recorre recursivamente cada valor string de los JSON y verifica que:

  • No contiene patrones de inyeccion (javascript:,