·4 min de lectura·Mounaji Studio

En un deploy, la identidad que importa es la del autor del commit

En Vercel, el permiso para publicar viaja con el commit, no con quien corre el comando. Cómo se ve un deploy BLOCKED por asiento, por qué la CLI lo muestra como UNKNOWN, dónde está la causa en la API y las dos salidas que hay.

engineeringdeploywebvendear

También en: English

Cuando piensas en quién tiene permiso para publicar un sitio, lo natural es pensar en la persona que aprieta el botón: la cuenta que corre vercel --prod o la integración que reacciona al push. En Vercel hay otra identidad que pesa tanto o más, y es la que menos se mira: el autor del commit.

Lo aprendimos en vendear, nuestro sitio de vidrieras con vendedor con IA. El proyecto de Vercel está en un equipo del plan Hobby con un solo miembro, la cuenta dueña. Un colaborador que no es miembro de ese equipo firmó dos commits en main, y los dos deployments que dispararon quedaron en estado BLOCKED. El código estaba bien, la cuenta estaba activa y el deploy lo intentaba la cuenta dueña. Lo que no tenía asiento era el autor.

Cómo funciona el chequeo

El mismo árbol, desplegado por la misma cuenta dueña: si el autor del último commit tiene asiento en el equipo, el deployment queda READY; si no, queda BLOCKED con TEAM_ACCESS_REQUIRED y la CLI lo muestra como UNKNOWN

Antes de construir, Vercel compara la identidad de git del commit con los miembros del equipo. Si el autor no está, el deployment no llega a construirse: queda BLOCKED y la causa se guarda en el propio deployment:

curl -s -H "Authorization: Bearer $VERCEL_TOKEN" \
  "https://api.vercel.com/v13/deployments/<id>?teamId=<team>" \
  | jq '{readyState, readyStateReason, seatBlock}'

En nuestro caso, seatBlock.blockCode era TEAM_ACCESS_REQUIRED.

Esto explica por qué el sitio llevaba semanas publicándose solo con cada push a main sin problemas: todos esos commits los había firmado la cuenta dueña. El chequeo no es nuevo ni intermitente. Simplemente no tiene nada que decir hasta que firma alguien de afuera.

Lo que muestra cada herramienta

Este es el detalle que hace caro el problema. El estado real existe, pero no todas las herramientas lo muestran:

Herramienta Qué muestra
vercel ls UNKNOWN, que se lee como "viejo", no como "falló"
vercel inspect <url> status UNKNOWN, sin una línea de causa
GET /v13/deployments/<id> BLOCKED, con readyStateReason y seatBlock
El dominio 200, sirviendo el deploy anterior

El sitio respondía bien, el repo estaba al día y la CLI no marcaba ningún error. Lo único distinto era que producción servía un commit de tres días antes, y eso sólo se ve si le preguntas al sitio qué versión sirve (para eso tenemos un endpoint de versión).

Lo que no lo destraba

Tres caminos parecen razonables y ninguno sirve, porque los tres conservan al mismo autor:

  • Esperar. Un BLOCKED se parece a un tope de uso del plan, algo que se resuelve solo. No lo es: un deploy nuevo lanzado días después quedó bloqueado en el mismo segundo, con la cuenta activa y sin problemas de facturación. Si lo que parece un cupo no se mueve con el tiempo, mira el permiso.
  • Publicar a mano desde el disco. El deployment lo crea la cuenta dueña, pero la CLI adjunta los metadatos de git de la carpeta local, incluido el autor del último commit (githubCommitAuthorName), y el chequeo corre sobre ellos.
  • vercel redeploy. Un deployment bloqueado responde 400: no se puede redesplegar y pide un commit nuevo.

Las dos salidas

  1. Darle asiento al autor. Es lo correcto si esa persona va a firmar commits seguido. En el plan Hobby no se pueden sumar miembros, así que implica pasar el equipo a Pro.

  2. Que el commit que llega a la rama de producción lo firme alguien con asiento. Para destrabar el caso alcanzó un commit vacío en main, firmado por la cuenta dueña:

    git commit --allow-empty -m "deploy: republicar main"
    git push origin main
    

    La integración construyó el mismo árbol y el deployment quedó READY. A futuro, la misma regla aplica a los merges: si los cierra la cuenta dueña con squash o rebase, el commit que llega a main lleva su autoría.

La segunda salida destraba hoy, pero no cambia el mecanismo: el siguiente commit de alguien sin asiento que quede arriba en main va a frenar igual.

La idea que conviene llevarse

En un pipeline solemos pensar el permiso como algo de la sesión: quién está logueado, qué token usa el CI. Acá el permiso viaja con el código. El mismo árbol, desplegado por la misma cuenta, se publica o no según el nombre que quedó escrito en el commit.

Por eso, cuando un deploy se frena sin un error claro, la primera pregunta no es "¿quién lo lanzó?", sino "¿quién firmó lo que está arriba en la rama?". Y la segunda, que lo detecta antes de que te lo diga un cliente, es "¿qué commit está sirviendo producción?":

curl -s https://www.vendear.com/api/version

Comentarios y correcciones

Chat with us