docs(devsecops): documentar 4+1 hallazgos de infraestructura y TODOs de Cosign

5 playbooks nuevos en docs/playbooks/ del portal:
- SQLite en modo DELETE causando SQLITE_BUSY, por que WAL lo resuelve.
- Anchors YAML no soportados por el parser de Gitea Actions, incluido
  el diagnostico equivocado inicial (indentacion) que se corrigio
  despues -- documentado con honestidad como leccion de proceso.
- Docker-in-Docker vs sibling containers, y por que Semgrep corre
  nativo en un venv en vez de como container aparte.
- El SNI/realm HTTP del tunel rompiendo especificamente a Cosign
  (docker push funcionaba, cosign sign no), conectado con el
  incidente ya documentado del 504 -- misma capa de ingress, dos
  fallas distintas.
- Contencion de recursos entre Gitea y su runner: causa raiz real
  confirmada en vivo durante esta misma sesion (ambos contenedores
  reiniciados a mitad de un build, sin limites de CPU/memoria reales),
  con fix propuesto (ver rama fix/gitea-runner-resource-limits en
  scripts/) pendiente de aplicacion manual.

Se actualiza el playbook del 504 para linkear hacia el nuevo hallazgo
de contencion, cerrando el loop que habia quedado abierto ahi.

cosign.md: nueva seccion "Limitaciones conocidas y mejoras futuras"
con los dos TODO reales -- firma por tag en vez de digest (con el
warning real de Cosign visto en los logs) y transparency log de Rekor
deshabilitado, explicado en simple.

index.md: tabla resumen de los 3 pipelines (imagen + adaptacion de
Semgrep por stack), diagrama generalizado para reflejar que es el
mismo patron en los 3 workflows, y "que falta" actualizado.

Validado con mkdocs build --strict (0 errores, 0 warnings) antes de
commitear.
This commit is contained in:
2026-08-15 15:17:43 -05:00
parent 826f199ebc
commit be3e5c2a4c
9 changed files with 666 additions and 13 deletions
@@ -0,0 +1,122 @@
# Incidente: anchors YAML no soportados por Gitea Actions — y un diagnóstico equivocado en el camino (2026-08)
| | |
|---|---|
| **Ventana del incidente** | 2026-08-15, desde el primer commit que agregó Gitleaks a `build.yaml` |
| **Servicio afectado** | Gitea Actions — el workflow `build.yaml` (frontend) |
| **Impacto** | `build.yaml` no generaba **ningún** `action_run`, ni en `push` ni en `pull_request` — el pipeline entero era invisible para Gitea, sin ningún error visible en la UI |
## Qué es un anchor/alias YAML, para quien no lo conoce
YAML tiene una forma de evitar repetir el mismo bloque dos veces:
```yaml
paths: &frontend_paths
- 'workloads/ecommerce/**'
- '.gitea/workflows/build.yaml'
on:
push:
paths: *frontend_paths
pull_request:
paths: *frontend_paths
```
`&frontend_paths` es un **anchor** (marca ese nodo con un nombre).
`*frontend_paths` es un **alias** (dice "poné acá una copia de lo que
marcó ese anchor"). Es YAML 100% estándar — cualquier parser que siga
la especificación lo resuelve sin problema, y es una forma común de no
duplicar listas idénticas en el mismo archivo.
## Síntoma
`build.yaml` (con Gitleaks recién agregado, usando anchors para no
repetir la lista de `paths` entre `push:` y `pull_request:`) no
generaba ningún run en Gitea Actions. Ni en el push directo a la rama
del PR, ni al abrir el pull request. Sin mensaje de error visible en
la UI de Gitea — el workflow simplemente no aparecía en la lista de
Actions, como si no existiera.
## Primer diagnóstico (equivocado)
La primera sospecha fue una indentación rota específicamente en el
step de Semgrep: el bloque `python3 -c "..."` embebido dentro de un
`run: |` tenía código pegado a columna 0, por debajo de la
indentación esperada del block scalar de YAML. Eso ** era un
problema real — cortaba el block scalar ahí mismo y en teoría podía
hacer que Gitea rechazara el archivo con un error de parseo genérico
(`could not find expected ':'`).
Se corrigió la indentación, se validó con un parser YAML real y
`bash -n` sobre los 20 steps del archivo, se mergeó a `main` como fix
(`fix(ci): corregir indentación YAML rota en el step de Semgrep`, PR
#19)... y `build.yaml` **siguió sin generar runs**.
!!! warning "Por qué vale la pena contar el diagnóstico que no era"
El primer fix no estaba mal — la indentación efectivamente estaba
rota y corregirla era necesario. El error fue asumir que esa era
*la única* causa sin confirmarlo con una corrida real después del
fix. La lección de proceso: un fix que "tiene sentido" y que pasa
la validación local (parser YAML, `bash -n`) todavía necesita una
confirmación en vivo contra el sistema real antes de darlo por
cerrado — sobre todo cuando el síntoma es "no pasa nada" en vez de
un error explícito, que es exactamente el tipo de fallo más fácil
de dar por resuelto sin verificar.
## Causa raíz real
`deploy-docs.yaml` (sin anchors) corría normal. `build.yaml` (con
anchors, agregados junto con Gitleaks) no generaba ningún run — ni
en `push` ni en `pull_request`, desde el primer commit que los
introdujo. El log del propio Gitea lo confirmó:
```text
unknown on type: &yaml.Node{...Value:"frontend_paths"...}
```
El parser propio de Gitea Actions para el bloque `on:` de un workflow
**no resuelve `&anchor`/`*alias` antes de inspeccionar el tipo de
nodo** — encuentra un anchor donde esperaba un valor ya resuelto, no
sabe qué tipo de dato es, y descarta el archivo completo en
silencio. `pyyaml` y cualquier parser YAML estándar sí resuelven el
alias primero (por eso el archivo "parseaba bien" en cualquier
herramienta de validación genérica) — es una limitación específica del
parser de workflows de Gitea Actions, no un YAML inválido.
Esto explica por qué el síntoma no tenía ningún error visible: no es
que el job fallara, es que **Gitea nunca llegaba a registrar el
workflow como existente**.
## Fix aplicado
Se eliminaron los anchors/alias. Las dos listas de `paths` (una para
`push:`, otra para `pull_request:`) quedan **duplicadas
literalmente**, sin referencia compartida:
```yaml
on:
push:
branches: [main]
paths:
- 'workloads/ecommerce/**'
- '.gitea/workflows/build.yaml'
pull_request:
branches: [main]
paths:
- 'workloads/ecommerce/**'
- '.gitea/workflows/build.yaml'
```
Es más repetitivo, pero es el precio de que el parser de Gitea
Actions lo entienda. Este mismo criterio (sin anchors, paths
duplicados) se replicó a propósito en `build-medusa.yaml` y
`deploy-docs.yaml` al agregarles el resto del pipeline de seguridad,
para no repetir el mismo problema.
## Validación
Confirmado en vivo: tras mergear el fix, `build.yaml` generó su
primer `action_run` real. Validado también con un parser YAML +
`bash -n` sobre los 20 steps del archivo, igual que en el intento
anterior — la diferencia esta vez fue confirmarlo contra una corrida
real antes de cerrar el incidente.