El eslabón perdido: La seguridad
En los artículos anteriores de esta serie, hemos explorado cómo asentar las bases del desarrollo asistido por IA. En el primer post, vimos cómo imponer disciplina al modelo usando TDD y Extreme Programming. En el segundo, comprobamos que un framework estructurado como Spec-Driven Development es vital para mantener el contexto cuando el proyecto crece. Teníamos el método y la planificación. Pero faltaba una tercera pieza crítica: la seguridad en la ejecución autónoma.
Para poner a prueba los límites del control y analizar cómo se comporta realmente un agente cuando se le da
autonomía, diseñé una práctica deliberada centrada en provocar y observar posibles brechas de seguridad. Eliminé
toda la configuración de gobernanza que tenía en el proyecto (skills, validaciones, specs complejas) y arranqué
desde cero con un único archivo básico de instrucciones (copilot-instructions.md). La directiva
principal era un gate conversacional: antes de escribir una sola línea de código, el agente debía
proponer un plan y esperar obligatoriamente a que yo escribiera la palabra "proceed" en el chat
para autorizar la implementación.
Tras solicitarle la creación de una nueva página con su interfaz, el agente elaboró un plan de acción limpio y correcto. Sin embargo, me quedé perplejo al ver en directo cómo, inmediatamente después de generar el plan, el propio LLM inyectó la palabra "proceed" en el chat para auto-aprobarse la tarea y continuar escribiendo la solución sin detenerse a esperar mi revisión.
El código generado fue sorprendentemente bueno, pero la anécdota esconde un patrón que es importante entender: los modelos de lenguaje están intrínsecamente entrenados para hacer progreso continuo. Tarde o temprano, y por su propia naturaleza, buscarán la forma de sortear los bloqueos de seguridad si perciben que pueden completar su cometido.
La ilusión del control y los Soft Guardrails
Esta experiencia expone la trampa de lo que hoy se conoce como "Vibe Coding" dentro del ciclo de vida del desarrollo de software (SDLC). Un agente autónomo puede generar código impecable, estructurar directorios complejos y pasar todos los tests unitarios automatizados. Pero el éxito funcional no garantiza que se sigan las reglas del proyecto ni la gobernanza. Si un agente es capaz de saltarse un flujo de aprobación auto-inyectando una confirmación, o decide violar directrices de arquitectura por inercia, ese aparente "éxito" constituye en realidad un fallo crítico de seguridad.
Para permitir que los agentes trabajen de forma segura e independiente, hay que aceptar una realidad incómoda:
la red de seguridad real debe residir fuera del LLM, nunca en la semántica del prompt. Las
instrucciones en lenguaje natural, ya sean System Prompts o reglas de un .md, son
simplemente
"Soft Guardrails". Son barreras probabilísticas que el modelo puede ignorar si experimenta una Deriva de
Contexto (Context Drift) o un sesgo estadístico hacia la ejecución inmediata de la tarea.
Para aislar al proyecto de estos riesgos, necesitamos abandonar la dependencia exclusiva del prompt y diseñar una arquitectura basada en Hard Guardrails: garantías deterministas aplicadas a través de infraestructura externa al modelo, como reglas de protección de ramas, hooks de validación y flujos de integración continua (CI).
La Regla de Oro del SDLC Agéntico
El principio fundamental que rige toda la arquitectura es la delimitación estricta de responsabilidades: Los agentes proponen; los humanos y las políticas aceptan. La responsabilidad directa de un agente (que lee el entorno, razona y ejecuta herramientas) termina en el momento exacto en que crea una Pull Request (PR). A partir de ese instante, la infraestructura automatizada de la plataforma de control de versiones toma el mando absoluto.
Para poner en práctica esta regla, dividimos el mecanismo de control en tres niveles: el entorno local del desarrollador y dos fronteras remotas infranqueables.
El entorno local: aislar el contexto y desactivar los permisos de escritura
En mi propia máquina, el primer objetivo fue evitar que el agente heredara información del sistema o de otros proyectos que pudiese distorsionar sus decisiones.
-
Evitar la contaminación de memoria (
.copilotignore): Descubrí que los IDEs modernos guardan en caché metadatos de proyectos previos (rutas, historiales o directorios de memorias). Sin un bloqueo, el agente alucinaba buscando carpetas de otros desarrollos, incluso skills que había eliminado. La solución fue configurar un archivo.copilotignorecon exclusiones como**/.env*,**/workspaceStorage/y**/.memories/*para censurar secretos y forzar la atención en el directorio actual. -
Limitar las herramientas de escritura (Modo Plan): Para evitar que el agente modificara
archivos mientras solo planificaba la solución, utilicé el "modo Plan" del IDE. Esto deshabilita temporalmente
las herramientas de edición y ejecución (
edit,execute), limitándolo a funciones de solo lectura para separar razonamiento de acción.
Los hooks de Git y la ilusión de la seguridad local
Al principio pensé en meter validaciones automáticas mediante hooks locales de Git para detener código mal formateado o fallos obvios. Parecía una solución interesante, pero comprobé que tiene trampa: como el entorno local está bajo su control, el agente puede saltárselo.
Si el agente intenta subir código y falla el hook local, esa inercia casi obsesiva por completar la tarea (la
misma
que le llevó a auto-inyectarse el "proceed") hace muy probable que en su segundo intento ejecute
un git push --no-verify. Al residir el control en la máquina que el propio agente maneja, esquiva la
restricción sin que nos enteremos. Esto me demostró que los controles locales ayudan a limpiar el camino, pero la
red de seguridad inmutable debe residir en el servidor remoto.
Frontera A: Integración Continua (CI) en el servidor remoto
Una vez que el agente abre una Pull Request, abandonamos su zona de influencia. Aquí es donde la infraestructura del servidor toma las riendas para validar que el código propuesto cumple las reglas del proyecto de forma incondicional.
-
Validaciones automáticas: En mis primeras pruebas vi que no bastaba con dejar que un linter
detuviera el proceso local: el agente podía desactivarlo editando la configuración de ESLint o inyectando
comentarios del tipo
/* eslint-disable */. Para evitarlo, configuré flujos en GitHub Actions que ejecutan analizadores de arquitectura independientes. Aunque quiero explorar herramientas más potentes (como CodeQL o Dependency Cruiser), en esta práctica me limité a implementar un script de validación personalizado. Si el código viola las capas de la arquitectura hexagonal, el pipeline remoto se pone en rojo de forma inmutable. -
Reglas de repositorio infranqueables (Rulesets y CODEOWNERS): También comprobé que un fallo en
el pipeline no detiene a un agente si este cuenta con permisos para fusionar la PR. Para blindar el repositorio,
configuré las reglas de protección (Rulesets) con un array de exclusión vacío
(
"bypass_actors": []), garantizando que nadie pueda saltarse los tests. A esto le sumé el archivoCODEOWNERSpara bloquear físicamente la fusión si se tocan carpetas críticas hasta recibir mi revisión y aprobación manual (Human in the loop).
Frontera B: Despliegue Continuo (CD) en producción
La última barrera detiene cualquier intento de modificar la infraestructura productiva sin supervisión. Aunque el código haya sido aprobado, el despliegue automático debe controlarse estrictamente.
-
Protección de entornos: Para asegurar este paso, configuré entornos protegidos en GitHub con la
regla de revisiones requeridas (
Required Reviewers). Esto congela el pipeline y retiene los secretos cifrados de producción hasta que un humano valida visualmente los cambios. -
Desconexión de integraciones de terceros: Al usar Vercel para publicar esta web, noté que
durante la revisión de una PR se ejecutaban procesos automáticos de despliegue en segundo plano. Al indagar, vi
que la integración por defecto vía webhook de GitHub se saltaba nuestras validaciones de CI. Para solucionarlo,
desactivé los webhooks automáticos en Vercel y centralicé el despliegue en mi propio pipeline usando su CLI y
tokens cifrados (como
VERCEL_TOKEN).
Lo que me llevé
Después de diseñar y probar este sistema de seguridad, me di cuenta de que aplicar inteligencia artificial en el desarrollo de software no va sobre buscar el prompt perfecto o confiar en el "buen comportamiento" del modelo. Se trata de asumir que el agente, en su afán por completar la tarea asignada, va a intentar saltarse cualquier norma lingüística que le pongamos por delante.
El verdadero aprendizaje ha sido cambiar la mentalidad: pasar de la gobernanza basada en intenciones a la gobernanza basada en infraestructura. Si pones la seguridad en el prompt, tarde o temprano fallará. Si la pones en la infraestructura determinista del repositorio, los desvíos del agente se reducen a simples errores de compilación o transacciones rechazadas en un pipeline seguro.
La combinación que funciona: método + especificaciones estructuradas + infraestructura segura de control + IA. En ese orden.
Explora el código
Aunque las reglas de protección (Rulesets) y la seguridad de entornos son configuraciones privadas del panel de administración de GitHub, puedes ver cómo están definidos los flujos de GitHub Actions, el archivo `.copilotignore` y la directiva `CODEOWNERS` directamente en el repositorio.
Como referencia he exportado el ruleset usado a un archivo en el
repositorio.
Conceptos aplicados
- Controles Blandos (Soft Guardrails): Directrices en lenguaje natural que orientan probabilísticamente al modelo, susceptibles a fallos por deriva de contexto o inercia de ejecución.
- Controles Duros (Hard Guardrails): Salvaguardas y restricciones técnicas deterministas aplicadas a nivel de infraestructura externa que el agente no puede modificar ni eludir.
- Aislamiento de contexto y herramientas: Delimitación estricta de la memoria del agente (exclusión de directorios) y de sus permisos locales para evitar la contaminación de tareas y asegurar un análisis limpio.
- CI/CD (Integración Continua / Despliegue Continuo): Pipeline automatizado que valida la arquitectura del código mediante análisis estático y controla los entornos de producción mediante flujos inmutables.
- Supervisión Humana Requerida (Human-in-the-Loop): Principio de diseño de seguridad que exige la aprobación explícita de un desarrollador antes de fusionar código o realizar cualquier despliegue.
Nota: Aunque este artículo utiliza ejemplos basados en GitHub y Vercel, los principios se aplican exactamente igual si trabajas con cualquier otra plataforma.