Módulo 2: Anatomy Of A Github Actions Workflow
5. Actions reutilizables: `uses`, `with`, y el riesgo de la cadena de suministro
Descripción
La lección 2 te mostró uses: actions/checkout@v4 sin detenerse en una pregunta importante: ¿qué es exactamente una "Action"? Esta lección responde eso, y hace algo más: te muestra que actions/checkout@v4 no es una referencia mágica, es una referencia a un tag de Git, un puntero que —a diferencia de un commit— puede moverse. Vas a correr el mismo Action pinneada por SHA exacto en vez de por tag, con act, y vas a entender por qué esa diferencia es una práctica real de seguridad, no un formalismo.
Conexión con el módulo
Esta lección cierra la disección conceptual del módulo (lecciones 2 a 5). Las lecciones 6, 7 y 8 son manos a la obra: vas a usar actions/checkout@v4 de nuevo, ahora como parte del primer workflow real de Andes Cargo. El Módulo 3 introduce una segunda Action con la misma lógica de versionado: hashicorp/setup-terraform@v3.
Analogía: la receta exacta de la página 42, o "la última versión" de un libro que se reedita
Pedir uses: actions/checkout@v4 es como pedirle a alguien "tráeme la receta de sopa de la última edición del libro de cocina" — funciona, casi siempre da el resultado correcto, pero si el autor publica una reedición con una receta corregida bajo la misma etiqueta de "edición actual", tu próxima corrida usa una receta distinta a la de ayer, sin que tú hayas cambiado una sola línea de tu propio archivo. Pedir uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 es pedir, en cambio, "tráeme exactamente la receta de la página 42 de la edición de tal fecha, sin importar qué diga la contratapa hoy" — un puntero que apunta siempre al mismo contenido exacto, para siempre, sin sorpresas.
Qué es una Action
Una Action es código empaquetado y reutilizable —típicamente en JavaScript o como una imagen Docker— publicado en un repositorio de GitHub, listo para usarse desde el campo uses: de cualquier workflow. El GitHub Marketplace es el catálogo público de miles de Actions de este tipo, mantenidas tanto por GitHub mismo (actions/checkout, actions/upload-artifact) como por terceros (hashicorp/setup-terraform, que vas a usar desde el Módulo 3).
La sintaxis general:
- uses: <organización>/<repositorio>@<referencia>
with:
<parámetro-1>: <valor-1>
<parámetro-2>: <valor-2>
<organización>/<repositorio> identifica de qué repositorio de GitHub viene el código; <referencia> es la parte que esta lección diseca —puede ser un tag (v4), una rama (main), o un SHA de commit completo—; with: pasa parámetros de entrada, exactamente como los argumentos de una función.
Tag vs. SHA: el mismo código, dos formas de apuntar a él
Un tag de Git como v4 no es el código en sí — es una etiqueta, un puntero que el mantenedor del repositorio asigna a un commit específico. Ese puntero puede reasignarse: el mismo v4 que hoy apunta al commit 11bd719... podría, técnicamente, apuntar mañana a un commit distinto, si el mantenedor decide mover el tag —algo que la mayoría de los mantenedores serios no hacen para versiones ya publicadas, pero que el mecanismo de Git permite sin ninguna restricción técnica—. Un SHA de commit, en cambio, es una huella digital criptográfica del contenido exacto de ese commit: es matemáticamente imposible que dos commits distintos tengan el mismo SHA completo, y una vez que ese commit existe, su SHA nunca cambia.
Corrí el mismo actions/checkout de dos formas, para confirmarlo con tus propios ojos:
Por tag (la que ya usaste en la lección 2):
- uses: actions/checkout@v4
Por SHA exacto (el mismo v4.2.2, resuelto a su commit real — verificado contra la API de GitHub el día de escribir esta lección):
- name: Check out, pinned to an exact commit SHA
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
with:
fetch-depth: 0
act push -j checkout-by-sha
Qué esperar (salida literal, ejecutada para escribir esta lección):
[sha-pin-demo/checkout-by-sha] ⭐ Run Set up job
[sha-pin-demo/checkout-by-sha] 🚀 Start image=catthehacker/ubuntu:act-latest
[sha-pin-demo/checkout-by-sha] ✅ Success - Set up job
[sha-pin-demo/checkout-by-sha] ⭐ Run Main Check out, pinned to an exact commit SHA
[sha-pin-demo/checkout-by-sha] 🐳 docker cp src=/ruta/a/tu/laboratorio/. dst=/ruta/a/tu/laboratorio
[sha-pin-demo/checkout-by-sha] ✅ Success - Main Check out, pinned to an exact commit SHA [15.767667ms]
[sha-pin-demo/checkout-by-sha] ⭐ Run Main echo "Checked out using a SHA-pinned Action, not a moving tag"
[sha-pin-demo/checkout-by-sha] | Checked out using a SHA-pinned Action, not a moving tag
[sha-pin-demo/checkout-by-sha] ✅ Success - Main echo "Checked out using a SHA-pinned Action, not a moving tag" [52.87675ms]
[sha-pin-demo/checkout-by-sha] 🏁 Job succeeded
Corre exactamente igual — mismo resultado, mismo comportamiento, porque hoy, en este momento, v4 y el SHA 11bd719... apuntan al mismo código exacto. Esa es, precisamente, la naturaleza del riesgo que esta lección nombra: hoy no hay diferencia observable entre los dos — la diferencia solo se manifestaría el día que alguien reasignara el tag v4 a un commit distinto, algo que ninguna corrida de hoy puede demostrarte, por definición. Fijar por SHA no es una mejora de rendimiento ni de funcionalidad — es una garantía sobre el futuro: pase lo que pase con el tag v4 de aquí en adelante, tu workflow sigue usando exactamente este commit, para siempre.
Por qué esto es una práctica de seguridad, no solo de reproducibilidad
Fijar por SHA protege contra dos escenarios reales, documentados en la industria:
- Un mantenedor legítimo comete un error y publica una versión rota bajo un tag existente —raro, pero ocurrido—, rompiendo silenciosamente cada workflow que confiaba en ese tag.
- Un ataque de cadena de suministro: si la cuenta de un mantenedor se ve comprometida, quien tenga acceso puede reasignar un tag público (como
v4) a un commit malicioso, sin que ningún workflow que use@v4note el cambio — la próxima corrida de miles de repositorios ejecutaría código que nadie revisó. Un SHA fijo hace que ese ataque, específicamente, no tenga ningún efecto sobre tu pipeline: seguirías apuntando al commit original, sin importar qué le pase al tag.
Esto es exactamente lo que la auditoría de mercado de este ecosistema señala como el hueco más citado de seguridad —junto al antipatrón de credenciales de larga vida que ves en el Módulo 4—: ningún temario de la competencia menciona pinning por SHA como práctica. Esta guía la nombra aquí, con el mecanismo mostrado y corrido de verdad, no solo mencionado en abstracto.
Lo que esta lección NO construye: un sistema completo de gestión de cadena de suministro —verificación de firmas, SBOM (Software Bill of Materials), escaneo automatizado de dependencias de Actions, herramientas como Dependabot configuradas para actualizar SHAs pinneados automáticamente—. Eso es contenido de cloud-security-and-guardrails-guide, vinculada y no reescrita aquí. Esta lección te deja con el mecanismo (uses: org/repo@SHA en vez de @tag) y el porqué, listo para aplicarlo — la profundidad completa del tema vive en esa guía hermana.
Profundización: hashicorp/setup-terraform@v3, la Action que vas a usar desde el Módulo 3
El Módulo 3 introduce una segunda Action con la misma lógica de versionado, esta vez de HashiCorp:
- uses: hashicorp/setup-terraform@v3
with:
terraform_version: "1.9.5"
Verificado contra la API de GitHub el día de escribir esta lección, el tag v3 de hashicorp/setup-terraform resuelve al SHA b9cd54a3c349d3f38e8881555d616ced269862dd. El mismo principio de esta lección aplica sin cambios: @v3 es más legible y es lo que vas a ver en la mayoría de los ejemplos de la documentación oficial de HashiCorp (por eso esta guía lo usa así en el Módulo 3, priorizando legibilidad pedagógica sobre el máximo endurecimiento posible), pero un equipo con exigencias de seguridad más altas fijaría esa Action, también, por SHA — exactamente con la misma sintaxis que ya practicaste arriba.
Errores comunes
Pensar que fijar por SHA es "más lento" o "peor rendimiento" (conceptual). Qué pasa: alguien evita el pinning por SHA asumiendo que resolver un SHA completo es más costoso que resolver un tag corto como v4. Por qué pasa: un SHA se ve "más largo y complicado" que un tag de tres caracteres. Cómo detectarlo: si tu razón para no fijar por SHA es sobre velocidad, no sobre legibilidad. Cómo corregirlo: como viste en la corrida real de esta lección, no hay ninguna diferencia de rendimiento — Git resuelve ambas referencias (tag o SHA) al mismo commit, con el mismo costo. La única desventaja real del SHA es que es menos legible a simple vista en el YAML —un costo de legibilidad, no de rendimiento.
Fijar por SHA y nunca volver a actualizar la Action (sobrecorrección). Qué pasa: un equipo fija cada Action por SHA, felicitándose por la seguridad ganada, y nunca vuelve a revisar si esas versiones tienen actualizaciones de seguridad propias. Por qué pasa: pinnear se siente como "terminado" — configurado una vez, listo para siempre. Cómo detectarlo: si tu repositorio tiene Actions pinneadas por SHA de hace más de un año, sin ningún proceso que las revise. Cómo corregirlo: pinnear por SHA protege contra cambios no autorizados en un tag existente — no reemplaza el proceso de actualizar deliberadamente cuando existe una versión nueva y necesaria (por ejemplo, un parche de seguridad de la propia Action). Herramientas como Dependabot pueden automatizar ese proceso, abriendo un PR cuando existe un SHA más nuevo para un tag — tema de cloud-security-and-guardrails-guide, nombrado aquí, no construido.
Copiar un SHA de un tutorial sin verificarlo contra el repositorio real (de seguridad, el error que esta lección específicamente evita). Qué pasa: alguien copia un SHA de un artículo de blog o de otra guía sin confirmar que ese SHA corresponde de verdad al tag que dice representar. Por qué pasa: un SHA "se ve" igual de confiable esté verificado o no —cuarenta caracteres hexadecimales no le dicen nada al ojo humano sobre su origen—. Cómo detectarlo: si no puedes explicar de dónde salió un SHA específico en tu workflow. Cómo corregirlo: los dos SHAs de esta lección se verificaron contra la API real de GitHub (api.github.com/repos/<org>/<repo>/git/refs/tags/<tag>) el mismo día en que se escribió esta lección — el mismo mecanismo que deberías usar tú antes de pinnear cualquier Action en un proyecto real, en vez de confiar en un SHA copiado de una fuente que no verificaste.
Ejercicios
Ejercicio 1 — Explica la diferencia a un colega que nunca usó Git más allá de lo básico. Sin usar la palabra "puntero", explica en dos frases por qué un tag de Git puede "cambiar de opinión" sobre a qué commit apunta, y un SHA no.
Ver solución
Una respuesta completa suena, más o menos, así: "Un tag es como una etiqueta con un nombre pegada sobre una caja — alguien puede despegarla y pegarla sobre una caja distinta después, y la etiqueta seguiría diciendo lo mismo aunque el contenido cambió. Un SHA es como el código de barras único, grabado en la caja misma: no se puede despegar ni reasignar, porque es una propiedad matemática del contenido exacto de esa caja, no una etiqueta externa que alguien puso ahí."
Ejercicio 2 — Verifica un SHA tú mismo. Sin mirar esta lección, ¿qué comando o URL usarías para confirmar si el SHA 11bd71901bbe5b1630ceea73d27597364c9af683 de verdad corresponde al tag v4.2.2 de actions/checkout, en vez de confiar en que esta lección lo dice?
Ver solución
La forma más directa es consultar la API pública de GitHub: https://api.github.com/repos/actions/checkout/git/refs/tags/v4.2.2 (con curl o simplemente pegando la URL en un navegador) — la respuesta incluye el campo object.sha, que debería coincidir exactamente con el SHA que estás verificando. Es, literalmente, el mismo comando que se usó para verificar los dos SHAs de esta lección antes de publicarla.
Ejercicio 3 — Decide el nivel de rigor correcto para dos escenarios distintos. Un colega te pregunta si debería fijar por SHA absolutamente todas las Actions de un workflow de práctica personal, sin ningún dato sensible de por medio. ¿Qué le responderías, contrastando ese caso con el de un pipeline que sí despliega infraestructura de producción real?
Ver solución
Una respuesta completa suena, más o menos, así: "Para un workflow de práctica personal, sin credenciales reales ni infraestructura de producción de por medio, usar @v4 es perfectamente razonable — el riesgo real es bajo, y la legibilidad del tag ayuda mientras aprendes. Para un pipeline que sí toca infraestructura de producción, con credenciales reales (aunque sean de corta vida vía OIDC, como ves en el Módulo 4), fijar por SHA cada Action de terceros es una práctica de seguridad seria, exactamente por el escenario de cadena de suministro que nombra esta lección: nadie debería poder cambiar qué código corre en tu pipeline de producción sin que tú lo decidas explícitamente, revisando un nuevo SHA."
Resumen y siguiente paso
En esta lección corriste, con act, el mismo actions/checkout referenciado dos formas distintas —por tag (@v4) y por SHA exacto (@11bd719...)— y confirmaste que ambas corren idéntico hoy, precisamente porque el riesgo del tag no es sobre el presente sino sobre el futuro: un tag puede reasignarse, un SHA no. Viste por qué esto es la práctica de seguridad más citada como ausente en la competencia del mercado que motiva esta guía, con el mecanismo real, verificado contra la API de GitHub, no solo mencionado.
Antes de avanzar deberías poder: explicar la diferencia entre pinnear por tag y por SHA sin usar la palabra "puntero" de forma literal; verificar un SHA tú mismo contra la API de GitHub; y decidir, según el contexto, cuándo el rigor de un SHA vale el costo de legibilidad.
Con la anatomía completa cubierta —on, jobs, steps, runs-on, uses, with, env, y los cuatro disparadores—, las lecciones 6, 7 y 8 son manos a la obra puras. La lección 6 te enseña a simular cualquier evento sin necesitar una cuenta de GitHub real, escribiendo tu propio pr-event.json.
Recursos
- GitHub Docs — Finding and customizing actions — documentación oficial sobre cómo descubrir y usar Actions del Marketplace.
- GitHub Docs — Security hardening for GitHub Actions — la fuente oficial de la recomendación de pinnear Actions de terceros por SHA de commit completo.
- GitHub — actions/checkout — el repositorio real cuyos tags y SHAs se verificaron para esta lección.
- GitHub — hashicorp/setup-terraform — la Action que vas a usar desde el Módulo 3, con el mismo mecanismo de versionado.
cloud-security-and-guardrails-guide(NIEVA) — supply chain a fondo: SBOM, firma de commits, Dependabot, escaneo automatizado — no construido aquí, solo nombrado.