Commit Graph
296 Commits
Author SHA1 Message Date
devops 98096ab69f Merge pull request 'feat(devsecops): Gitleaks + Trivy + Semgrep + Syft + Cosign en el frontend' (#19) from fix/frontend-gitleaks-ci into main
Build and Push Docs Portal / Construir y publicar Docs Portal (push) Successful in 1m36s
2026-08-15 04:14:08 +00:00
devops 2438a6ba0f fix(ci): corregir indentación YAML rota en el step de Semgrep
El python3 -c "..." embebido dentro del run: | tenía el código pegado
a columna 0, por debajo de la indentación del bloque YAML -- eso corta
el block scalar ahí mismo y Gitea terminaba ignorando el workflow
completo ("could not find expected ':'"), silenciosamente, desde el
commit de Semgrep.

Validado con un parser YAML real (no solo con builds de Docker) y
bash -n sobre los 20 steps del archivo.
2026-08-14 22:59:31 -05:00
devops 96be5b4b03 chore: trigger CI re-check after Gitea SQLite WAL fix 2026-08-14 22:28:22 -05:00
devops 7dc50b83e0 docs(devsecops): agregar página resumen con diagrama del pipeline
docs/devsecops/index.md documenta el pipeline completo (job gitleaks +
job build) con un diagrama Mermaid del orden real de ejecución, tabla
de qué bloquea vs qué solo informa, y qué pasa si cada herramienta
falla. Nav actualizado: "Resumen" como landing page de la sección
DevSecOps.

Con esto quedan las 5 herramientas de la Fase 2 (Gitleaks, Trivy,
Semgrep, Syft, Cosign) integradas y documentadas para
workloads/ecommerce, listas para replicar a commerce-backend y
docs-portal en una próxima vuelta.
2026-08-14 21:59:58 -05:00
devops c1b5f72a68 feat(devsecops): firmar la imagen del frontend con Cosign
Firma la imagen (solo el tag versionado, no :latest) después del push
exitoso, usando la llave privada desde secrets de Gitea Actions
(COSIGN_PRIVATE_KEY/COSIGN_PASSWORD, nunca en el repo ni en disco).
Verifica la firma como smoke test en el mismo pipeline contra
workloads/ecommerce/cosign.pub (pública, commiteada a propósito).

Firma solo con el par de llaves propio, sin publicar en el
transparency log público de Sigstore (--use-signing-config=false
--tlog-upload=false / --insecure-ignore-tlog=true) — registry privado,
no tiene sentido esa fuga de metadata.

Par de llaves generado y validado end-to-end (firma + verificación,
incluyendo que verificar con la llave incorrecta falla como se espera)
contra un registry local descartable antes de tocar nada real. Docs en
docs/devsecops/cosign.md, incluyendo qué falta para que un admission
controller verifique esto en el cluster (no implementado todavía).
2026-08-14 21:55:03 -05:00
devops b6038e06ca feat(devsecops): generar SBOM (Syft) de la imagen del frontend
Corre después del gate de CRITICAL de Trivy, sobre la imagen ya
construida. Genera CycloneDX y SPDX, publicados como artifact
sbom-v1.0.X en cada build.

Validado contra la imagen real: 3528 componentes CycloneDX / 228
paquetes SPDX. Documenta en docs/devsecops/sbom.md el propósito
(trazabilidad tipo "log4shell"), diferencia entre formatos, y un
hallazgo real (yarn empaquetado sin usarse, mismo patrón que el npm
sacado en el fix de Trivy).
2026-08-14 21:14:00 -05:00
devops 4aed9f6c5c feat(devsecops): agregar Semgrep SAST en modo auditoría al pipeline
Escanea workloads/ecommerce con rulesets públicos del registro de
Semgrep (p/typescript, p/react, p/nextjs, p/security-audit) vía la
imagen oficial semgrep/semgrep:1.173.0. Sin --error a propósito: siempre
termina en exit 0, solo reporta — primera vuelta para revisar juntos qué
reglas deberían pasar a bloquear más adelante.

Validado contra el código real: 0 hallazgos en 91 reglas / 72 archivos.
Documenta la herramienta en docs/devsecops/sast.md, incluyendo la
diferencia con gitleaks/trivy y qué significa (y qué no) un scan limpio.
2026-08-14 21:07:05 -05:00
devops df13233a29 feat(devsecops): agregar Trivy (imagen + IaC) al pipeline del frontend
trivy config sobre frontend.yaml (CRITICAL/HIGH/MEDIUM, informativo) y
trivy image sobre la imagen recién construida (CRITICAL bloquea con
--ignore-unfixed, HIGH solo informa), entre build (push:false, load:true)
y el push real al registry.

Fix real encontrado al validar contra la imagen real: el stage runner
heredaba npm/npx/corepack completos de la imagen base de Node sin
necesitarlos en runtime, trayendo CVE-2026-59873 (CRITICAL, node-tar
empaquetado en npm). Sacarlos del stage final baja CRITICAL de 1 a 0 y
HIGH fixable de 21 a 15 (las que quedan son de la propia app, ej. next
desactualizado, documentadas como pendiente sin bloquear).

Documenta ambos scans en docs/devsecops/trivy.md con los hallazgos
reales de este repo.
2026-08-14 20:43:09 -05:00
devops 422e9d257d feat(devsecops): agregar Gitleaks al pipeline del frontend
Corre en push y pull_request, antes del job build (needs: gitleaks).
Si detecta un secreto, exit-code=1 detiene el pipeline antes de
construir la imagen. Scan histórico completo del repo (249 commits)
confirmado limpio, corrido aparte de forma manual.

Documenta el step en docs/devsecops/gitleaks.md: qué es secret
scanning, por qué corre antes del build, cómo leer un hallazgo y
cómo manejar falsos positivos con allowlist.
2026-08-14 19:48:44 -05:00
gitea-actions 66c44a7dad chore(gitops): deploy Docs Portal v1.0.97 [skip ci] 2026-08-14 04:10:07 +00:00
devops ef0093a406 Merge pull request 'fix(docs-portal): deshabilitar git-revision-date-localized (rompe --strict)' (#18) from fix/docs-portal-deshabilitar-plugin-fechas into main
Build and Push Docs Portal / Construir y publicar Docs Portal (push) Successful in 10m7s
2026-08-14 03:29:21 +00:00
devops 0234c20463 fix(docs-portal): deshabilitar git-revision-date-localized (rompe --strict)
mkdocs build --strict aborta ante CUALQUIER WARNING, no solo ante links
rotos. El plugin, al no tener .git real en el contexto de build
(workloads/docs-portal/, sin .git de la raíz del repo), cae siempre en
fallback_to_build_date y emite un WARNING por página — suficiente para
tumbar el build bajo --strict (confirmado en run 96, job 108: 33
warnings, todos de este plugin, cero links rotos).

Se deshabilita el plugin (comentado en mkdocs.yml y requirements.txt,
con TODO fase 2: mover el build a la raíz del repo + fetch-depth:0 para
darle historial real) y se revierte la instalación de git en el
Dockerfile, que ya no hace falta. index.md actualizado para no prometer
fechas reales que hoy no se muestran.
2026-08-13 22:27:56 -05:00
devops 9ec40370bf Merge pull request 'fix(docs-portal): corregir anchor roto en playbook de crashloop de Medusa' (#17) from fix/docs-portal-anchor-roto into main
Build and Push Docs Portal / Construir y publicar Docs Portal (push) Failing after 2m11s
2026-08-14 03:20:51 +00:00
devops 22534d65f3 fix(docs-portal): corregir anchor roto en playbook de crashloop de Medusa
mkdocs build --strict (run 95, job 107) falló: el link a '#deuda-técnica-pendiente'
no coincide con el anchor real que genera mkdocs, porque el slugify por
defecto de Python-Markdown normaliza tildes (NFKD + strip de combining marks)
antes de generar el id del heading. El heading '## Deuda técnica pendiente'
genera 'deuda-tecnica-pendiente' (sin tilde), no 'deuda-técnica-pendiente'.
2026-08-13 22:10:36 -05:00
devops 45924f9df2 Merge pull request 'fix(docs-portal): instalar git en la imagen de build para mkdocs-git-revision-date-localized-plugin' (#16) from fix/docs-portal-dockerfile-git-binario into main
Build and Push Docs Portal / Construir y publicar Docs Portal (push) Failing after 9m50s
2026-08-14 02:57:10 +00:00
devops bb1249fd58 fix(docs-portal): instalar git en la imagen de build para mkdocs-git-revision-date-localized-plugin
El plugin depende de GitPython, que necesita el binario git para
importarse (no solo para leer fechas) — sin él, mkdocs build --strict
falla en el import del plugin antes de llegar al fallback_to_build_date
configurado en mkdocs.yml.

Detectado en el primer intento real de build en Gitea Actions (run 94,
job 106).
2026-08-13 21:56:11 -05:00
devops 10556758b2 Merge pull request 'docs(docs-portal): documentar que el pipeline de build/deploy quedó operativo' (#15) from fix/docs-portal-estado-pipeline-vivo into main
Build and Push Docs Portal / Construir y publicar Docs Portal (push) Failing after 7m46s
2026-08-14 02:42:04 +00:00
devops e8712327a2 docs(docs-portal): documentar que el pipeline de build/deploy quedó operativo
Dispara el primer build real del portal via .gitea/workflows/deploy-docs.yaml
ahora que el Deployment, Service, Ingress y el secret de registry ya existen
en el namespace docs-portal.
2026-08-13 21:41:50 -05:00
devops d5c80c98e7 Merge pull request 'feat(docs-portal): pipeline GitOps y manifiestos K8s para el portal MkDocs' (#14) from fix/docs-portal-pipeline-manifests into main
Build and Push Docs Portal / Construir y publicar Docs Portal (push) Failing after 1m21s
2026-08-14 02:33:53 +00:00
devops fb5cf8bc98 feat(docs-portal): pipeline GitOps y manifiestos K8s para el portal MkDocs
Agrega lo que faltaba para desplegar workloads/docs-portal/ (ya existente
sin commitear): deployment/service/ingress + kustomization siguiendo el
patrón de workloads/nginx, Applications de workload y gobernanza
separadas, y el workflow de Gitea Actions (build+push a Gitea Registry,
bump de versión en el manifiesto) siguiendo el mismo patrón que
build.yaml/build-medusa.yaml.
2026-08-13 21:08:04 -05:00
devops 11737ba109 Merge pull request 'docs(playbooks): documentar incidentes túnel/precios/imágenes' (#13) from fix/docs-incidentes-tunel-precios-imagenes into main 2026-08-13 23:39:17 +00:00
devops b42bcad45e docs(playbooks): documentar incidentes túnel/precios/imágenes [skip ci]
Tres incidentes resueltos en la sesión del 2026-08-12/13: 504 intermitente
por QUIC inestable en cloudflared, precios null por falta de region_id
en el Store API de Medusa v2 (se descarta la hipótesis inicial de
regiones COP duplicadas con evidencia directa en Postgres), e imágenes
en blanco por un proxy host mal configurado en Nginx Proxy Manager para
media.cruzcloud.net. Se agregan también dos notas de referencia en
known-issues.md: la topología Cloudflare Tunnel -> NPM -> k3d, y el
requisito de region_id explícito en StoreGetProductsParams.
2026-08-13 18:34:10 -05:00
gitea-actions 130177a9f2 chore(gitops): deploy Medusa v1.0.92 [skip ci] 2026-08-13 22:08:17 +00:00
devops 7644b53c49 Merge pull request 'feat(commerce-backend): revalidar el storefront al crear/borrar productos' (#11) from fix/medusa-revalidate-on-product-created into main
Build and Push Medusa / Construir y publicar Medusa (push) Successful in 12m33s
2026-08-13 21:55:54 +00:00
devops 8c52229e71 feat(commerce-backend): revalidar el storefront al crear/borrar productos
El subscriber revalidate-storefront.ts (PR #9) solo escuchaba
product.updated y los eventos de variante, asi que un producto nuevo
(product.created) o eliminado (product.deleted) no disparaba
revalidateTag: el storefront tardaba hasta el ciclo normal de cache
(~60s por pod) en reflejar altas/bajas de catalogo, a diferencia de
precio/descripcion/imagenes en productos existentes, que ya viajan por
product.updated.
2026-08-13 16:55:16 -05:00
devops 2d09867f70 Merge pull request 'chore(gitops): fijar Medusa a v1.0.90 tras carrera de promocion en CI' (#10) from fix/medusa-manifest-lagged-race into main 2026-08-13 21:41:45 +00:00
devops 6a0e9965a9 chore(gitops): fijar Medusa a v1.0.90 tras carrera de promocion en CI
El pipeline build-medusa.yaml (run #90) construyo y publico
ecommerce-medusa:v1.0.90 con exito, pero su paso "Actualizar
manifiesto Medusa" quedo skipped: el chequeo de promocion segura
comparo github.sha contra origin/main y encontro que el commit
"chore: release v1.0.91" del frontend ya habia cambiado el HEAD, asi
que se abstuvo de sobrescribirlo. medusa.yaml se quedo en v1.0.88, sin
el subscriber revalidate-storefront agregado en el PR #9.

Bump manual del tag en ambos containers (migrations y medusa) para
que Argo CD despliegue la imagen que ya esta en el registry.
2026-08-13 16:39:28 -05:00
devops 095912d02d chore: release v1.0.91 [skip ci] 2026-08-13 21:19:17 +00:00
devops a1d2f9db67 Merge pull request 'feat(ecommerce): revalidar el storefront al instante tras editar precios' (#9) from fix/medusa-price-instant-revalidate into main
Build and Push Frontend / Construir y Subir Imagen (push) Successful in 7m39s
Build and Push Medusa / Construir y publicar Medusa (push) Successful in 15m24s
2026-08-13 21:06:13 +00:00
devops d1a4a84d24 feat(ecommerce): revalidar el storefront al instante tras editar precios
Antes el precio actualizado en Medusa tardaba hasta ~60s (o más, con
varias réplicas del frontend sin cache handler compartido) en verse en
el front, por el revalidate:60 del fetch a /store/products.

Ahora:
- Nueva ruta app/api/revalidate en el storefront que llama a
  revalidateTag("medusa-products") al recibir un POST autenticado con
  el header x-revalidate-secret.
- Nuevo subscriber en el backend Medusa (product.updated,
  product-variant.updated/created/deleted) que llama a esa ruta usando
  STOREFRONT_URL (ya existe en commerce-config) y un REVALIDATE_SECRET
  compartido entre ambos servicios.
- secrets.template.yaml documenta la nueva clave REVALIDATE_SECRET en
  commerce-secrets y commerce-storefront (mismo valor en ambos).

Requiere reaplicar commerce-secrets y commerce-storefront con el script
actualizado en el repo scripts (fix/revalidate-secret-scripts) para que
el REVALIDATE_SECRET exista en el cluster.
2026-08-13 16:02:49 -05:00
devops a9c57d4985 chore: release v1.0.89 [skip ci] 2026-08-13 07:07:55 +00:00
devops 584a42ea72 Merge pull request 'fix(ecommerce): detalle de producto en dynamic render, no SSG+ISR stale' (#8) from fix/product-detail-static-mock-price into main
Build and Push Frontend / Construir y Subir Imagen (push) Successful in 5m55s
2026-08-13 07:02:11 +00:00
devopsandClaude Sonnet 5 a6a92f75ea fix(ecommerce): render product detail dynamically instead of stale SSG+ISR
Product detail pages were generateStaticParams'd at Docker build time,
where MEDUSA_* env vars aren't set, so the static snapshot baked in the
mock catalog (price: null for all products). With revalidate=60 and no
shared ISR cache handler across the 2 frontend replicas, each pod healed
its own cache independently on next visit past staleness — so a product
could show "Consultar precio" on one pod and the real price on the other,
while the fully-dynamic catalog listing always hit Medusa fresh. Verified
against the live Medusa API that pricing/region data itself was correct
for the reported failing products.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01DXqBoNfYQNwFg65mbx2FWM
2026-08-13 01:59:44 -05:00
devops 0eea6234d6 chore: release v1.0.87 [skip ci] 2026-08-13 00:24:20 -05:00
gitea-actions 77bf6089fb chore(gitops): deploy Medusa v1.0.88 [skip ci] 2026-08-13 05:01:13 +00:00
devops 0134a4dd0b Merge pull request 'fix: desactivar cookie Secure en sesion admin de Medusa' (#7) from fix/medusa-admin-session-cookie into main
Build and Push Medusa / Construir y publicar Medusa (push) Successful in 18m10s
2026-08-13 04:08:03 +00:00
devops 3fe63591ec Merge pull request 'fix: forzar ISR en /product/[slug] para que no quede atascado en mock' (#6) from fix/product-page-static-mock-price into main
Build and Push Frontend / Construir y Subir Imagen (push) Successful in 7m12s
2026-08-13 04:04:40 +00:00
devops c6cf394c26 fix: desactivar cookie Secure en sesion admin de Medusa
Todos los Ingress del lab terminan en Traefik por HTTP plano (entrypoint
web, sin TLS); Cloudflare es quien atiende HTTPS de cara al navegador.
Con secure:true (default en produccion), express-session nunca emite
Set-Cookie porque no detecta la conexion como HTTPS, dejando el
dashboard admin con 401 en /admin/users/me pese a loguear bien.
2026-08-12 23:01:35 -05:00
devops 7a09202c27 fix: forzar ISR en /product/[slug] para que no quede atascado en datos mock del build
generateStaticParams usa el catálogo mock en build time porque
HEADLESS_PROVIDER y MEDUSA_* no existen como build args del Dockerfile.
Sin un revalidate explícito, esa ruta queda estática para siempre con
price:null. El listado no sufre esto porque su ruta es dinámica por
searchParams.
2026-08-12 22:56:03 -05:00
devops a902dc0a26 chore: release v1.0.86 [skip ci] 2026-08-12 07:16:46 +00:00
devops 04dc6bd8bc Merge pull request 'fix: usar region_id en vez de currency_code para precios de Medusa' (#5) from fix/medusa-region-id-pricing into main
Build and Push Frontend / Construir y Subir Imagen (push) Successful in 9m9s
2026-08-12 07:03:28 +00:00
devops 60072cfcbe fix: usar region_id en vez de currency_code para precios de Medusa
El validador de /store/products (StoreGetProductsParams, .strict()) solo
acepta region_id/country_code/province/cart_id para resolver contexto de
precio -- currency_code como campo plano no existe y rompía con 400
"Unrecognized fields: 'currency_code'" en cada carga de /catalog.

country_code tampoco alcanza: probado en vivo, devuelve "Missing required
pricing context to calculate prices - region_id". Se necesita region_id
explícito.

Se agrega MEDUSA_REGION_ID (env var) apuntando a la región "Colombia"
(COP) creada vía Admin API, ya que no existía ninguna región configurada
en el backend.
2026-08-12 02:01:49 -05:00
devops c9b376c4e6 Merge pull request 'fix: conectar el frontend al catálogo real de Medusa' (#4) from fix/frontend-wire-medusa-catalog into main 2026-08-12 05:16:18 +00:00
devops cea41ce428 fix: conectar el frontend al catálogo real de Medusa
El Deployment frontend-deploy no tenía ninguna variable de entorno, así
que HEADLESS_PROVIDER quedaba undefined y el provider caía siempre en
mockCatalogProvider (data/products.json estático), aunque
medusaCatalogProvider ya estaba implementado y listo en
lib/headless/providers/medusa.ts.

Se agrega HEADLESS_PROVIDER=medusa, MEDUSA_BACKEND_URL apuntando al
Service interno medusa-svc:9000 (evita depender de Cloudflare/NPM en
cada render SSR), y envFrom hacia el secret commerce-storefront
(MEDUSA_PUBLISHABLE_KEY) ya creado en el namespace ecommerce.

No se bumpea el tag de imagen: build.yaml excluye explícitamente los
cambios de frontend.yaml del trigger de build, y la versión la gestiona
la propia CI vía sed sobre este archivo.
2026-08-12 00:12:10 -05:00
devops 381e6ab6ab docs(playbooks): documentar incidente medusa-deploy atascado en Init (2026-08)
Postmortem del incidente resuelto en e9c93bf: sintoma reportado como
CrashLoopBackOff que en realidad era Init:0/2 indefinido (0 restarts).
Documenta las hipotesis descartadas en orden (secret/DATABASE_URL,
NetworkPolicy, salud de Postgres, ResourceQuota, DNS, MTU/PMTUD
cross-node), la causa raiz (pg_isready no parseaba ?sslmode=disable en
la URI, exit 3 "no attempt"), el fix con flags explicitos, y la deuda
tecnica pendiente en la branch fix/medusa-wait-for-postgres.
2026-08-10 00:47:23 -05:00
devops e9c93bfb82 fix(medusa): usar flags explicitos en pg_isready en vez de DATABASE_URL crudo
El init container wait-for-postgres pasaba $DATABASE_URL completo a
pg_isready. Al agregarle ?sslmode=disable (via create-commerce-secrets.sh),
pg_isready fallaba con "no attempt" (exit 3, conninfo invalida para su
parser de URI) y el pod quedaba atascado en Init indefinidamente, sin
llegar nunca al CrashLoopBackOff visible. Postgres, DNS, Endpoints y
NetworkPolicy estaban sanos; el fallo era puramente del parseo de la URI.

Se reemplaza por -h/-p/-U/-d explicitos (host y puerto fijos del Service,
usuario y db ya disponibles via envFrom), asi el init container queda
inmune a query params futuros en DATABASE_URL.
2026-08-10 00:27:10 -05:00
devops f25b10a2f9 Merge pull request 'fix(medusa): forzar podAffinity con commerce-postgres para evitar blackhole MTU cross-node' (#3) from fix/medusa-postgres-node-affinity into main 2026-08-09 07:36:33 +00:00
devops 7a83ed61b9 fix(medusa): forzar podAffinity con commerce-postgres para evitar blackhole MTU cross-node
Diagnostico: pg_isready y el cliente pg de Medusa fallan de forma
consistente (100%, 186/186 intentos) cuando el pod queda agendado en un
nodo distinto al de commerce-postgres-0. TCP handshake (nc/ping) funciona
cruzando nodos, pero el primer paquete de datos real de la sesion nunca
llega - blackhole de PMTU Discovery entre los nodos del cluster k3d
(flannel VXLAN / MTU del bridge Docker subyacente).

Se agrega podAffinity requiredDuringSchedulingIgnoredDuringExecution
(no nodeSelector fijo, mantiene portabilidad) para que medusa-deploy
siempre comparta nodo con commerce-postgres-0 y evite cruzar el
blackhole. Es un workaround, no el fix de raiz: documentado en
docs/known-issues.md junto con el TODO de ajustar el MTU del cluster
a 1400.
2026-08-09 02:34:15 -05:00
devops 987ef04b0d Merge pull request 'fix(medusa): agregar initContainer wait-for-postgres para evitar CrashLoopBackOff por fallo transitorio de red en arranque' (#2) from fix/medusa-wait-for-postgres into main 2026-08-09 06:42:39 +00:00
devops f4ad14028e fix(medusa): agregar initContainer wait-for-postgres para evitar CrashLoopBackOff por fallo transitorio de red en arranque 2026-08-09 01:29:43 -05:00