Módulo 6: Supply Chain Sbom And Signing
8. Proyecto: el paquete de cadena de suministro de Andes Cargo
Descripción
Las lecciones 2 a 7 construyeron cuatro piezas por separado: un SBOM (lecciones 2-3), un keypair local (lecciones 4-5), una firma verificada (lección 6), y la prueba de que esa verificación de verdad detecta manipulación (lección 7). Este proyecto final las integra en lo que de verdad son desde el primer momento en que un pipeline las use: un paquete de cadena de suministro, con un job nuevo —verify-artifact— agregado al apply.yml heredado de cicd-and-gitops-on-aws-guide, corrido con act de punta a punta. Lo corres dos veces: una con el artefacto correcto (el gate deja pasar), otra con el artefacto alterado (el gate detiene todo antes de que terraform-apply siquiera empiece).
Conexión con el módulo
Este es el cierre del módulo, y el mismo ejercicio de evidencia ejecutada que cada proyecto de esta guía practica desde el Módulo 1: no "¿generaste un SBOM y una firma?", sino "¿puedes demostrar, con un pipeline corrido de verdad, que un artefacto sin firma válida nunca llega a apply?". RISK-MAP.md cierra aquí su fila TM-02 — la única de la categoría Tampering de todo THREAT-MODEL.md.
Paso 1 — El paquete completo, los cuatro archivos
ls -la sbom.cyclonedx.json cosign.pub manifest.sig lambda/function.zip
Qué esperar (literal — los tamaños de sbom.cyclonedx.json/manifest.sig pueden variar unos bytes según metadatos como el timestamp, ya marcados variables desde la lección 3; function.zip es literal):
-rw-r--r-- 4388 sbom.cyclonedx.json
-rw-r--r-- 178 cosign.pub
-rw-r--r-- ~330 manifest.sig
-rw-r--r-- 890 lambda/function.zip
Cuatro archivos, cuatro roles distintos y complementarios: sbom.cyclonedx.json es el inventario (qué hay adentro del proyecto, incluidas las dependencias transitivas de la lección 3); cosign.pub es la llave pública, la única pieza que un tercero necesita para verificar cualquier firma tuya; manifest.sig es la firma sobre el artefacto exacto; lambda/function.zip es el artefacto que las tres piezas anteriores describen y protegen, sin ser, él mismo, nuevo de este módulo — es el mismo .zip que terraform-and-iac-guide generó. cosign.key, deliberadamente, no aparece en esta lista: sigue existiendo en tu disco local (.gitignore lo excluye desde la lección 5), pero nunca es parte de lo que se distribuye ni de lo que un pipeline necesita para verificar —solo para firmar, un paso que ya ocurrió, a mano, en la lección 6—.
Paso 2 — Extendiendo apply.yml: el job verify-artifact
.github/workflows/apply.yml, heredado de cicd-and-gitops-on-aws-guide (Módulo 5, lección 4), gana un job nuevo, en paralelo con fetch-reviewed-plan, y terraform-apply gana una segunda dependencia:
name: apply
on:
push:
branches: [main]
jobs:
fetch-reviewed-plan:
runs-on: ubuntu-latest
steps:
- name: Download the plan reviewed in the pull request
uses: actions/download-artifact@v4
with:
name: terraform-plan
- name: Confirm the plan file arrived intact
run: |
test -s tfplan
echo "tfplan is present: $(wc -c < tfplan) bytes"
verify-artifact:
runs-on: ubuntu-latest
steps:
- name: Check out andes-cargo-infra
uses: actions/checkout@v4
- name: Install envsubst (required by the cosign installer, missing on act's runner image)
run: apt-get update -qq && apt-get install -y -qq gettext-base
- name: Install cosign
uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6
- name: Verify function.zip against manifest.sig
run: |
cosign verify-blob \
--key cosign.pub \
--bundle manifest.sig \
--insecure-ignore-tlog=true \
lambda/function.zip
terraform-apply:
needs: [fetch-reviewed-plan, verify-artifact]
runs-on: ubuntu-latest
env:
AWS_ACCESS_KEY_ID: test
AWS_SECRET_ACCESS_KEY: test
AWS_DEFAULT_REGION: us-east-1
AWS_ENDPOINT_URL: http://host.docker.internal:4566
steps:
- name: Check out andes-cargo-infra
uses: actions/checkout@v4
- name: Set up Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: "1.15.8"
- name: Download the plan reviewed in the pull request
uses: actions/download-artifact@v4
with:
name: terraform-plan
- name: Terraform init
run: terraform init -input=false
- name: Install tflocal
run: pip3 install --quiet --break-system-packages terraform-local
- name: Terraform apply
run: tflocal apply -input=false -auto-approve tfplan
Tres cambios, y cada uno merece explicarse:
Primero, el job verify-artifact en sí — cuatro steps, en orden: descargar el código (donde viven cosign.pub, manifest.sig, y lambda/function.zip, los tres commiteados desde las lecciones anteriores), instalar una dependencia del runner que falta (el próximo párrafo lo explica), instalar cosign, y correr exactamente el mismo cosign verify-blob que ejecutaste a mano en la lección 6 — sin ningún cambio en el comando, solo dentro de un job de pipeline en vez de tu terminal.
Segundo, un step que ninguna lección anterior de este módulo necesitó: instalar envsubst. Al integrar sigstore/cosign-installer dentro de act por primera vez, esta guía encontró —y documenta, en vez de esconder— una incompatibilidad real entre la imagen de runner medium que .actrc usa desde cicd-and-gitops-on-aws-guide (catthehacker/ubuntu:act-latest) y esa Action: el script interno de cosign-installer depende de envsubst (parte del paquete gettext-base de Ubuntu) para resolver una ruta de instalación configurable, y esa imagen medium —diseñada para ser liviana, no para replicar cada herramienta de un runner real de GitHub— no la incluye por defecto, a diferencia de los runners reales de GitHub, que sí la traen preinstalada. Sin este step, el job falla con envsubst: command not found — un fallo de infraestructura del laboratorio, no de la lógica de este módulo, y por eso se corrige con una línea, no se esconde.
Tercero, needs: [fetch-reviewed-plan, verify-artifact] — antes, terraform-apply solo dependía de fetch-reviewed-plan (Módulo 5 de cicd-and-gitops-on-aws-guide). Ahora depende de ambos: el mecanismo de needs: con una lista, que ya conoces desde ese módulo, exige que todos los jobs listados terminen con éxito antes de que terraform-apply siquiera empiece a correr — no que al menos uno lo haga. Es, literalmente, el candado de este proyecto: si verify-artifact falla, terraform-apply nunca se ejecuta, sin importar que fetch-reviewed-plan haya salido perfecto.
Nota sobre el pinning por SHA, retomando la lección 1: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 no está fijado por tag (@v4) — está fijado por el SHA de commit completo correspondiente al tag v4.1.2, verificado contra la API pública de GitHub el mismo día en que se escribió esta lección (api.github.com/repos/sigstore/cosign-installer/tags). Es exactamente la práctica que cicd-and-gitops-on-aws-guide (Módulo 2, lección 5) nombró como el pilar de seguridad de cadena de suministro que le delegó a esta guía: cada Action de terceros que este módulo agrega al pipeline heredado está pinneada por SHA, no por tag móvil.
Paso 3 — Corriendo el gate con el artefacto correcto
act push -j verify-artifact -W .github/workflows/apply.yml
Qué esperar (salida literal, ejecutada para escribir esta lección — filtrada de las advertencias repetidas de act sobre que este directorio de laboratorio no es un repositorio Git, irrelevantes para el resultado):
[apply/verify-artifact] ⭐ Run Set up job
[apply/verify-artifact] 🚀 Start image=catthehacker/ubuntu:act-latest
[apply/verify-artifact] ✅ Success - Set up job
[apply/verify-artifact] ⭐ Run Main Check out andes-cargo-infra
[apply/verify-artifact] ✅ Success - Main Check out andes-cargo-infra [11.675375ms]
[apply/verify-artifact] ⭐ Run Main Install envsubst (required by the cosign installer, missing on act's runner image)
[apply/verify-artifact] | Setting up gettext-base (0.21-14ubuntu2) ...
[apply/verify-artifact] ✅ Success - Main Install envsubst (required by the cosign installer, missing on act's runner image) [6.576651834s]
[apply/verify-artifact] ⭐ Run Main Install cosign
[apply/verify-artifact] | INFO: Downloading bootstrap version 'v3.0.6' of cosign to verify version to be installed...
[apply/verify-artifact] | INFO: bootstrap version successfully verified and matches requested version so nothing else to do
[apply/verify-artifact] ✅ Success - Main Install cosign [4.038418125s]
[apply/verify-artifact] ⭐ Run Main Verify function.zip against manifest.sig
[apply/verify-artifact] | WARNING: Skipping tlog verification is an insecure practice that lacks transparency and auditability verification for the blob.
[apply/verify-artifact] | Verified OK
[apply/verify-artifact] ✅ Success - Main Verify function.zip against manifest.sig [74.244958ms]
[apply/verify-artifact] ⭐ Run Complete job
[apply/verify-artifact] ✅ Success - Complete job
[apply/verify-artifact] 🏁 Job succeeded
Job succeeded — y, en el centro de la salida, exactamente el mismo Verified OK que ya viste en la lección 6, ahora corriendo dentro de un contenedor Docker efímero, instalado desde cero en cada corrida, con el mismo resultado. Esto es, en sí mismo, una segunda confirmación de la firma —no solo funciona en tu máquina con el cosign que instalaste a mano en la lección 5, funciona igual en un entorno de ejecución completamente distinto (catthehacker/ubuntu:act-latest, un contenedor Ubuntu limpio), con una instalación de cosign distinta (v3.0.6, la versión bootstrap que el propio instalador usa para verificarse a sí mismo, según muestra el log) — la firma no depende de ningún detalle específico de tu entorno de desarrollo.
Paso 4 — Corriendo el gate con el artefacto alterado: el apply no llega a existir
Repite el experimento de la lección 7, pero esta vez dentro del pipeline completo, no solo con cosign a mano. Sustituye temporalmente lambda/function.zip por una versión alterada (un byte extra, exactamente como en la lección 7) y corre el workflow completo, sin acotarlo a un solo job:
cp lambda/function.zip.tampered lambda/function.zip # simula la manipulación de la lección 7
act push -W .github/workflows/apply.yml
Qué esperar (salida literal, ejecutada para escribir esta lección — resumida a las líneas que muestran el resultado de cada job):
[apply/fetch-reviewed-plan] ❗ ::error::Unable to download artifact(s): Unable to get the ACTIONS_RUNTIME_TOKEN env variable
[apply/fetch-reviewed-plan] 🏁 Job failed
[apply/verify-artifact ] ⭐ Run Main Verify function.zip against manifest.sig
[apply/verify-artifact ] | Error: failed to verify signature: could not verify message: invalid signature when validating ASN.1 encoded signature
[apply/verify-artifact ] ❌ Failure - Main Verify function.zip against manifest.sig [72.758625ms]
[apply/verify-artifact ] 🏁 Job failed
Error: Job 'verify-artifact' failed
Ningún renglón de terraform-apply aparece en absoluto en esta salida. No falló — nunca llegó a correr. needs: [fetch-reviewed-plan, verify-artifact] significa que Stage 1 (terraform-apply) solo se activa después de que ambos jobs de Stage 0 terminen con éxito, y aquí los dos fallan: verify-artifact por la razón que este módulo entero existe (la firma no coincide con el artefacto alterado), y fetch-reviewed-plan por una razón completamente distinta y ya conocida de cicd-and-gitops-on-aws-guide —esta corrida específica no incluyó los flags --artifact-server-path/--artifact-server-addr con un ci.yml previo que hubiera subido un tfplan real, así que no hay ningún artefacto terraform-plan que descargar—. Sepáralas con cuidado: la lección de este proyecto es sobre la segunda falla (verify-artifact), no sobre la primera, que es simplemente el estado esperado de no haber corrido primero el ci.yml completo en esta sesión de laboratorio.
Restaura el artefacto correcto antes de seguir:
git checkout -- lambda/function.zip # o: cosign verify-blob confirma "Verified OK" de nuevo tras restaurar
Cómo defender este trabajo en una entrevista
Un entrevistador técnico que revise este proyecto no necesita que recites la especificación de CycloneDX o el algoritmo ECDSA de memoria. Necesita que puedas responder, sin dudar, tres tipos de pregunta:
-
"¿Por qué SBOM y firma, y no solo una de las dos?" — la respuesta vive en la lección 2: un SBOM sin firma te dice qué hay adentro de un paquete, pero no si el paquete es el que tu equipo realmente produjo; una firma sin SBOM confirma que el paquete no cambió, pero no qué contiene. Este módulo construye las dos porque responden preguntas complementarias, no la misma pregunta dos veces.
-
"¿Por qué keypair local y no keyless, si Sigstore ofrece las dos opciones?" — la respuesta vive en la lección 4, y tiene tres partes concretas: el mismo límite de validación real de OIDC que el Módulo 2 ya documentó en LocalStack Hobby, la necesidad de que todo corra $0 sin depender de una conexión de red a servicios públicos, y la confirmación de que un keypair local sigue siendo Sigstore real, no una versión reducida. Un entrevistador de un equipo con GitHub Actions y AWS reales entendería, además, que en su contexto keyless probablemente sería la elección correcta — la respuesta demuestra que sabes cuándo cada mecanismo aplica, no que memorizaste "keypair es mejor".
-
"¿Cómo sabes que esto funciona, no solo que existe?" — la respuesta es este proyecto completo: la lección 7 rompió la firma a propósito y la vio fallar con un mensaje explícito; este proyecto corrió el gate completo dos veces, una con el artefacto correcto (
Job succeeded,terraform-applysí se hubiera activado) y una con el alterado (Job failed,terraform-applynunca se ejecutó) — nunca "debería bloquear un artefacto sin firmar", siempre "corrió, y esto fue lo que pasó, con el log completo como evidencia".
Actualizando RISK-MAP.md: la sexta fila cerrada
Con TM-02 marcada Resolved, RISK-MAP.md queda con seis de siete filas cerradas al cierre de este módulo — solo TM-03 (CloudTrail, Módulo 7) sigue abierta:
| Order | ID | Control | Status |
|---|---|---|---|
| 1 | TM-01 | OIDC federation + scoped trust policy | Resolved (M2) |
| 2 | TM-07 | Least-privilege role tightening | Resolved (M2.7) |
| 3 | TM-05 | SSM Parameter Store / Secrets Manager | Resolved (M3) |
| 4 | TM-04 | no-public-buckets.rego | Resolved (M4.7) |
| 5 | TM-06 | no-destroy-shipments.rego | Resolved (M4.6) |
| 6 | TM-02 | SBOM + cosign sign-blob/verify-blob | Resolved (M6.6, verificado en pipeline en M6.8) |
| 7 | TM-03 | CloudTrail | Open (Módulo 7) |
La nota de evidencia para esta fila, siguiendo la misma disciplina que RISK-MAP.md exige desde el Módulo 1 —nunca solo la palabra "Resolved" sin más—: "lambda/function.zip firmado con cosign sign-blob (keypair local, offline) en M6.6; verificación confirmada Verified OK contra el artefacto correcto y Error: invalid signature contra uno alterado a propósito en M6.7; ambos resultados reproducidos dentro de un job verify-artifact real de apply.yml, corrido con act push, en M6.8 — terraform-apply queda gateado por needs: a que esta verificación pase."
El proyecto completo, en un vistazo
andes-cargo-infra/
├── THREAT-MODEL.md (M1)
├── RISK-MAP.md (M1 → 6/7 filas Resolved al cierre de M6)
├── secrets.tf (M3)
├── policy/ (M4)
├── modules/
│ ├── s3-bucket/
│ ├── iam-role/
│ └── oidc-provider/ (M2)
├── lambda/
│ ├── handler.py (heredado, 1801 bytes)
│ ├── function.zip (heredado, 890 bytes — EL artefacto que este módulo protege)
│ └── requirements.txt (M6.3 — boto3 + 6 dependencias transitivas resueltas)
├── sbom.cyclonedx.json (M6.3 — 8 componentes)
├── cosign.pub (M6.5 — committeado)
├── cosign.key (M6.5 — gitignorado, NUNCA versionado)
├── manifest.sig (M6.6 — la firma, offline, sin Rekor)
└── .github/workflows/
└── apply.yml ← extendido con verify-artifact (M6.8)
Errores comunes
Interpretar fetch-reviewed-plan fallando en el Paso 4 como parte de la lección de este módulo (de atribución, el más importante de este proyecto). Qué pasa: alguien, viendo dos jobs fallar a la vez en el Paso 4, concluye que este módulo también resolvió algo sobre la descarga de artefactos entre ci.yml y apply.yml. Cómo detectarlo: si tu explicación de la salida del Paso 4 menciona ACTIONS_RUNTIME_TOKEN como parte de la tesis de este módulo. Cómo corregirlo: esa falla es plumbing heredado, sin cambios, de cicd-and-gitops-on-aws-guide — ocurre en este proyecto solo porque el Paso 4 no corrió primero un ci.yml con --artifact-server-path/--artifact-server-addr para producir un tfplan real que descargar, un paso fuera del alcance de este módulo. La lección de este proyecto, específicamente, es la de verify-artifact: esa falla sí es nueva, sí es intencional, y sí es la que este módulo entero construyó.
Dejar lambda/function.zip en su estado alterado después del Paso 4, sin restaurarlo (de higiene del proyecto, revisita el patrón del Módulo 4). Qué pasa: alguien termina el Paso 4, ve el Job failed esperado, y sigue adelante sin restaurar el artefacto original. Cómo detectarlo: si cosign verify-blob --key cosign.pub --bundle manifest.sig --insecure-ignore-tlog=true lambda/function.zip sigue fallando después de que pensabas haber terminado este proyecto. Cómo corregirlo: cada lección de este módulo que introdujo un cambio de prueba (la 7, y este proyecto) revirtió ese cambio explícitamente antes de declarar el paso completo — el estado final de andes-cargo-infra/ al cierre de este proyecto es el correcto, con Verified OK confirmado, no el estado intermedio de la demostración de falla.
Asumir que agregar envsubst como step es un parche permanente que cualquier Action de terceros va a necesitar (de generalización, sobre un caso específico de esta Action). Qué pasa: alguien, después de resolver el problema de envsubst para sigstore/cosign-installer, asume que cualquier Action nueva que agregue a un workflow bajo act va a necesitar el mismo tipo de step preventivo. Cómo detectarlo: si empiezas a agregar instalaciones de herramientas "por si acaso" antes de siquiera probar una Action nueva bajo act. Cómo corregirlo: el problema de esta lección es específico de una dependencia interna concreta de sigstore/cosign-installer (su script de instalación usa envsubst) combinada con una limitación específica de la imagen medium de act (no lo incluye por defecto). Otras Actions pueden depender de herramientas completamente distintas, o de ninguna adicional. La forma correcta de proceder, cada vez, es correr la Action nueva bajo act primero, leer el error real si aparece uno, y resolver la causa específica — exactamente el proceso que produjo el step de esta lección, no una superstición aplicada por adelantado.
Ejercicios
Ejercicio 1 — Reconstruye, de memoria, la cadena completa de needs: de apply.yml después de este módulo. Sin mirar el YAML de esta lección, dibuja (en texto) qué jobs existen, cuáles corren en Stage 0, cuál en Stage 1, y de qué depende ese último.
Ver solución
Stage 0 (sin needs:, corren en paralelo): fetch-reviewed-plan y verify-artifact. Stage 1 (needs: [fetch-reviewed-plan, verify-artifact]): terraform-apply, que solo se activa si ambos jobs de Stage 0 terminan con éxito. Antes de este módulo, terraform-apply solo dependía de fetch-reviewed-plan (heredado de cicd-and-gitops-on-aws-guide); este proyecto agregó verify-artifact como una segunda condición obligatoria, no como una alternativa — las dos tienen que pasar, no basta con una de las dos.
Ejercicio 2 — Explica por qué el gate de este módulo corre en Stage 0, junto a fetch-reviewed-plan, y no como un paso dentro del propio job terraform-apply. Un compañero propone simplificar el workflow moviendo el cosign verify-blob a un step más, dentro de terraform-apply, antes del tflocal apply. ¿Qué perderías con ese cambio?
Ver solución
Perderías la posibilidad de que verify-artifact corra en paralelo con fetch-reviewed-plan (más rápido, en un pipeline con jobs que sí tardan minutos reales) y, más importante, perderías la claridad de que la verificación es un gate independiente, con su propio resultado visible en la interfaz de GitHub Actions (un job separado, con su propio ícono de éxito/fallo), no un paso escondido dentro de otro job con un propósito distinto. Moverlo adentro de terraform-apply seguiría bloqueando el apply en la práctica (set -e haría que el job entero fallara si cosign verify-blob fallara), pero perdería la separación de responsabilidades: terraform-apply dejaría de ser "el job que aplica infraestructura" para convertirse en "el job que aplica infraestructura y también verifica firmas", una mezcla de propósitos que dificulta, con el tiempo, saber de un vistazo cuál de las dos cosas falló.
Ejercicio 3 — Defiende, frente a una objeción concreta, por qué este módulo firma el .zip de despliegue y no, en cambio, cada commit individual del repositorio con git commit -S. Un colega con experiencia en Git pregunta por qué esta guía no usa la firma de commits nativa de Git (git commit -S, verificable con GPG o el propio soporte de firma de Git con SSH/cosign desde versiones recientes) en vez de firmar el artefacto de despliegue por separado. ¿Cómo responderías?
Ver solución
Una respuesta completa distingue qué garantiza cada mecanismo. Firmar commits confirma que un commit específico, en el historial de Git, fue creado por quien dice haberlo creado — una garantía valiosa sobre la autoría del código fuente, pero que no dice nada sobre el artefacto de despliegue que un pipeline construye después: entre el commit firmado y el .zip final hay pasos —checkout, empaquetado con archive_file, y en un proyecto más complejo, quizás instalación de dependencias o un paso de build— que un commit firmado no cubre en absoluto. Un atacante que comprometiera el propio proceso de construcción (el runner de CI, por ejemplo) podría producir un .zip malicioso a partir de un commit perfectamente legítimo y firmado, sin que la firma del commit lo detectara. Firmar el artefacto de despliegue, como hace este módulo, cierra exactamente esa brecha: garantiza que el .zip que Lambda va a ejecutar es, byte por byte, el que salió del proceso de construcción en el momento en que se firmó — una garantía distinta y complementaria a la firma de commits, no un sustituto de ella. Un sistema de cadena de suministro maduro, en un proyecto real, probablemente usaría ambas capas, no solo una.
Resumen y siguiente paso
En este proyecto integraste las cuatro piezas de este módulo —SBOM, keypair, firma, verificación probada contra manipulación— en un job verify-artifact real dentro de apply.yml, y corriste el pipeline completo dos veces con act: una con el artefacto correcto (Job succeeded, el mismo Verified OK de la lección 6 confirmado dentro de un contenedor efímero), y una con el artefacto alterado (Job failed, y terraform-apply nunca llegó a ejecutarse, gateado por needs:). Documentaste, sin esconderla, una incompatibilidad real entre la imagen de runner de act y la Action oficial de instalación de cosign —y la resolviste con una línea, no con un atajo—. Cerraste TM-02 de RISK-MAP.md, dejando el documento con seis de siete filas resueltas.
Antes de cerrar este módulo deberías poder: correr cosign sign-blob/verify-blob desde cero, sin mirar ninguna lección anterior; explicar, con las tres preguntas de entrevista de esta lección, por qué SBOM y firma son complementarios, por qué esta guía eligió keypair sobre keyless, y cómo demostrarías —con evidencia ejecutada, no una promesa— que la verificación de verdad funciona; y defender, frente a la objeción de un colega, por qué firmar el artefacto de despliegue es una capa distinta y necesaria frente a firmar commits de Git.
Con esto, el Módulo 6 de cloud-security-and-guardrails-guide queda completo: el hueco de mercado que VALIDACION.md marcó como "cero" en toda la competencia —SBOM, cosign/Sigstore, y el escaneo del Módulo 5— cerrado con evidencia ejecutada en cada lección, incluida la deriva real de versión de cosign documentada en vivo, no escondida. El Módulo 7 abre la última capa de la guía antes del capstone: la distinción entre guardrails preventivos y detectivos, con la fila TM-03 (CloudTrail) como el último hallazgo de THREAT-MODEL.md que queda por resolver.
Recursos
- Sigstore — Documentación oficial de
cosign— la referencia completa design-blob/verify-blobusada en todo este módulo. - Este módulo, lecciones 3, 5, 6 y 7 — el origen de cada una de las cuatro piezas reunidas en este proyecto, con su evidencia individual ya verificada.
- Este curso, Módulo 1,
THREAT-MODEL.md/RISK-MAP.md— el hallazgoTM-02que este proyecto cierra, y la fila que actualiza. cicd-and-gitops-on-aws-guide, Módulo 2, lección 5 y Módulo 5, lección 4 — el pinning por SHA y elapply.ymloriginal que este proyecto extiende, sin reescribir.- nektosact.com — User Guide — referencia de
act push -W, usada en todo este proyecto para acotar y correr las corridas del workflow extendido.