Skip to content

fix(tracker-web): versioned BFF base /api/v1 + build .dockerignore (GT-447) #54

fix(tracker-web): versioned BFF base /api/v1 + build .dockerignore (GT-447)

fix(tracker-web): versioned BFF base /api/v1 + build .dockerignore (GT-447) #54

Workflow file for this run

name: Deploy check (kind + Helm + smoke)
# Este job vivia en `ci.yml` y se saco a su propio fichero por UNA razon: poder
# filtrarlo por rutas. Tarda ~7 minutos —levanta un cluster de Kubernetes, construye
# dos imagenes y redespliega en perfil de produccion— y se disparaba tambien cuando
# el cambio eran dos ficheros markdown. Medido el 2026-07-20: publicar la ficha
# GT-474, que solo tocaba documentacion, costo 14 minutos de CI entre `develop` y
# `main`.
#
# SE USA `paths-ignore` Y NO `paths`, Y LA DIFERENCIA ES DE SEGURIDAD, NO DE ESTILO.
# Una lista blanca (`paths`) se queda obsoleta EN SILENCIO: alguien anade una carpeta
# de codigo nueva, nadie la incluye, y el despliegue deja de comprobarse sin que nada
# avise — exactamente la clase de hueco que este job existe para cerrar. Una lista
# negra falla al reves: ante la duda, corre.
#
# Por eso lo ignorado es SOLO lo demostrablemente inerte. `.harness/` NO esta: sus
# scripts los ejecuta CI.
# NO corre en push a `main`, y es deliberado. El merge a `main` es contenido
# IDENTICO al de `develop` —siempre `--no-ff` de develop, nunca commits sueltos—
# que ya paso este mismo job minutos antes. Correrlo dos veces sobre el mismo
# arbol costaba 7 minutos por nada: era la mitad del tiempo de publicar.
#
# EL RIESGO, dicho: un commit directo a `main` que no venga de `develop` se salta
# esta comprobacion. El flujo del repositorio no hace eso —se publica siempre por
# develop— pero si alguien empieza a hacerlo, esto deja de cubrirlo y hay que
# volver a poner `main` aqui. Queda escrito para que la decision se revise a
# proposito y no se descubra por sorpresa.
on:
push:
branches: [develop]
paths-ignore:
- 'docs/**'
- '*.md'
pull_request:
branches: [main, develop]
paths-ignore:
- 'docs/**'
- '*.md'
permissions:
contents: read
concurrency:
group: deploy-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
deploy:
name: Deploy (kind + Helm + smoke)
runs-on: ubuntu-latest
# Anadido el 2026-07-20, despues de que el PRIMER despliegue real destapara tres defectos
# de golpe (GT-460, CD-15, GT-461) que ni las 894 pruebas ni el resto de CI podian ver.
#
# Los tres vivian en el hueco entre lo que CI ejercitaba y lo que producción recorre: CI
# aplicaba migraciones con `dotnet ef database update` y el clúster usa el BUNDLE de la
# imagen —caminos distintos, y solo uno cubierto—; los secretos que el chart exige no los
# creaba nadie; y el smoke apuntaba a rutas anteriores al versionado de la API. Ninguno
# era detectable leyendo: aparecieron al desplegar.
#
# Este job cierra ese hueco corriendo LITERALMENTE el mismo comando que corre un
# desarrollador. Por eso `kind` se instala como binario en vez de usar una accion que
# cree el clúster por su cuenta: si CI usara un camino propio, volveria a haber dos
# caminos y uno sin cubrir, que es la causa raiz que este job existe para eliminar.
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Instalar kind
# kubectl, helm y docker vienen en el runner; kind no.
#
# `sudo install` y no `curl -o` directo: el runner no puede dar permisos de ejecucion
# dentro de /usr/local/bin, asi que la descarga cuela y el `chmod` revienta despues.
run: |
curl -fsSLo /tmp/kind \
https://kind.sigs.k8s.io/dl/v0.24.0/kind-linux-amd64
sudo install -m 0755 /tmp/kind /usr/local/bin/kind
kind --version
- name: Levantar el stack (kind + build + load + Helm + migraciones)
run: bash product/infra/helm/local-test.sh up
- name: Smoke contra el despliegue vivo
env:
SMOKE_OBSERVE_SECONDS: "25"
run: bash product/infra/helm/local-test.sh smoke
# OPP-003 / RoboSoft — agentes E2E deterministicos contra el despliegue LOCAL
# (dev-bypass). Corre aqui, mientras el perfil local esta desplegado y antes del
# redespliegue de produccion, porque los robots actuan por `x-tenant-id` (dev-bypass).
# Ejercitan el funnel SDLC completo, el ciclo ProviderConnection y el aislamiento de
# tenant contra el tracker-api + Postgres reales. `core-integration` se excluye: necesita
# el Core (otro producto), que no se despliega en este pipeline. Este paso MUERDE.
- name: RoboSoft E2E (agentes deterministicos contra el despliegue local)
run: bash product/infra/helm/local-test.sh robosoft
# GT-464 — hasta aqui el despliegue se probaba SOLO con el perimetro abierto:
# `values-local.yaml` corre en Development con `dev-bypass`, que autentica cualquier
# peticion como administrador con todos los permisos. Lo de abajo lo prueba cerrado,
# que es como corre de verdad.
- name: Fail-closed sobre la imagen (el bypass no es alcanzable en Production)
# Va antes de redesplegar porque no necesita clúster: son dos `docker run`, con
# control incluido. Si esto cae, el resto da igual.
run: bash product/infra/helm/local-test.sh verify-failclosed
- name: Redesplegar con el PERFIL DE PRODUCCION
env:
TRACKER_PROFILE: prod
run: |
bash product/infra/helm/local-test.sh down
bash product/infra/helm/local-test.sh install
- name: Smoke de produccion (perimetro CERRADO)
env:
SMOKE_OBSERVE_SECONDS: "25"
run: bash product/infra/helm/local-test.sh smoke-prod
- name: Diagnostico (solo si algo fallo)
# En un runner efimero no queda clúster al que asomarse. El modo de fallo real de
# CD-15 fue `helm --wait` agotandose SIN decir por que: el motivo solo estaba en el
# `describe` del pod. Lo que no se imprima aqui, se pierde.
if: failure()
run: bash product/infra/helm/local-test.sh diagnose