7 min de lectura

Agentes de IA que abren pull requests con controles seguros

Los agentes de IA que abren pull requests necesitan un alcance estricto del repositorio, ramas protegidas, asignación de revisores, evidencias de pruebas y un registro de auditoría para cada cambio.

Agentes de IA que abren pull requests con controles seguros

Los agentes de IA que abren pull requests mediante una API pueden ahorrar mucho tiempo de ingeniería, pero solo si el repositorio trata cada cambio generado como una contribución no confiable cuyo autor se puede rastrear. El límite útil es sencillo: un agente puede preparar un cambio propuesto; las personas y los controles del repositorio deciden si pertenece al código base.

He visto equipos poner esto en riesgo al concentrarse en la calidad del código del modelo e ignorar los permisos que lo rodean. Los fallos graves suelen ser muy corrientes. Una tarea dirigida a un servicio de staging termina en un repositorio de producción. Un token demasiado amplio concede en silencio acceso de escritura a todos los proyectos. Un agente abre diez pull requests casi idénticos después de un tiempo de espera. Alguien hace merge de uno porque el título parece razonable.

Una configuración segura no depende de que el agente tenga cuidado. Limita dónde puede actuar, obliga a que el cambio pase por la revisión habitual y deja un registro suficientemente completo para investigarlo después.

El alcance del repositorio debe ser explícito y aplicarse automáticamente

Un agente debe recibir permisos para un conjunto de repositorios con nombre, no para un alcance comodín de toda la organización que alguien piensa restringir más adelante. El alcance del repositorio responde a una pregunta concreta: ¿en qué bases de código puede leer, crear ramas de escritura y abrir pull requests este proceso?

Mantén la lista de permitidos fuera del texto de instrucciones del agente. Los prompts pueden orientar el comportamiento, pero no hacen cumplir la autorización. El componente que guarda la credencial del repositorio o realiza la solicitud a la API debe rechazar cualquier repositorio que no esté en la lista permitida.

Para cada repositorio permitido, define las ramas base y el espacio de nombres de escritura autorizados. Un registro útil tiene este aspecto:

repositories:
  - name: acme/payments-api
    base_branches: ["main", "release/2025.1"]
    write_branch_prefix: "agent/"
    pull_request_drafts: true
  - name: acme/docs
    base_branches: ["main"]
    write_branch_prefix: "agent/"
    pull_request_drafts: false

Este fragmento evita un fallo común: el agente recibe la solicitud de «corregir el texto del checkout», encuentra un archivo parecido en un repositorio que puede buscar y escribe allí porque sus credenciales se lo permiten. La lista de permitidos convierte ese caso en una solicitud denegada, no en un trabajo de limpieza para otra persona.

El alcance también incluye las operaciones del repositorio. La mayoría de los agentes necesitan leer archivos, crear una rama, hacer push de commits, leer comprobaciones y crear o actualizar un pull request. Rara vez necesitan cambiar la configuración del repositorio, registrar webhooks, modificar las reglas de protección de ramas, añadir claves de despliegue, gestionar miembros o hacer merge de cambios. No concedas esos permisos solo porque venían incluidos en un token amplio y cómodo.

Usa una identidad de bot independiente en lugar del token personal de un desarrollador. Un token personal dificulta la atribución, sobrevive mal a los cambios de trabajo y suele tener permisos que nadie recuerda haber concedido. Una identidad de bot te da un único actor que puedes suspender si algo sale mal.

El acceso de lectura merece la misma atención que el de escritura. Un agente que puede inspeccionar todos los repositorios privados puede exponer código fuente o configuración a través de sus propios registros, el contexto de la tarea y sus respuestas. Dale el conjunto mínimo de repositorios que resulte útil, aunque nunca reciba una credencial de escritura directa.

Un prefijo de rama es un límite de ejecución, no una preferencia de nombres

El agente debe crear ramas únicamente bajo un prefijo dedicado como agent/, y el servidor del repositorio debe aplicar esa restricción. Una convención escrita en un prompt acabará incumpliéndose, ya sea por una llamada de herramienta mal formada, un error de reintento o un agente que intenta satisfacer una tarea demasiado amplia.

Protege main, las ramas de release, las ramas de entorno y cualquier rama que despliegue automáticamente. El agente no debe poder hacerles push, hacerles force-push ni cambiar las reglas que las protegen.

Haz que los nombres de rama sean lo bastante deterministas para investigarlos y lo bastante únicos para evitar colisiones. Incluye una referencia de tarea y un sufijo aleatorio corto o un identificador de ejecución:

agent/OPS-1842-retry-payment-7f3a

No permitas que el agente use directamente los títulos de las incidencias como nombres de rama. Los títulos pueden contener secretos, nombres de clientes, caracteres no seguros o lenguaje engañoso. Genera el nombre de rama en el controlador y pásaselo al agente como un valor inmutable.

El commit base también necesita una regla explícita. Cuando el controlador inicia una ejecución, debe resolver la rama base aprobada a un SHA de commit y registrarlo. El agente crea su rama a partir de ese SHA, no a partir de lo que main signifique después de una larga ejecución de generación de código. Esto no elimina la divergencia, pero hace que sea visible y reproducible.

Una rama solo debe contener los commits asociados a su tarea. Eso significa que no debe incluir una pasada de formato oportunista, una actualización de dependencias no relacionada ni un intento de «limpiar» código cercano porque parecía extraño. Los cambios generados suelen parecer convincentes, y los revisores pasarán por alto modificaciones no relacionadas cuando estén dentro de un parche que por lo demás parece razonable.

Define un presupuesto de cambios antes de empezar el trabajo. Puede limitar los archivos modificados, el total de líneas o las rutas fuera del componente solicitado. El límite no evalúa por sí solo el riesgo. Es una alarma que indica al agente que debe detenerse y pedir una tarea nueva, en lugar de convertir en silencio una reparación pequeña en una reescritura de todo el repositorio.

La creación del pull request necesita una transacción de API comprobada

Una respuesta HTTP correcta no demuestra que el agente haya abierto el pull request adecuado. El controlador debe verificar el repositorio, la rama head, la rama base, el SHA del commit y el identificador del pull request devuelto antes de informar del éxito.

En una API de estilo GitHub, los campos importantes de la solicitud son el título propuesto, head, base, el cuerpo y el estado de borrador. El endpoint exacto varía según la plataforma, pero las comprobaciones de seguridad no:

{
  "title": "OPS-1842: retry transient payment gateway failures",
  "head": "agent/OPS-1842-retry-payment-7f3a",
  "base": "main",
  "body": "Task: OPS-1842\nBase commit: 4b2c...\nTests: unit payment retry suite\nLimits: no configuration changes",
  "draft": true
}

Antes de enviar la solicitud, consulta la rama y confirma que su SHA final coincide con el commit registrado por la ejecución. Después de recibir la respuesta, recupera el pull request y compara su head, base y estado con la solicitud. Registra el número inmutable del pull request o el identificador de nodo de la plataforma, no solo su URL.

Los reintentos necesitan un tratamiento especial. Los tiempos de espera de red crean el problema clásico de los pull requests duplicados: el servidor puede haber creado el pull request 418, pero el cliente no recibió la respuesta y vuelve a intentarlo. Mantén un registro de idempotencia en el controlador con el ID de la tarea, el repositorio, la rama, el SHA base y el número del pull request. Al reintentar, busca la rama y el pull request abierto existente antes de emitir una llamada de creación.

No uses el título de una tarea como único valor de idempotencia. Una solicitud recurrente como «actualizar la documentación generada» chocará con una ejecución anterior. El ID de ejecución debe identificar una ejecución concreta, mientras que el ID de la tarea ayuda a relacionar trabajos vinculados.

Los pull requests en borrador son un buen valor predeterminado para el trabajo de los agentes. Indican a los revisores que el cambio existe, pero que aún no ha superado el criterio de finalización declarado por quien lo creó. Un agente solo debe marcar un pull request como listo después de completar los comandos obligatorios y de que el registro de ejecución contenga sus resultados. Si tu repositorio no usa borradores, aplica una etiqueta como agent-created desde un controlador confiable, no mediante texto compuesto por el agente.

La asignación de revisores debe seguir la propiedad y el riesgo

El primer revisor debe proceder de las reglas de propiedad del repositorio, no de una suposición del agente sobre quién parece saber más. La documentación de CODEOWNERS de GitHub describe una correspondencia entre archivos y propietarios que puede solicitar revisiones para las rutas modificadas. GitLab ofrece mecanismos comparables de aprobación y propietarios del código. Esos archivos sirven como datos de enrutamiento, pero no hacen que la revisión sea obligatoria automáticamente a menos que la protección de ramas o las reglas de merge lo exijan.

La diferencia importa. Un repositorio puede mostrar que ha solicitado la revisión de un propietario del código y aun así permitir un merge sin su aprobación, según la configuración. Trata el enrutamiento y la aplicación de la regla como controles separados. Comprueba ambos con un pull request de prueba deliberadamente no autorizado antes de confiar en la política.

Usa la lista de archivos modificados después del commit final, no las rutas que el agente planeaba modificar. Un parche generado puede alcanzar una biblioteca compartida, un directorio de despliegue o una carpeta de migraciones al final de la ejecución. El cálculo de revisores debe ver lo que realmente cambió.

Añade a una persona responsable cuando la tarea afecte a áreas en las que las reglas de propiedad sean demasiado amplias o no existan. Esa persona es responsable de la intención de la tarea. Un propietario del código puede confirmar que la implementación encaja en un componente; la persona responsable puede confirmar que el comportamiento solicitado es correcto para el producto. No asignes a una docena de personas solo porque la diferencia de código atraviese varios límites. Las listas grandes de revisores producen el resultado conocido: cada persona supone que otra se ocupó de la parte difícil.

Algunas rutas deben obligar a seguir un proceso más estricto. Por ejemplo, las migraciones de bases de datos, el código de autorización, las definiciones de compilación y release, los manifiestos de dependencias, la configuración de infraestructura y los artefactos generados. La respuesta correcta no siempre es «bloquear al agente». A menudo es «exigir al propietario que entienda la consecuencia». Una migración puede superar las pruebas unitarias y aun así hacer imposible la reversión.

Asigna revisores mediante la API solo después de que exista el pull request y verifica la asignación resultante. Si un grupo de propietarios no puede recibir solicitudes, el controlador debe marcar el pull request como bloqueado en lugar de sustituirlo en silencio por un desarrollador cualquiera. Una sustitución silenciosa convierte una regla de propiedad en simple decoración.

Las pruebas describen evidencias, mientras que la aprobación decide la aceptación

Mantén las claves del repositorio fuera de los agentes
Sallyport inyecta las credenciales HTTP desde su bóveda cifrada, así que el agente recibe resultados, no claves del repositorio.

El agente debe indicar exactamente qué ejecutó, qué no ejecutó y por qué. «Las pruebas han pasado» es una afirmación inútil sin los comandos, el código de salida y el SHA del commit que probaron. Guarda también esas evidencias fuera del texto del pull request, porque un agente puede editarlo después.

Usa un informe estructurado pequeño para cada ejecución:

{
  "run_id": "run_01J...",
  "repository": "acme/payments-api",
  "head_sha": "8c71...",
  "commands": [
    {"command": "npm test -- payment-retry", "exit_code": 0},
    {"command": "npm run lint", "exit_code": 0}
  ],
  "not_run": ["integration suite requires payment sandbox approval"]
}

El controlador debe rechazar el paso a revisión cuando las evidencias indiquen un SHA distinto del de la punta de la rama. Esto detecta una secuencia sutil pero frecuente: el agente ejecuta las pruebas, hace una corrección «pequeña» más y abre el pull request sin repetir ninguna comprobación.

Las comprobaciones de estado obligatorias deben permanecer en el lado del repositorio. El agente no debe tener permiso para omitir comprobaciones, aprobar su propio pull request, modificar la protección de ramas ni hacer merge. Una comprobación puede demostrar que un comando conocido terminó correctamente. No puede demostrar que una nueva regla de autorización sea correcta, que se haya entendido el requisito o que la tarea debiera haberse intentado en ese repositorio.

No permitas que un resumen generado sustituya la revisión de la diferencia de código. Los buenos resúmenes ayudan a los revisores a orientarse, pero son afirmaciones del autor. Los revisores necesitan los cambios reales de los archivos, las pruebas, el contexto de la incidencia correspondiente y cualquier omisión deliberada.

Cada cambio creado necesita un registro de auditoría que resista un incidente

Verifica el registro sin conexión
Ejecuta sp audit verify para comprobar sin conexión la cadena hash cifrada, sin una clave de la bóveda.

La URL de un pull request no es un registro de auditoría. Desaparece cuando se mueven repositorios, se eliminan ramas, cambian los accesos o alguien edita la descripción. Mantén un registro de eventos de solo anexado que permita a un investigador saber quién inició una ejecución, qué proceso realizó cada llamada, qué repositorio cambió y qué devolvió el sistema.

Como mínimo, registra estos campos:

  • un ID de ejecución y la referencia original de la tarea o incidencia
  • la identidad del bot que actuó y la identidad del proceso de agente autenticado
  • el repositorio, la rama base, el SHA base, la rama head y cada SHA de commit creado
  • el tipo de solicitud de API, el identificador inmutable del pull request, las marcas de tiempo y el estado del resultado
  • las solicitudes de revisión, las aprobaciones, los resultados de las comprobaciones y los eventos de cierre, merge o rechazo

No guardes por defecto credenciales en texto plano, archivos fuente completos ni prompts de tareas arbitrarios en el registro de auditoría. Los investigadores necesitan datos de acciones fiables, no otra copia sin control de material sensible. Si conservas el contenido del parche, registra un resumen criptográfico y aplica tus reglas habituales de conservación y acceso.

Conviene mantener la diferencia entre un registro de actividad y un registro de decisiones. Un registro de actividad indica que una llamada de API creó el pull request 418. Un registro de decisiones indica quién aprobó esa sesión del agente, quién cambió su autorización y quién la revocó. Durante un incidente importan ambos. Necesitas saber qué ocurrió y por qué el actor tenía autoridad en ese momento.

Sallyport puede conservar las sesiones de los agentes y cada llamada HTTP o SSH en registros derivados de su registro de auditoría cifrado y encadenado mediante hashes, y sp audit verify comprueba la cadena sin conexión sobre el texto cifrado. Esto encaja con una configuración en la que el agente solicita una acción, pero nunca recibe la credencial del repositorio.

El encadenamiento mediante hashes hace detectables las modificaciones posteriores, pero no completa un registro de eventos débil. Registra las identidades del repositorio y de los commits en el límite de la acción. Un registro perfectamente verificado de «solicitud HTTP enviada» no te dirá si la solicitud creó el pull request equivocado.

Mantén las credenciales fuera del agente y separa la creación del merge

El agente nunca debe tener un token amplio del repositorio en su prompt, entorno, archivo de trabajo ni salida de herramientas. Una vez que el token entra en ese contexto, puede filtrarse a través de registros, historial del shell, mensajes de error, transcripciones copiadas o una instrucción que convenza al agente de imprimirlo. La redacción posterior no devuelve de forma fiable un secreto a tu control.

Usa una pasarela de acciones o un controlador limitado que acepte una solicitud concreta: crear una rama en este repositorio, hacer push de estos commits a este prefijo permitido, crear un pull request en borrador contra esta rama base aprobada o solicitar estos revisores. La pasarela inyecta las credenciales y devuelve el resultado. Debe rechazar las llamadas que no encajen en el alcance declarado.

Los permisos de creación y los de merge son privilegios distintos. Un servicio que puede crear un pull request puede estar autorizado a proponer miles de cambios incorrectos. Un servicio que puede hacer merge puede introducir un solo cambio incorrecto en producción. No los combines solo porque la demostración resulte más fluida. Mantén la acción de merge bajo las reglas de protección de ramas y una persona responsable, incluso cuando el agente haya generado un parche perfecto.

La autorización por ejecución también es mejor que confiar permanentemente en un proceso de agente. Las herramientas de los agentes pueden iniciar subprocesos, reutilizarse en trabajos inesperados y permanecer activas después de la tarea que justificó el acceso. Concede a cada proceso una sesión limitada, registra la aprobación y haz que la revocación sea inmediata.

Un simulacro de fallos revela las carencias que oculta el texto de una política

Exige aprobación en cada llamada
Marca una clave para aprobación en cada llamada cuando cada uso de la API del repositorio necesite una decisión humana.

Realiza un simulacro de fallos controlado antes de confiar en la creación automatizada de pull requests. Usa un repositorio de prueba o una política de ramas desechable y asigna al agente una tarea que intente cruzar cada límite. El objetivo es verificar las denegaciones y el registro, no admirar una demostración del camino correcto.

Empieza con un repositorio permitido y otro prohibido. Confirma que el controlador puede crear el pull request en borrador esperado en el primero y rechaza el segundo antes de que aparezca ninguna rama. Después intenta hacer push a main, hacer force-push a una rama agent/ y crear un pull request contra una rama de release no aprobada. Inspecciona los eventos del repositorio, no solo los mensajes del controlador.

A continuación, simula un tiempo de espera después de que la solicitud de creación llegue a la API del repositorio. Reinicia la ejecución y confirma que encuentra el pull request original en lugar de abrir otro. Cambia la rama después de registrar los resultados de las pruebas y verifica que la transición a listo se detenga por la discrepancia de SHA.

Por último, revoca la sesión del agente durante una ejecución e intenta otra llamada a la API. La llamada debe fallar, la denegación debe aparecer en el registro de decisiones y no debe mostrarse ninguna credencial en la salida del agente. Si alguna de estas pruebas depende de que una persona vea un mensaje de chat, el control todavía no existe.

La primera acción práctica consiste en inventariar el token que usa hoy tu agente. Enumera cada repositorio que puede tocar, cada rama que puede actualizar y si puede hacer merge o cambiar la configuración. La mayoría de los equipos descubren que el token tiene un alcance mayor que el trabajo. Reduce ese alcance antes de pedir al agente que produzca un pull request más.

FAQ

¿Qué permisos debe tener un agente de IA para abrir pull requests?

El agente debe usar una identidad de bot específica con solo los permisos de repositorio y API necesarios para crear ramas, hacer push en un espacio de nombres permitido y abrir pull requests. No debe recibir permisos de mantenimiento, administración ni merge. El límite de las credenciales importa tanto como el prompt.

¿Deberían los agentes de IA hacer push directamente a la rama main?

Asigna al agente un prefijo de rama como agent/ y rechaza sus pushes en cualquier otro lugar. Protege las ramas predeterminadas y de release para que solo la ruta habitual de merge pueda actualizarlas. Así evitas que el agente eluda la revisión al elegir un destino conveniente.

¿Qué tamaño debe tener un pull request generado por IA?

Un pull request debe contener un único propósito coherente, una diferencia de código acotada y pruebas claras. Si una tarea necesita refactorización no relacionada, actualizaciones de dependencias y un cambio de comportamiento, divídela. La calidad de la revisión cae cuando el revisor tiene que reconstruir varias decisiones a la vez.

¿Cómo asigno revisores a pull requests creados por IA?

Usa las reglas de propiedad del repositorio para la asignación inicial y añade después a una persona responsable cuando los cambios afecten a archivos generados, migraciones, permisos, definiciones de despliegue o código sensible para la seguridad. CODEOWNERS sirve para dirigir las revisiones, pero no sustituye los requisitos de revisión. El revisor obligatorio debe proceder de las reglas de protección de ramas o de merge.

¿Qué debe registrarse cuando un agente crea un pull request?

Registra la sesión del agente, la identidad del actor, el repositorio, el SHA del commit, los nombres de las ramas, los parámetros de la solicitud, la URL del pull request, las marcas de tiempo, los eventos de aprobación y el resultado del merge. Guarda también la referencia de la tarea original y un resumen criptográfico del parche si tus reglas de conservación lo permiten. Un título y una URL no forman un registro de auditoría útil.

¿Es seguro permitir que un agente de IA cree pull requests automáticamente?

Puede ser seguro si el agente no tiene permisos de merge, trabaja únicamente en repositorios permitidos y no puede hacer push en ramas protegidas. Exige revisión humana, comprobaciones correctas y un registro claro de cada acción. Trata al agente como un colaborador no confiable con manos rápidas, no como un mantenedor.

¿Puede un agente de IA abrir pull requests mediante una API?

Usa la API de la plataforma del repositorio para crear la rama desde un commit base explícito, hacer push de los commits y crear el pull request contra una rama base aprobada. Comprueba la respuesta, registra el identificador devuelto y detente si falla alguna solicitud. No extraigas datos de la interfaz web ni deduzcas que todo salió bien a partir de una URL generada.

¿Debe un agente actualizar un pull request existente o crear uno nuevo?

El agente debe proponer un pull request nuevo cuando haya cambiado el resultado previsto, la rama original haya quedado obsoleta o los revisores necesiten tomar una decisión aparte. Solo debe actualizar un pull request existente cuando la tarea y la propiedad sigan siendo las mismas. Reutilizar un pull request para ocultar un alcance nuevo es un fallo de revisión.

¿Cómo evito que un agente cree pull requests duplicados?

Usa datos de idempotencia en tu propio controlador: registra el ID de la tarea, el repositorio, el SHA base, el nombre de la rama y el número del pull request creado antes de reintentar. En cada reintento, busca la rama y el pull request abierto existente antes de crear otro. La mayoría de las API de repositorios aceptan solicitudes repetidas, pero eso no hace que los duplicados sean inofensivos.

¿Las pruebas correctas hacen que los pull requests de IA sean seguros para hacer merge?

No. Una diferencia de código limpia dice poco sobre si el agente eligió el comportamiento correcto, modificó el repositorio adecuado o usó una dependencia aprobada. Las pruebas y las reglas de revisión deben seguir siendo obligatorias, y las personas necesitan suficiente contexto para juzgar el cambio solicitado.

Sallyport

Sallyport ejecuta llamadas de API y comandos SSH por tu agente de IA. Las claves se quedan en una bóveda local de tu Mac; tú apruebas cada ejecución y cada acción queda en un registro sellado.

© 2026 Sallyport · Código abierto bajo Apache-2.0 · Oleg Sotnikov