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:
@@ -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 *sí* 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.
|
||||
Reference in New Issue
Block a user