siesa-agents 2.1.72-qa.2 → 2.1.72-qa.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bmad/bmm/config.yaml +33 -0
- package/claude/skills/sa-agent-sre-sentinel/SKILL.md +180 -0
- package/claude/skills/sa-aplicar/SKILL.md +268 -0
- package/claude/skills/sa-auditar-servicio/SKILL.md +255 -0
- package/claude/skills/sa-nueva-transversal/SKILL.md +317 -0
- package/claude/skills/sa-nuevo-ambiente/SKILL.md +147 -0
- package/claude/skills/sa-nuevo-servicio/SKILL.md +530 -0
- package/claude/skills/sa-onboard-db/SKILL.md +122 -0
- package/claude/skills/sa-qa-data-generator/SKILL.md +200 -51
- package/claude/skills/sa-quality-process/SKILL.md +6 -0
- package/claude/skills/sa-registrar-permisos/SKILL.md +233 -0
- package/package.json +1 -1
- package/siesa-agents/bmm/workflows/3-solutioning/quality-process/prompts/prompt_design_test.md +1037 -60
- package/siesa-agents/bmm/workflows/3-solutioning/quality-process/prompts/prompt_dor_gate.md +419 -379
- package/siesa-agents/bmm/workflows/3-solutioning/quality-process/prompts/prompt_e2e_executor.md +273 -0
- package/siesa-agents/bmm/workflows/3-solutioning/quality-process/prompts/prompt_playwright_impl.md +359 -355
- package/siesa-agents/bmm/workflows/3-solutioning/quality-process/prompts/prompt_test_plan.md +73 -111
- package/siesa-agents/bmm/workflows/3-solutioning/quality-process/workflow.md +1320 -997
- package/siesa-agents/resources/playwright-kit/.env.example +42 -0
- package/siesa-agents/resources/playwright-kit/README.md +228 -0
- package/siesa-agents/resources/playwright-kit/allure/categories.json +26 -0
- package/siesa-agents/resources/playwright-kit/global-setup.ts +34 -0
- package/siesa-agents/resources/playwright-kit/helpers/blazor-e2e-helpers.ts +417 -0
- package/siesa-agents/resources/playwright-kit/helpers/react-e2e-helpers.ts +297 -0
- package/siesa-agents/resources/playwright-kit/package-lock.json +850 -0
- package/siesa-agents/resources/playwright-kit/package.json +27 -0
- package/siesa-agents/resources/playwright-kit/playwright.config.ts +60 -0
- package/siesa-agents/resources/playwright-kit/proposed/.gitkeep +0 -0
- package/siesa-agents/resources/playwright-kit/reporters/agiletest-reporter.ts +252 -0
- package/siesa-agents/resources/playwright-kit/specs/.gitkeep +0 -0
- package/siesa-agents/resources/playwright-kit/specs/architecture-brief-siesa-erp.md +85 -0
- package/siesa-agents/resources/playwright-kit/specs/architecture-brief-siesa-react.md +109 -0
- package/siesa-agents/resources/playwright-kit/specs/architecture-brief-template.md +69 -0
- package/siesa-agents/resources/playwright-kit/tests/seed-example.spec.ts +95 -0
- package/siesa-agents/resources/playwright-kit/tools/locator-overlay.js +1306 -0
- package/siesa-agents/resources/playwright-kit/tools/locator-recorder.spec.ts +986 -0
- package/siesa-agents/scripts/__pycache__/bmad_to_agiletest.cpython-36.pyc +0 -0
- package/siesa-agents/scripts/bmad_to_agiletest.py +352 -337
- package/siesa-agents/scripts/converters/convert_csv_to_test_design.py +327 -0
- package/siesa-agents/scripts/converters/convert_excel_to_test_design.py +360 -0
- package/siesa-agents/scripts/converters/convert_md_to_test_design.py +359 -0
- package/siesa-agents/scripts/converters/convert_pdf_to_test_design.py +412 -0
- package/siesa-agents/scripts/converters/export_yaml_to_csv.py +149 -0
- package/siesa-agents/scripts/converters/export_yaml_to_excel.py +233 -0
- package/siesa-agents/scripts/converters/export_yaml_to_markdown.py +172 -0
- package/siesa-agents/scripts/converters/export_yaml_to_pdf.py +297 -0
- package/siesa-agents/scripts/merge_test_design.py +106 -106
- package/siesa-agents/scripts/playwright/yaml-to-playwright-spec.ts +203 -0
- package/siesa-agents/scripts/requirements.txt +7 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sa-nuevo-ambiente
|
|
3
|
+
description: 'Adds a new environment (staging or prod) to this transversal by reading environments/{env}.yaml and generating the matching Terraform, CI/CD, and Kubernetes overlay artifacts. Use whenever the user wants to add a new deploy target to an existing transversal.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> **Contexto de ejecución:** este skill asume que el cwd está dentro de la carpeta del workspace de despliegue (`_siesa-agents/devops/` en Siesa-Agents tras correr `/sa-init-devops`, o la raíz de un clon directo de `architecture-sa-devops`). Las rutas relativas (`environments/`, `terraform/`, `k8s/`, `scripts/`, etc.) se resuelven contra ese cwd.
|
|
7
|
+
|
|
8
|
+
Agrega un nuevo ambiente (staging o prod) a esta transversal. Lee el `environments/{ambiente}.yaml` ya configurado y genera los artefactos Terraform, CI/CD y K8s overlay correspondientes.
|
|
9
|
+
|
|
10
|
+
**Uso:** `/sa-nuevo-ambiente {ambiente}`
|
|
11
|
+
|
|
12
|
+
**Ejemplo:** `/sa-nuevo-ambiente staging`
|
|
13
|
+
|
|
14
|
+
**Prerequisito:** El archivo `environments/{ambiente}.yaml` debe existir y tener todos los `<PLACEHOLDER>` completados antes de invocar este flow.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Instrucciones
|
|
19
|
+
|
|
20
|
+
El argumento es: `$ARGUMENTS`
|
|
21
|
+
|
|
22
|
+
`AMBIENTE` = el argumento (ej: `staging`, `prod`)
|
|
23
|
+
|
|
24
|
+
Primero lee `environments/{AMBIENTE}.yaml` y valida que no existan `<PLACEHOLDER>` sin completar. Si los hay, muestra cuáles faltan y detente.
|
|
25
|
+
|
|
26
|
+
Luego lee los valores:
|
|
27
|
+
- `PROJECT_ID` = `.gcp.project_id`
|
|
28
|
+
- `PROJECT_NUM` = `.gcp.project_number`
|
|
29
|
+
- `REGION` = `.gcp.region`
|
|
30
|
+
- `GATEWAY_NAME` = `.gateway.name`
|
|
31
|
+
- `GKE_CLUSTER` = `.gke.cluster_name`
|
|
32
|
+
- `WORKER_POOL` = `.cloud_build.worker_pool`
|
|
33
|
+
- `DEPLOY_SA` = `.deploy.sa_name`
|
|
34
|
+
- `SUITE` = `.naming.product_suite`
|
|
35
|
+
- `BUSINESS_UNIT` = `.naming.business_unit`
|
|
36
|
+
- `PROJECT_ID_DEV` = leyendo `environments/dev.yaml` → `.gcp.project_id` (para el bucket de estado)
|
|
37
|
+
|
|
38
|
+
Si `PROJECT_NUM` contiene `<PLACEHOLDER>` o está vacío, resuélvelo con Bash antes de continuar:
|
|
39
|
+
```bash
|
|
40
|
+
gcloud projects describe {PROJECT_ID} --format='value(projectNumber)'
|
|
41
|
+
```
|
|
42
|
+
Si el comando falla (proyecto no creado aún), detente y pide al usuario que cree el proyecto GCP primero.
|
|
43
|
+
|
|
44
|
+
Lee también `environments/dev.yaml` para obtener la lista de servicios y namespaces actuales.
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
### Paso 1 — `terraform/environments/{AMBIENTE}/main.tf`
|
|
49
|
+
|
|
50
|
+
Copia la estructura de `terraform/environments/qa/main.tf` (NO de dev — QA tiene los recursos IAM del worker pool privado) y aplica estos cambios:
|
|
51
|
+
- `bucket = "bkt-sie-{SUITE}-iac-state-{PROJECT_ID_DEV}"` — mismo bucket, distinto prefix
|
|
52
|
+
- `prefix = "terraform/environments/{AMBIENTE}"`
|
|
53
|
+
- `config = yamldecode(file("${path.module}/../../../environments/{AMBIENTE}.yaml"))`
|
|
54
|
+
- Comentario de cabecera: actualizar para describir el ambiente `{AMBIENTE}`
|
|
55
|
+
- El provider kubernetes apunta al cluster `{GKE_CLUSTER}`
|
|
56
|
+
|
|
57
|
+
**CRÍTICO — IAM para worker pool privado:** El deploy vía `gcloud builds submit k8s/` con worker pool requiere 4 recursos IAM que NO están en `dev/main.tf` pero SÍ en `qa/main.tf`. Asegúrate de incluirlos (copiando de QA):
|
|
58
|
+
1. `cicd_sa_storage_admin` — `roles/storage.admin` a cada CI/CD SA (escribir fuente al bucket `{project}_cloudbuild`)
|
|
59
|
+
2. `compute_sa_storage_admin` — `roles/storage.admin` al Compute SA (leer fuente desde el bucket en el worker pool)
|
|
60
|
+
3. `compute_sa_container_admin` — `roles/container.admin` al Compute SA (kubectl dentro del container)
|
|
61
|
+
4. `compute_sa_secret_accessor` — `roles/secretmanager.secretAccessor` al Compute SA (leer secrets al crear K8s secrets)
|
|
62
|
+
|
|
63
|
+
Sin estos 4, `gcloud builds submit` falla con `forbidden from accessing bucket`.
|
|
64
|
+
|
|
65
|
+
### Paso 2 — `.github/workflows/infra-pipeline-{AMBIENTE}.yml`
|
|
66
|
+
|
|
67
|
+
Copia `.github/workflows/infra-pipeline-dev.yml` y aplica estos cambios:
|
|
68
|
+
- `name: Infrastructure Pipeline — Dev` → `name: Infrastructure Pipeline — {AMBIENTE}`
|
|
69
|
+
- Reemplaza todos los paths que dicen `environments/dev.yaml` → `environments/{AMBIENTE}.yaml`
|
|
70
|
+
- Reemplaza todos los paths que dicen `k8s/overlays/dev/` → `k8s/overlays/{AMBIENTE}/`
|
|
71
|
+
- Reemplaza en los triggers `paths:`:
|
|
72
|
+
```yaml
|
|
73
|
+
- 'terraform/environments/{AMBIENTE}/**'
|
|
74
|
+
- 'environments/{AMBIENTE}.yaml'
|
|
75
|
+
- 'k8s/base/**'
|
|
76
|
+
- 'k8s/overlays/{AMBIENTE}/**'
|
|
77
|
+
```
|
|
78
|
+
- Reemplaza todos los `yq` que leen `environments/dev.yaml` → `environments/{AMBIENTE}.yaml`
|
|
79
|
+
- Reemplaza `terraform/environments/dev/` → `terraform/environments/{AMBIENTE}/`
|
|
80
|
+
- Reemplaza `k8s/overlays/dev/` → `k8s/overlays/{AMBIENTE}/` en los kubectl apply y tar
|
|
81
|
+
|
|
82
|
+
Si el ambiente es `prod`, agrega al job `terraform-apply`:
|
|
83
|
+
```yaml
|
|
84
|
+
environment:
|
|
85
|
+
name: prod
|
|
86
|
+
url: https://{DOMINIO}
|
|
87
|
+
```
|
|
88
|
+
(lee el dominio de `environments/prod.yaml` → `.dns.domain`)
|
|
89
|
+
|
|
90
|
+
### Paso 3 — `k8s/overlays/{AMBIENTE}/` (estructura completa)
|
|
91
|
+
|
|
92
|
+
Copia todos los archivos de `k8s/overlays/dev/` a `k8s/overlays/{AMBIENTE}/` y aplica estos reemplazos en el contenido de cada archivo YAML:
|
|
93
|
+
|
|
94
|
+
**En archivos `dapr/**/pubsub.yaml` y `dapr/**/secretstore.yaml`:**
|
|
95
|
+
- `value: {PROJECT_ID_DEV}` → `value: {PROJECT_ID}`
|
|
96
|
+
|
|
97
|
+
**En archivos `routes/*.yaml`:**
|
|
98
|
+
- `name: {GATEWAY_NAME_DEV}` → `name: {GATEWAY_NAME}`
|
|
99
|
+
(donde `GATEWAY_NAME_DEV` se lee de `environments/dev.yaml` → `.gateway.name`)
|
|
100
|
+
|
|
101
|
+
**El resto de archivos** (healthcheck, import-map, cron bindings) se copian sin modificar.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
### Paso 4 — Mostrar resumen
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
✅ GENERADO para ambiente {AMBIENTE}:
|
|
109
|
+
|
|
110
|
+
terraform/environments/{AMBIENTE}/main.tf
|
|
111
|
+
.github/workflows/infra-pipeline-{AMBIENTE}.yml
|
|
112
|
+
k8s/overlays/{AMBIENTE}/
|
|
113
|
+
dapr/*/* (pubsub, secretstore, statestore, crons)
|
|
114
|
+
routes/*
|
|
115
|
+
healthcheck/*
|
|
116
|
+
import-map/
|
|
117
|
+
|
|
118
|
+
⚠️ PASOS MANUALES REQUERIDOS:
|
|
119
|
+
|
|
120
|
+
1. Verificar que el proyecto GCP {PROJECT_ID} existe y tiene APIs habilitadas.
|
|
121
|
+
|
|
122
|
+
2. Ejecutar bootstrap si es la primera vez con este proyecto:
|
|
123
|
+
cd terraform/bootstrap
|
|
124
|
+
terraform apply -var="project_id={PROJECT_ID}"
|
|
125
|
+
|
|
126
|
+
3. Crear SA de deploy (si no existe):
|
|
127
|
+
gcloud iam service-accounts create {DEPLOY_SA} --project={PROJECT_ID}
|
|
128
|
+
|
|
129
|
+
4. Para cada servicio: crear el secret de conexión DB en el nuevo proyecto.
|
|
130
|
+
IMPORTANTE — verificar el nombre real del secret antes de codificarlo en el pipeline:
|
|
131
|
+
gcloud secrets list --project={PROJECT_ID} --filter="name:{AMBIENTE}"
|
|
132
|
+
Convención QA: prefijo corto (`baseconfig`, `tprt`, `acct`) no el nombre del servicio completo.
|
|
133
|
+
Crear si no existe:
|
|
134
|
+
gcloud secrets create {servicio-corto}-{AMBIENTE}-db-connection \
|
|
135
|
+
--project={PROJECT_ID} --data-file=-
|
|
136
|
+
|
|
137
|
+
5. Commit + merge a main → el pipeline infra-pipeline-{AMBIENTE}.yml se dispara (Terraform apply).
|
|
138
|
+
|
|
139
|
+
6. CRÍTICO — Instalar Dapr en el cluster (primera vez):
|
|
140
|
+
El job k8s-manifests salta cuando no hay cambios K8s. Para forzarlo:
|
|
141
|
+
gh workflow run infra-pipeline-{AMBIENTE}.yml --ref main
|
|
142
|
+
Sin esto, los deploys de servicios fallan con:
|
|
143
|
+
"no matches for kind Configuration in version dapr.io/v1alpha1"
|
|
144
|
+
|
|
145
|
+
7. Aplicar DDL de grants en el nuevo Cloud SQL para cada servicio:
|
|
146
|
+
/sa-onboard-db {schema} {owner-role}
|
|
147
|
+
```
|
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: sa-nuevo-servicio
|
|
3
|
+
description: 'Adds a new service to this transversal, generating every artifact needed in the deploy repo plus the CI/CD file ready to drop into the services own repo. Supports fullstack, backend-only, or frontend-only modes via flags. Use whenever the user wants to onboard a new service into the deploy infrastructure.'
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
> **Contexto de ejecución:** este skill asume que el cwd está dentro de la carpeta del workspace de despliegue (`_siesa-agents/devops/` en Siesa-Agents tras correr `/sa-init-devops`, o la raíz de un clon directo de `architecture-sa-devops`). Las rutas relativas (`environments/`, `terraform/`, `k8s/`, `scripts/`, etc.) se resuelven contra ese cwd.
|
|
7
|
+
|
|
8
|
+
Agrega un nuevo servicio a esta transversal. Genera todos los artefactos necesarios en el repo deploy y el archivo CI/CD listo para copiar al repo del servicio.
|
|
9
|
+
|
|
10
|
+
**Uso:** `/sa-nuevo-servicio {nombre} [api-port] [mfe-port] [--no-mfe] [--no-api]`
|
|
11
|
+
|
|
12
|
+
- Ambos puertos → servicio fullstack (backend + MFE)
|
|
13
|
+
- Solo `api-port` con `--no-mfe` → servicio backend puro (sin MFE)
|
|
14
|
+
- Solo `mfe-port` con `--no-api` → servicio frontend puro (sin API backend, ej: app-shell)
|
|
15
|
+
|
|
16
|
+
**Ejemplos:**
|
|
17
|
+
- `/sa-nuevo-servicio treasury 7022 8022` ← fullstack
|
|
18
|
+
- `/sa-nuevo-servicio payroll 7024 --no-mfe` ← backend puro
|
|
19
|
+
- `/sa-nuevo-servicio app-shell 8000 --no-api` ← frontend puro
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Instrucciones
|
|
24
|
+
|
|
25
|
+
Los argumentos son: `$ARGUMENTS`
|
|
26
|
+
|
|
27
|
+
### PRINCIPIO FUNDAMENTAL — El estándar siempre prevalece
|
|
28
|
+
|
|
29
|
+
**Cada artefacto generado por este flow SOBREESCRIBE lo que exista**, sin preguntar. Si el servicio ya existe parcialmente, sus artefactos se actualizan al estándar actual. Nada del estándar anterior se conserva por inercia.
|
|
30
|
+
|
|
31
|
+
- Archivos K8s → se sobreescriben con Write si difieren del template
|
|
32
|
+
- `environments/dev.yaml` y `environments/shared.yaml` → se actualizan si la entrada ya existe
|
|
33
|
+
- `ci-pipeline.yml` en el repo del servicio → se sobreescribe siempre con el template actual
|
|
34
|
+
- `cloudbuild-deploy.yaml` u otros artefactos del estándar anterior → se eliminan del repo del servicio si existen
|
|
35
|
+
|
|
36
|
+
La única excepción son acciones que puedan dejar un servicio sin desplegar en producción (como eliminar un deployment activo o borrar un secret en uso). En esos casos, sí se pregunta antes de actuar.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
Parsea los argumentos:
|
|
41
|
+
- Detecta flags primero: `HAS_MFE` = `false` si `--no-mfe` está presente, `true` en caso contrario. `HAS_API` = `false` si `--no-api` está presente, `true` en caso contrario.
|
|
42
|
+
- `NOMBRE` = primer argumento posicional (sin contar flags)
|
|
43
|
+
- Si `HAS_API = true` y `HAS_MFE = true`: `API_PORT` = segundo arg, `MFE_PORT` = tercer arg
|
|
44
|
+
- Si `HAS_API = true` y `HAS_MFE = false` (--no-mfe): `API_PORT` = segundo arg, `MFE_PORT` = vacío
|
|
45
|
+
- Si `HAS_API = false` y `HAS_MFE = true` (--no-api): `API_PORT` = vacío, `MFE_PORT` = segundo arg
|
|
46
|
+
|
|
47
|
+
Lee `environments/dev.yaml` para obtener:
|
|
48
|
+
- `PROJECT_ID` = `.gcp.project_id`
|
|
49
|
+
- `PROJECT_NUM` = `.gcp.project_number`
|
|
50
|
+
- `REGION` = `.gcp.region`
|
|
51
|
+
- `GATEWAY_NAME` = `.gateway.name`
|
|
52
|
+
- `SUITE` = `.naming.product_suite`
|
|
53
|
+
- `BUSINESS_UNIT` = `.naming.business_unit`
|
|
54
|
+
- `GKE_CLUSTER` = `.gke.cluster_name`
|
|
55
|
+
- `WORKER_POOL` = `.cloud_build.worker_pool`
|
|
56
|
+
|
|
57
|
+
Si `PROJECT_NUM` contiene `<PLACEHOLDER>` o está vacío, resuélvelo con Bash antes de continuar:
|
|
58
|
+
```bash
|
|
59
|
+
gcloud projects describe {PROJECT_ID} --format='value(projectNumber)'
|
|
60
|
+
```
|
|
61
|
+
Si el comando falla, detente y pide al usuario que complete `gcp.project_number` en `environments/dev.yaml`.
|
|
62
|
+
|
|
63
|
+
Lee `environments/shared.yaml` para obtener:
|
|
64
|
+
- `HUB_PROJECT` = `.hub.project_id` (Hub donde vive el Artifact Registry)
|
|
65
|
+
|
|
66
|
+
Calcula:
|
|
67
|
+
- `SA_SHORT` = `NOMBRE` con hyphens removidos, truncado a 10 caracteres (ej: `treasury` → `treasury`, `third-party` → `thirdparty`)
|
|
68
|
+
- `SA_NAME` = `sa-sie-{SUITE}-{SA_SHORT}-cicd`
|
|
69
|
+
- `GITHUB_REPO` = `SiesaTeams/business-{BUSINESS_UNIT}-{NOMBRE}-service`
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
### Fase A — Validación previa (ejecutar antes de generar artefactos)
|
|
74
|
+
|
|
75
|
+
#### A1 — API Guard: Habilitar APIs obligatorias
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
gcloud services enable \
|
|
79
|
+
container.googleapis.com \
|
|
80
|
+
sqladmin.googleapis.com \
|
|
81
|
+
pubsub.googleapis.com \
|
|
82
|
+
secretmanager.googleapis.com \
|
|
83
|
+
artifactregistry.googleapis.com \
|
|
84
|
+
iam.googleapis.com \
|
|
85
|
+
--project={PROJECT_ID}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Opcional según stack:
|
|
89
|
+
```bash
|
|
90
|
+
# Cloud Run (si aplica)
|
|
91
|
+
gcloud services enable run.googleapis.com --project={PROJECT_ID}
|
|
92
|
+
# Firestore
|
|
93
|
+
gcloud services enable firestore.googleapis.com --project={PROJECT_ID}
|
|
94
|
+
# Redis/Memorystore (PROD)
|
|
95
|
+
gcloud services enable redis.googleapis.com --project={PROJECT_ID}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
#### A2 — Workload Identity Binding
|
|
99
|
+
|
|
100
|
+
El SA `{SA_NAME}` y su binding WIF se crean automáticamente vía Terraform tras agregar el servicio a `environments/shared.yaml` y ejecutar `infra-pipeline-shared`. Verificar que existen antes del primer CI/CD:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
gcloud iam service-accounts describe {SA_NAME}@{PROJECT_ID}.iam.gserviceaccount.com \
|
|
104
|
+
--project={PROJECT_ID}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
Si falta el SA, es señal de que el pipeline `infra-pipeline-shared` no ha aplicado aún — no continuar hasta que esté aplicado.
|
|
108
|
+
|
|
109
|
+
#### A3 — Production-Ready Checklist
|
|
110
|
+
|
|
111
|
+
Verificar en el repo `{GITHUB_REPO}` antes de generar artefactos:
|
|
112
|
+
|
|
113
|
+
- [ ] **Secrets:** Solo Secret Manager. **PROHIBIDO** variables de entorno para datos sensibles. Usar `{NOMBRE}-dev-db-connection` (convención esta transversal) o `sec-sie-{NOMBRE}-dev-db` (estándar org).
|
|
114
|
+
- [ ] **Estructura K8s:** `k8s/base/` + `k8s/overlays/{env}/` presentes en el repo del servicio.
|
|
115
|
+
- [ ] **Migraciones:** Framework containerizado (EF Core `MigrateAsync`, Prisma, Liquibase). **PROHIBIDO** migraciones manuales o SQL suelto.
|
|
116
|
+
|
|
117
|
+
Si algún punto no se cumple, detener y coordinar con el equipo antes de continuar.
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
Luego genera los siguientes artefactos **en este orden**, creando o sobreescribiendo cada archivo con Write:
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
### Paso 1 — `k8s/overlays/dev/dapr/{NOMBRE}/pubsub.yaml`
|
|
126
|
+
|
|
127
|
+
```yaml
|
|
128
|
+
apiVersion: dapr.io/v1alpha1
|
|
129
|
+
kind: Component
|
|
130
|
+
metadata:
|
|
131
|
+
name: pubsub
|
|
132
|
+
namespace: {NOMBRE}
|
|
133
|
+
spec:
|
|
134
|
+
type: pubsub.gcp.pubsub
|
|
135
|
+
version: v1
|
|
136
|
+
metadata:
|
|
137
|
+
- name: projectId
|
|
138
|
+
value: {PROJECT_ID}
|
|
139
|
+
- name: disableEntityManagement
|
|
140
|
+
value: "true"
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Paso 2 — `k8s/overlays/dev/dapr/{NOMBRE}/secretstore.yaml`
|
|
144
|
+
|
|
145
|
+
```yaml
|
|
146
|
+
apiVersion: dapr.io/v1alpha1
|
|
147
|
+
kind: Component
|
|
148
|
+
metadata:
|
|
149
|
+
name: secretstore
|
|
150
|
+
namespace: {NOMBRE}
|
|
151
|
+
spec:
|
|
152
|
+
type: secretstores.gcp.secretmanager
|
|
153
|
+
version: v1
|
|
154
|
+
metadata:
|
|
155
|
+
- name: projectId
|
|
156
|
+
value: {PROJECT_ID}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Paso 3 — `k8s/overlays/dev/routes/{NOMBRE}-route.yaml`
|
|
160
|
+
|
|
161
|
+
El contenido del route depende de qué componentes tiene el servicio:
|
|
162
|
+
|
|
163
|
+
**Si HAS_API = true Y HAS_MFE = true (fullstack):**
|
|
164
|
+
```yaml
|
|
165
|
+
apiVersion: gateway.networking.k8s.io/v1
|
|
166
|
+
kind: HTTPRoute
|
|
167
|
+
metadata:
|
|
168
|
+
name: {NOMBRE}-route
|
|
169
|
+
namespace: {NOMBRE}
|
|
170
|
+
labels:
|
|
171
|
+
app.kubernetes.io/name: {NOMBRE}
|
|
172
|
+
app.kubernetes.io/part-of: {BUSINESS_UNIT}-platform
|
|
173
|
+
spec:
|
|
174
|
+
parentRefs:
|
|
175
|
+
- name: {GATEWAY_NAME}
|
|
176
|
+
namespace: gateway-infra
|
|
177
|
+
sectionName: https
|
|
178
|
+
rules:
|
|
179
|
+
- matches:
|
|
180
|
+
- path:
|
|
181
|
+
type: PathPrefix
|
|
182
|
+
value: /mfe/{NOMBRE}
|
|
183
|
+
filters:
|
|
184
|
+
- type: URLRewrite
|
|
185
|
+
urlRewrite:
|
|
186
|
+
path:
|
|
187
|
+
type: ReplacePrefixMatch
|
|
188
|
+
replacePrefixMatch: /
|
|
189
|
+
backendRefs:
|
|
190
|
+
- name: {NOMBRE}-mfe
|
|
191
|
+
port: 80
|
|
192
|
+
- matches:
|
|
193
|
+
- path:
|
|
194
|
+
type: PathPrefix
|
|
195
|
+
value: /api/{NOMBRE}/health
|
|
196
|
+
filters:
|
|
197
|
+
- type: URLRewrite
|
|
198
|
+
urlRewrite:
|
|
199
|
+
path:
|
|
200
|
+
type: ReplacePrefixMatch
|
|
201
|
+
replacePrefixMatch: /health
|
|
202
|
+
backendRefs:
|
|
203
|
+
- name: {NOMBRE}-api
|
|
204
|
+
port: 8080
|
|
205
|
+
- matches:
|
|
206
|
+
- path:
|
|
207
|
+
type: PathPrefix
|
|
208
|
+
value: /api/{NOMBRE}
|
|
209
|
+
filters:
|
|
210
|
+
- type: URLRewrite
|
|
211
|
+
urlRewrite:
|
|
212
|
+
path:
|
|
213
|
+
type: ReplacePrefixMatch
|
|
214
|
+
replacePrefixMatch: /api/v1
|
|
215
|
+
backendRefs:
|
|
216
|
+
- name: {NOMBRE}-api
|
|
217
|
+
port: 8080
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
**Si HAS_API = true Y HAS_MFE = false (backend puro, --no-mfe):**
|
|
221
|
+
Omitir el bloque de regla MFE (`/mfe/{NOMBRE}`). Incluir solo las dos reglas de `/api/{NOMBRE}`.
|
|
222
|
+
|
|
223
|
+
**Si HAS_API = false Y HAS_MFE = true (frontend puro, --no-api):**
|
|
224
|
+
Incluir solo la regla del MFE (`/mfe/{NOMBRE}`). Omitir las dos reglas de `/api/{NOMBRE}`.
|
|
225
|
+
|
|
226
|
+
### Paso 4 — `k8s/overlays/dev/healthcheck/{NOMBRE}-api-hc.yaml` (solo si HAS_API)
|
|
227
|
+
|
|
228
|
+
Generar este archivo únicamente si `HAS_API = true`.
|
|
229
|
+
|
|
230
|
+
```yaml
|
|
231
|
+
apiVersion: networking.gke.io/v1
|
|
232
|
+
kind: HealthCheckPolicy
|
|
233
|
+
metadata:
|
|
234
|
+
name: {NOMBRE}-api-hc
|
|
235
|
+
namespace: {NOMBRE}
|
|
236
|
+
spec:
|
|
237
|
+
default:
|
|
238
|
+
checkIntervalSec: 15
|
|
239
|
+
timeoutSec: 5
|
|
240
|
+
healthyThreshold: 1
|
|
241
|
+
unhealthyThreshold: 3
|
|
242
|
+
config:
|
|
243
|
+
type: TCP
|
|
244
|
+
tcpHealthCheck:
|
|
245
|
+
port: 8080
|
|
246
|
+
targetRef:
|
|
247
|
+
group: ""
|
|
248
|
+
kind: Service
|
|
249
|
+
name: {NOMBRE}-api
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Paso 5 — `k8s/overlays/dev/healthcheck/{NOMBRE}-mfe-hc.yaml` (solo si HAS_MFE)
|
|
253
|
+
|
|
254
|
+
```yaml
|
|
255
|
+
apiVersion: networking.gke.io/v1
|
|
256
|
+
kind: HealthCheckPolicy
|
|
257
|
+
metadata:
|
|
258
|
+
name: {NOMBRE}-mfe-hc
|
|
259
|
+
namespace: {NOMBRE}
|
|
260
|
+
spec:
|
|
261
|
+
default:
|
|
262
|
+
checkIntervalSec: 15
|
|
263
|
+
timeoutSec: 5
|
|
264
|
+
healthyThreshold: 1
|
|
265
|
+
unhealthyThreshold: 3
|
|
266
|
+
config:
|
|
267
|
+
type: TCP
|
|
268
|
+
tcpHealthCheck:
|
|
269
|
+
port: 80
|
|
270
|
+
targetRef:
|
|
271
|
+
group: ""
|
|
272
|
+
kind: Service
|
|
273
|
+
name: {NOMBRE}-mfe
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### Paso 6 — Actualizar `environments/dev.yaml`
|
|
277
|
+
|
|
278
|
+
Lee el archivo actual. Si ya existe la entrada para `{NOMBRE}` bajo `services:`, sobreescríbela con los valores calculados. Si no existe, agrégala. Mismo criterio para `namespaces:`.
|
|
279
|
+
|
|
280
|
+
```yaml
|
|
281
|
+
{NOMBRE}:
|
|
282
|
+
sa_name: {SA_NAME}
|
|
283
|
+
github_repo: {GITHUB_REPO}
|
|
284
|
+
description: "Docker images for {NOMBRE} service"
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Agrega `- {NOMBRE}` a la lista `namespaces:` si no está ya.
|
|
288
|
+
|
|
289
|
+
### Paso 7 — Actualizar `environments/shared.yaml`
|
|
290
|
+
|
|
291
|
+
Lee el archivo actual. Si ya existe la entrada para `{NOMBRE}` bajo `services:`, sobreescríbela con los valores calculados. Si no existe, agrégala.
|
|
292
|
+
|
|
293
|
+
```yaml
|
|
294
|
+
{NOMBRE}:
|
|
295
|
+
sa_name: {SA_NAME}
|
|
296
|
+
github_repo: {GITHUB_REPO}
|
|
297
|
+
description: "Docker images for {NOMBRE} service"
|
|
298
|
+
roles:
|
|
299
|
+
- roles/cloudbuild.builds.editor
|
|
300
|
+
- roles/artifactregistry.writer
|
|
301
|
+
- roles/container.developer
|
|
302
|
+
- roles/secretmanager.secretAccessor
|
|
303
|
+
- roles/cloudsql.client
|
|
304
|
+
- roles/cloudbuild.workerPoolUser
|
|
305
|
+
- roles/clouddeploy.releaser
|
|
306
|
+
- roles/iam.serviceAccountUser
|
|
307
|
+
- roles/storage.admin
|
|
308
|
+
- roles/pubsub.publisher
|
|
309
|
+
- roles/pubsub.subscriber
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### Paso 8 — Actualizar `k8s/overlays/dev/import-map/import-map.yaml` (solo si HAS_MFE)
|
|
313
|
+
|
|
314
|
+
Lee el archivo actual. Agrega al JSON de imports si no está ya:
|
|
315
|
+
```json
|
|
316
|
+
"@siesa/{NOMBRE}": "/mfe/{NOMBRE}/spa-entry.js"
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### Paso 9 — Generar y aplicar el CI/CD pipeline en el repo del servicio
|
|
320
|
+
|
|
321
|
+
**El pipeline se sobreescribe siempre. El estándar prevalece sobre cualquier pipeline anterior.**
|
|
322
|
+
|
|
323
|
+
#### 9a — Detectar estructura del repo del servicio
|
|
324
|
+
|
|
325
|
+
Calcula `LOCAL_REPO_PATH` = directorio padre de este repo + `/{GITHUB_REPO última parte}`.
|
|
326
|
+
- Ejemplo: deploy en `~/SiesaTeams/business-financiero-deploy` + `GITHUB_REPO = SiesaTeams/business-financiero-segments-service` → `LOCAL_REPO_PATH = ~/SiesaTeams/business-financiero-segments-service`
|
|
327
|
+
|
|
328
|
+
Si el repo no está clonado localmente, clónalo:
|
|
329
|
+
```bash
|
|
330
|
+
git clone https://github.com/{GITHUB_REPO}.git {LOCAL_REPO_PATH}
|
|
331
|
+
```
|
|
332
|
+
|
|
333
|
+
Detecta las rutas de Dockerfile ejecutando:
|
|
334
|
+
```bash
|
|
335
|
+
# API Dockerfile
|
|
336
|
+
if [ -f "{LOCAL_REPO_PATH}/api/Dockerfile" ]; then
|
|
337
|
+
echo "API_DOCKERFILE=api/Dockerfile"
|
|
338
|
+
echo "API_CONTEXT=api/"
|
|
339
|
+
elif [ -f "{LOCAL_REPO_PATH}/src/backend/Dockerfile" ]; then
|
|
340
|
+
echo "API_DOCKERFILE=src/backend/Dockerfile"
|
|
341
|
+
echo "API_CONTEXT=."
|
|
342
|
+
fi
|
|
343
|
+
|
|
344
|
+
# MFE Dockerfile
|
|
345
|
+
if [ -f "{LOCAL_REPO_PATH}/mfe/Dockerfile" ]; then
|
|
346
|
+
echo "MFE_DOCKERFILE=mfe/Dockerfile"
|
|
347
|
+
echo "MFE_CONTEXT=mfe/"
|
|
348
|
+
elif [ -f "{LOCAL_REPO_PATH}/src/frontend/Dockerfile" ]; then
|
|
349
|
+
echo "MFE_DOCKERFILE=src/frontend/Dockerfile"
|
|
350
|
+
echo "MFE_CONTEXT=src/frontend"
|
|
351
|
+
fi
|
|
352
|
+
|
|
353
|
+
# ¿Necesita build args de GitHub Packages?
|
|
354
|
+
grep -l "NUGET_GITHUB_TOKEN\|NPM_GITHUB_TOKEN" \
|
|
355
|
+
{LOCAL_REPO_PATH}/src/backend/Dockerfile \
|
|
356
|
+
{LOCAL_REPO_PATH}/api/Dockerfile \
|
|
357
|
+
{LOCAL_REPO_PATH}/src/frontend/Dockerfile \
|
|
358
|
+
{LOCAL_REPO_PATH}/mfe/Dockerfile 2>/dev/null && echo "NEEDS_GITHUB_PACKAGES=true"
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
Con estos valores, construye el pipeline adaptado.
|
|
362
|
+
|
|
363
|
+
#### 9b — Eliminar artefactos del estándar anterior
|
|
364
|
+
|
|
365
|
+
Si el repo del servicio tiene `cloudbuild-deploy.yaml` en la raíz, eliminarlo:
|
|
366
|
+
```bash
|
|
367
|
+
rm -f {LOCAL_REPO_PATH}/cloudbuild-deploy.yaml
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
Si tiene `cloudbuild-sandbox.yaml`, eliminarlo también:
|
|
371
|
+
```bash
|
|
372
|
+
rm -f {LOCAL_REPO_PATH}/cloudbuild-sandbox.yaml
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
#### 9c — Construir el pipeline estándar
|
|
376
|
+
|
|
377
|
+
Lee `cicd-templates/.github/workflows/ci-pipeline.yml` como base. Genera el pipeline final con:
|
|
378
|
+
|
|
379
|
+
1. **Sección `env:`** — siempre estos valores:
|
|
380
|
+
```yaml
|
|
381
|
+
env:
|
|
382
|
+
PROJECT_ID: {PROJECT_ID}
|
|
383
|
+
HUB_PROJECT_ID: {HUB_PROJECT}
|
|
384
|
+
PROJECT_NUM: "{PROJECT_NUM}"
|
|
385
|
+
REGION: {REGION}
|
|
386
|
+
GKE_CLUSTER: {GKE_CLUSTER}
|
|
387
|
+
WORKER_POOL: {WORKER_POOL}
|
|
388
|
+
SERVICE_NAME: {NOMBRE}
|
|
389
|
+
NAMESPACE: {NOMBRE}
|
|
390
|
+
BUILD_API: "{HAS_API}"
|
|
391
|
+
BUILD_MFE: "{HAS_MFE}"
|
|
392
|
+
VITE_MODE: development
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
2. **Sección `permissions:`** — siempre incluir `packages: read`:
|
|
396
|
+
```yaml
|
|
397
|
+
permissions:
|
|
398
|
+
contents: read
|
|
399
|
+
id-token: write
|
|
400
|
+
packages: read
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
3. **Paso "Build & Push API image"** — adaptar rutas según detección:
|
|
404
|
+
|
|
405
|
+
Si `API_DOCKERFILE = api/Dockerfile`:
|
|
406
|
+
```yaml
|
|
407
|
+
- name: Build & Push API image
|
|
408
|
+
if: env.BUILD_API == 'true'
|
|
409
|
+
run: |
|
|
410
|
+
IMAGE="${{ env.REGION }}-docker.pkg.dev/${{ env.HUB_PROJECT_ID }}/art-fin-shared/${{ env.SERVICE_NAME }}/${{ env.SERVICE_NAME }}-api"
|
|
411
|
+
docker build -t ${IMAGE}:${{ github.sha }} -f api/Dockerfile api/
|
|
412
|
+
docker push ${IMAGE}:${{ github.sha }}
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
Si `API_DOCKERFILE = src/backend/Dockerfile`:
|
|
416
|
+
```yaml
|
|
417
|
+
- name: Build & Push API image
|
|
418
|
+
if: env.BUILD_API == 'true'
|
|
419
|
+
run: |
|
|
420
|
+
IMAGE="${{ env.REGION }}-docker.pkg.dev/${{ env.HUB_PROJECT_ID }}/art-fin-shared/${{ env.SERVICE_NAME }}/${{ env.SERVICE_NAME }}-api"
|
|
421
|
+
docker build \
|
|
422
|
+
--build-arg NUGET_GITHUB_USER=x-access-token \
|
|
423
|
+
--build-arg NUGET_GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} \
|
|
424
|
+
-t ${IMAGE}:${{ github.sha }} \
|
|
425
|
+
-f src/backend/Dockerfile .
|
|
426
|
+
docker push ${IMAGE}:${{ github.sha }}
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
4. **Paso "Build & Push MFE image"** — adaptar rutas según detección:
|
|
430
|
+
|
|
431
|
+
Si `MFE_DOCKERFILE = mfe/Dockerfile`:
|
|
432
|
+
```yaml
|
|
433
|
+
- name: Build & Push MFE image
|
|
434
|
+
if: env.BUILD_MFE == 'true'
|
|
435
|
+
run: |
|
|
436
|
+
IMAGE="${{ env.REGION }}-docker.pkg.dev/${{ env.HUB_PROJECT_ID }}/art-fin-shared/${{ env.SERVICE_NAME }}/${{ env.SERVICE_NAME }}-mfe"
|
|
437
|
+
docker build \
|
|
438
|
+
--build-arg VITE_MODE=${{ env.VITE_MODE }} \
|
|
439
|
+
-t ${IMAGE}:${{ github.sha }} \
|
|
440
|
+
-f mfe/Dockerfile mfe/
|
|
441
|
+
docker push ${IMAGE}:${{ github.sha }}
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
Si `MFE_DOCKERFILE = src/frontend/Dockerfile`:
|
|
445
|
+
```yaml
|
|
446
|
+
- name: Build & Push MFE image
|
|
447
|
+
if: env.BUILD_MFE == 'true'
|
|
448
|
+
run: |
|
|
449
|
+
IMAGE="${{ env.REGION }}-docker.pkg.dev/${{ env.HUB_PROJECT_ID }}/art-fin-shared/${{ env.SERVICE_NAME }}/${{ env.SERVICE_NAME }}-mfe"
|
|
450
|
+
docker build \
|
|
451
|
+
--build-arg NPM_GITHUB_TOKEN=${{ secrets.GITHUB_TOKEN }} \
|
|
452
|
+
--build-arg VITE_MODE=${{ env.VITE_MODE }} \
|
|
453
|
+
-t ${IMAGE}:${{ github.sha }} \
|
|
454
|
+
-f src/frontend/Dockerfile src/frontend
|
|
455
|
+
docker push ${IMAGE}:${{ github.sha }}
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
5. El resto del pipeline (secciones Deploy via Cloud Build y Smoke test) se toma intacto del template.
|
|
459
|
+
|
|
460
|
+
Guarda el pipeline generado en `/tmp/ci-pipeline-{NOMBRE}.yml` y también en:
|
|
461
|
+
```
|
|
462
|
+
{LOCAL_REPO_PATH}/.github/workflows/ci-pipeline.yml
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
#### 9d — Commit y push al repo del servicio
|
|
466
|
+
|
|
467
|
+
```bash
|
|
468
|
+
cd {LOCAL_REPO_PATH}
|
|
469
|
+
git checkout develop
|
|
470
|
+
git add .github/workflows/ci-pipeline.yml
|
|
471
|
+
# Si se eliminaron artefactos del estándar anterior:
|
|
472
|
+
git add -u cloudbuild-deploy.yaml cloudbuild-sandbox.yaml 2>/dev/null || true
|
|
473
|
+
git commit -m "ci: migrar a pipeline estándar build & deploy DEV
|
|
474
|
+
|
|
475
|
+
- Imagen: Hub AR (prj-sie-sb-fin-common/art-fin-shared/{NOMBRE})
|
|
476
|
+
- Deploy: Cloud Build config inline (sin cloudbuild-deploy.yaml externo)
|
|
477
|
+
- Tag: SHA completo del commit"
|
|
478
|
+
git push origin develop
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
---
|
|
482
|
+
|
|
483
|
+
### Paso 10 — Mostrar resumen
|
|
484
|
+
|
|
485
|
+
```
|
|
486
|
+
✅ GENERADO/ACTUALIZADO AUTOMÁTICAMENTE:
|
|
487
|
+
k8s/overlays/dev/dapr/{NOMBRE}/pubsub.yaml
|
|
488
|
+
k8s/overlays/dev/dapr/{NOMBRE}/secretstore.yaml
|
|
489
|
+
k8s/overlays/dev/routes/{NOMBRE}-route.yaml
|
|
490
|
+
[k8s/overlays/dev/healthcheck/{NOMBRE}-api-hc.yaml] (si HAS_API)
|
|
491
|
+
[k8s/overlays/dev/healthcheck/{NOMBRE}-mfe-hc.yaml] (si HAS_MFE)
|
|
492
|
+
environments/dev.yaml ← service + namespace
|
|
493
|
+
environments/shared.yaml ← service + roles IAM
|
|
494
|
+
[k8s/overlays/dev/import-map/import-map.yaml] (si HAS_MFE)
|
|
495
|
+
{LOCAL_REPO_PATH}/.github/workflows/ci-pipeline.yml ← pipeline estándar aplicado
|
|
496
|
+
|
|
497
|
+
⚠️ PASOS MANUALES REQUERIDOS (en orden):
|
|
498
|
+
|
|
499
|
+
0. Ejecutar Fase A — Validación previa:
|
|
500
|
+
- API Guard: habilitar APIs en {PROJECT_ID}
|
|
501
|
+
- Confirmar WI Binding existente para {SA_NAME}
|
|
502
|
+
- Verificar Production-Ready checklist en {GITHUB_REPO}
|
|
503
|
+
|
|
504
|
+
1. Puertos locales — agregar en docs/developer-guide.md:
|
|
505
|
+
{NOMBRE}: [API {API_PORT}] (si HAS_API) / [MFE {MFE_PORT}] (si HAS_MFE)
|
|
506
|
+
|
|
507
|
+
[Si HAS_API = true]
|
|
508
|
+
2. Secret Manager — crear antes del primer CI/CD:
|
|
509
|
+
gcloud secrets create {NOMBRE}-dev-db-connection \
|
|
510
|
+
--project={PROJECT_ID} \
|
|
511
|
+
--data-file=<(echo "Host=127.0.0.1;Port=5432;Database=finance-dev;Username=dev;Password=CHANGE_ME")
|
|
512
|
+
|
|
513
|
+
⚠️ Naming: esta transversal usa `{NOMBRE}-dev-db-connection`.
|
|
514
|
+
Estándar org: `sec-sie-{NOMBRE}-dev-db`. Referenciar desde Secret Manager en
|
|
515
|
+
ambos casos — nunca pasar contraseñas como variable de entorno plana.
|
|
516
|
+
|
|
517
|
+
[Si HAS_API = true]
|
|
518
|
+
3. Cloud SQL — ejecutar DDL de grants (usar /sa-onboard-db {schema} {owner-role}):
|
|
519
|
+
Reemplaza {schema} con el nombre del schema PostgreSQL del servicio.
|
|
520
|
+
|
|
521
|
+
4. Registrar permisos en access-manager (usar /sa-registrar-permisos):
|
|
522
|
+
Después del primer deploy exitoso. Solo aplica si HAS_API = true.
|
|
523
|
+
|
|
524
|
+
5. Commit en este repo deploy + push a main → infra-pipeline-dev disparará automáticamente.
|
|
525
|
+
|
|
526
|
+
6. Artefactos inmutables — verificar en el pipeline:
|
|
527
|
+
- Docker images se etiquetan con el SHA completo del commit (inmutables por diseño).
|
|
528
|
+
- NUNCA re-buildear el mismo código para distintos ambientes.
|
|
529
|
+
- Para QAS/PROD: promover el digest existente de dev — no hacer nuevo build.
|
|
530
|
+
```
|