git verify-tag para coding agents: ningún release sin firma válida
Resumen
git verify-tag valida la firma GPG de un tag anotado sin mover HEAD ni tocar el working tree. Solo opera sobre tag objects: un tag liviano o sin firma falla con exit distinto de cero. Con -v, --raw y --format controlas el detalle del reporte. Cero construir releases sobre tags no verificados, cero confundir un tag liviano con un release firmado y cero volcar el reporte crudo al contexto del agente. Git 2.50.1.

Qué resuelve
Esta pieza se queda en la decisión práctica: qué instalar, qué riesgo agrega y cómo aplicarlo sin romper operación.
git verify-tag valida la firma GPG creada por git tag en los tag objects que le pasas, sin mover HEAD, sin tocar el índice y sin tocar el working tree. El man (git-verify-tag(1); git-scm.com/docs/git-verify-tag; man local Git 2.54.0, 2026-04-19; binario Git 2.50.1 / Apple Git-155): Validates the gpg signature created by git tag in the tag objects listed on the command line. SYNOPSIS: git verify-tag [-v | --verbose] [--format=<format>] [--raw] <tag>....
Es la compuerta de release del plumbing: antes de que un agente construya, despliegue o empaquete a partir de un tag que otro agente (o humano) dejó en el repo, verifica que ese tag lo firmó quien dice haberlo firmado. Lectura pura, cero efectos.
No es verify-commit. verify-commit valida la firma de un commit (git commit -S); verify-tag valida la firma de un tag anotado (git tag -s). Son complementos: el commit dice quién escribió el cambio, el tag dice quién autorizó el release. Verificar uno no verifica el otro.
Tampoco es tag. tag crea y lista; verify-tag solo valida y responde con exit code. Ni es describe: describe encuentra el tag anotado más cercano para nombrar un commit; verify-tag comprueba que ese tag sea auténtico. Ni es show: show imprime el objeto para inspeccionarlo; verify-tag lo valida. En todos rige la misma higiene: cero volcar la salida cruda al contexto del LLM.
Contrato: git verify-tag <tag>. Exit code 0 = firma válida. Solo tag objects: liviano o sin firma = fallo. Cero construir sobre tags no verificados. Cero confundir "existe el tag" con "el tag es auténtico".
La regla de oro: solo tag objects
verify-tag solo sabe validar tag objects, es decir, tags anotados (y firmados). Todo lo demás falla con exit distinto de cero. Comportamiento verificado en local (Git 2.50.1):
| Lo que le pasas | Resultado | Exit |
|---|---|---|
| Tag anotado firmado, firma válida | Firma válida | 0 |
| Tag anotado sin firmar | error: no signature found | 1 |
| Tag liviano (apunta directo a un commit) | error: <tag>: cannot verify a non-tag object of type commit. | 1 |
| Ref que no existe | error: tag '<tag>' not found. | 1 |
Tres consecuencias prácticas para un agente:
- Un tag liviano nunca es un release verificable. Si tu flujo de release acepta tags livianos, la compuerta de firma no existe. Estandariza
git tag -s(o-u <key-id>) para releases y deja los livianos para marcadores locales desechables. no signature foundno es "tag malo", es "tag sin firmar". Distingue el caso: un tag anotado sin firma puede ser legítimo en repos que no firman; la política (exigir firma o no) la pone tu compuerta, no git.- Verifica el nombre exacto que vas a consumir. Un typo no da un falso positivo: da
tag not foundy exit 1. El contrato es fail-closed.
Opciones: -v, --raw, --format

El SYNOPSIS completo es git verify-tag [-v | --verbose] [--format=<format>] [--raw] <tag>.... Nótese el ...: acepta varios tags en una invocación y los valida uno por uno. Si cualquiera falla, el exit es distinto de cero.
-v, --verbose: imprime el contenido del tag object antes de validarlo. Útil para depurar a mano (ves tagger, fecha y mensaje junto al resultado). Para un agente, úsalo solo en diagnóstico: en el camino feliz, el exit code basta.--raw: imprime el estado GPG crudo a standard error en vez de la salida legible. Ojo al detalle: va a stderr, no a stdout. Si tu harness captura solo stdout, el reporte crudo se pierde (o contamina logs). Y nunca lo pegues al prompt: es GPG crudo, ruido caro para el contexto.--format=<format>: formatea la salida con placeholders del tag. Sirve para reportes máquina-legibles (tagger + fecha en una línea) sin parsear texto humano.
Regla de contexto para agentes: el exit code es el contrato; el texto es solo para humanos depurando. Un if git verify-tag "$TAG" decide; nada del stdout/stderr necesita entrar al prompt.
Receta: compuerta de release para un agente

Así se ve la compuerta mínima antes de construir un release desde un tag:
TAG="v2.4.0"
git fetch origin "refs/tags/${TAG}:refs/tags/${TAG}"
if git verify-tag "$TAG" 2>/dev/null; then
echo "firma válida, construyendo release"
else
echo "tag no verificado, alto" >&2
exit 1
fi
Notas de la receta:
- El fetch trae el tag exacto del remoto; verificar un tag local desactualizado es verificar el release equivocado.
2>/dev/nulldescarta el reporte humano; la decisión vive en el exit code.- El
exit 1es fail-closed: sin firma válida no hay build, no hay deploy, no hay excepción silenciosa. - Si tu política exige además que el commit esté firmado, encadena verify-commit sobre el SHA al que apunta el tag. Tag válido + commit válido = procedencia completa.
Checklist
- Los releases usan tags anotados firmados (
git tag -s), nunca livianos. - La compuerta corre
git verify-tag <tag>y decide por exit code, no por parsear texto. - El tag se trae del remoto (
fetch refs/tags/...) antes de verificar. -
--rawy-vsolo en diagnóstico humano; jamás al contexto del LLM. -
no signature foundynon-tag objectse tratan como fallo fail-closed, no como warnings. - Si la política lo exige, se verifica también el commit con verify-commit.
FAQ
¿verify-tag verifica también el commit al que apunta el tag? No. Valida la firma del tag object. El commit apuntado puede no estar firmado. Para procedencia completa, verifica ambos: tag con verify-tag y commit con verify-commit.
¿Un tag liviano firmado existe?
No hay tal cosa: la firma vive en el tag object y el tag liviano no crea objeto, es solo una ref a un commit. Por eso verify-tag responde cannot verify a non-tag object of type commit. Si necesitas firmarlo, conviértelo en anotado.
¿Por qué --raw va a stderr?
Diseño de git: la salida legible y la cruda son reportes para humanos, no datos. Tu harness debe decidir por exit code; si necesitas el detalle máquina-legible, usa --format.
¿Puedo verificar varios tags a la vez?
Sí: git verify-tag v1 v2 v3 los valida en orden. Basta un fallo para exit distinto de cero. Para reportes por tag individual, prefiera un loop que registre cuál falló.
¿Firma válida significa firmante confiable? No. Significa que el tag lo firmó alguien con esa key. La confianza (¿esa key pertenece a quien debe autorizar releases?) la pone tu política: restringe qué key-ids acepta la compuerta y rota las comprometidas.
Lecturas relacionadas
Sigue explorando Coding Agents y otras piezas para builders.

git maintenance para coding agents: housekeeping programado, no gc a pelo

git credential para coding agents: helpers, no tokens en el prompt

git rerere para coding agents: el mismo conflicto no se resuelve dos veces
