@ingeniomaps/cauce 0.78.0 → 0.80.0
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/CHANGELOG.md +119 -0
- package/README.md +6 -3
- package/automatization/hooks/README.md +18 -2
- package/automatization/hooks/guard-secrets-read.sh +3 -0
- package/automatization/runners/claude/README.md +3 -1
- package/automatization/runners/claude/settings.json +29 -0
- package/automatization/runners/gemini/README.md +2 -1
- package/automatization/runners/gemini/settings.json +9 -0
- package/automatization/workflows/autobuild.js +21 -10
- package/engine/cli/args.js +1 -0
- package/engine/cli/bootstrap.js +1 -1
- package/engine/cli/ops.js +9 -5
- package/engine/cli/wiring.js +21 -3
- package/engine/config/paths.js +5 -3
- package/engine/hooks/approval.js +8 -4
- package/engine/hooks/files.js +104 -27
- package/engine/hooks/run.js +7 -0
- package/engine/hooks/shell.js +34 -17
- package/engine/integrations/providers/jira.js +1 -1
- package/engine/integrations/registry.js +28 -5
- package/engine/secrets/index.js +201 -0
- package/package.json +1 -1
- package/template/AGENTS.md +1 -0
- package/template/integrations/README.md +21 -0
- package/template/organization/README.md +52 -0
- package/template/planning/adr/README.md +1 -0
- package/template/planning/adr/system/OPS-007-contrato-de-secretos-compartido.md +62 -0
|
@@ -22,3 +22,24 @@ node tools/ops.js integration promote . jira KEY-123
|
|
|
22
22
|
El motor compara base reconciliada, remoto actual y curación local. Usa `reset` para adoptar el remoto,
|
|
23
23
|
`reconcile` para conservar la edición local sobre la nueva base y `rebase` para reparar hashes mecánicos.
|
|
24
24
|
Ninguno de esos comandos escribe en el proveedor.
|
|
25
|
+
|
|
26
|
+
## Un proveedor propio
|
|
27
|
+
|
|
28
|
+
Cauce trae Jira. Para conectar otra herramienta, el adaptador se escribe acá, en la instancia, sin tocar
|
|
29
|
+
Cauce:
|
|
30
|
+
|
|
31
|
+
1. Crear `integrations/<nombre>/` con su `config.json` y el adaptador, por ejemplo `adapter.js`.
|
|
32
|
+
2. Registrarlo en `config.json` con la ruta, relativa a `integrations/<nombre>/`:
|
|
33
|
+
`"adapter": "./adapter.js"`. Un nombre sin `./` —`"jira"`— es un adaptador de Cauce.
|
|
34
|
+
3. `node tools/ops.js integration enable . <nombre>` lo conecta y `integration check .` lo valida.
|
|
35
|
+
|
|
36
|
+
El adaptador exporta `contract: 1` y tres funciones:
|
|
37
|
+
|
|
38
|
+
- `validateConfig(config, errors)` valida sin conectarse, y empuja a `errors` lo que impide correr.
|
|
39
|
+
- `fetchItems(config, options)` hace la lectura paginada completa del proveedor.
|
|
40
|
+
- `normalizeFixture(payload, config)` usa el mismo normalizador sin red, para pruebas e importaciones.
|
|
41
|
+
|
|
42
|
+
`check` rechaza un adaptador con otra versión o sin alguna de las funciones, y una ruta que salga de
|
|
43
|
+
`integrations/<nombre>/`. Puede ser CommonJS o ESM. El motor lo ejecuta con los mismos permisos que el
|
|
44
|
+
CLI: la contención es de ruta, no de capacidad. Staging, revisión, promoción y validación son los mismos
|
|
45
|
+
que para Jira; el adaptador sólo traduce la API del proveedor.
|
|
@@ -18,4 +18,56 @@ Recomendados, sin molde: escribilos con la forma que le sirva a este proyecto.
|
|
|
18
18
|
La lista no es cerrada. Todo hecho de negocio o producto que cambie lentamente vive acá —una guía de
|
|
19
19
|
marca, un manual de operación, un pipeline de contenido— aunque no tenga una línea propia arriba.
|
|
20
20
|
|
|
21
|
+
Opcional, con forma fija: `secrets.json`, el contrato de secretos que la empresa comparte entre sus
|
|
22
|
+
repositorios. Ver «Secretos compartidos» abajo.
|
|
23
|
+
|
|
21
24
|
Principio: cada hecho tiene un dueño. Enlaza en vez de copiar información que ya vive en otro lugar.
|
|
25
|
+
|
|
26
|
+
## Secretos compartidos
|
|
27
|
+
|
|
28
|
+
Cuando varios servicios usan el mismo gestor de secretos —Infisical, Vault, Doppler—, terminan con los
|
|
29
|
+
mismos scripts y workflows copiados en cada repositorio, y la copia que se quedó atrás no avisa.
|
|
30
|
+
`secrets.json` declara ese contrato una vez y `node tools/ops.js secrets check .` lo compara contra cada
|
|
31
|
+
servicio **sin conectarse a nada**. Cauce no conoce ningún gestor: lo que habla con él es de la empresa.
|
|
32
|
+
|
|
33
|
+
```json
|
|
34
|
+
{
|
|
35
|
+
"schemaVersion": 1,
|
|
36
|
+
"accounts": { "principal": { "url": "https://app.infisical.com" } },
|
|
37
|
+
"projects": { "tienda": { "account": "principal" } },
|
|
38
|
+
"identities": {
|
|
39
|
+
"local-dev": { "account": "principal", "source": "file", "file": "~/.config/acme/local-dev.env" },
|
|
40
|
+
"ci": { "account": "principal", "source": "ci-secret" }
|
|
41
|
+
},
|
|
42
|
+
"shared": { "check-schema": "organization/secrets/check-schema.py" },
|
|
43
|
+
"services": {
|
|
44
|
+
"api": { "root": "api", "project": "tienda", "identity": "local-dev",
|
|
45
|
+
"files": { "scripts/check-schema.py": "check-schema" } }
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
- **Nunca guarda un valor.** Una clave con forma de secreto —`token`, `password`, `secret`— es un error.
|
|
51
|
+
Las entradas pueden llevar otros campos que lean los scripts de la empresa (un id de proyecto, sus
|
|
52
|
+
ambientes); el chequeo no los mira.
|
|
53
|
+
- **Una identidad por nivel de acceso, no por repositorio.** Compartir credenciales es apuntar al mismo
|
|
54
|
+
alias, y rotar es cambiar un archivo. `source: file` es un archivo **fuera de todo repositorio**, que
|
|
55
|
+
carga una persona; `source: ci-secret` vive en el CI y no lleva ruta.
|
|
56
|
+
- **`shared` guarda la copia canónica** de cada archivo compartido, dentro de esta instancia, y
|
|
57
|
+
`services.<nombre>.files` dice dónde va en el servicio. Cada `root` es una raíz de `ops.config.json`.
|
|
58
|
+
- **Varios proyectos, una instancia.** El chequeo compara los servicios de esta instancia; para que el
|
|
59
|
+
esqueleto de un proyecto y los servicios de otro se midan contra lo mismo, los dos van como raíces acá.
|
|
60
|
+
|
|
61
|
+
`secrets check` falla si una copia no coincide con la canónica —y dice el `cp` que la pone al día—, si
|
|
62
|
+
falta, si una referencia no cierra o si una credencial está dentro de un repositorio. Una identidad que
|
|
63
|
+
no está en esta máquina es una advertencia: en el CI no tiene por qué estar.
|
|
64
|
+
|
|
65
|
+
El recorrido:
|
|
66
|
+
|
|
67
|
+
- **Adoptar un servicio**: declararlo, copiar los archivos de `shared` y correr `secrets check`. Cargar
|
|
68
|
+
la identidad en su archivo y los secretos del CI lo hace una persona: el guard de secretos frena que
|
|
69
|
+
un agente escriba un `.env.*`, y es lo correcto.
|
|
70
|
+
- **Mantener**: se cambia la copia canónica, `secrets check` lista los servicios que quedaron atrás y
|
|
71
|
+
cada uno se actualiza con un commit en su repositorio.
|
|
72
|
+
- **Rotar**: se reemplaza el archivo de la identidad; los servicios que la usan no cambian.
|
|
73
|
+
- **Dar de baja**: se saca el servicio de `services` y se borran sus copias en su repositorio.
|
|
@@ -47,3 +47,4 @@ archivo lo mantiene Cauce, así que una fila agregada acá se perdería en el pr
|
|
|
47
47
|
- [OPS-004](system/OPS-004-promocion-humana-y-evidencia-verificable.md): promoción controlada y verificable.
|
|
48
48
|
- [OPS-005](system/OPS-005-catalogo-en-el-paquete.md): el catálogo viaja dentro del paquete.
|
|
49
49
|
- [OPS-006](system/OPS-006-ceremonia-por-superficie.md): la ceremonia escala con la superficie del cambio.
|
|
50
|
+
- [OPS-007](system/OPS-007-contrato-de-secretos-compartido.md): un contrato de secretos compartido, sin gestor.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# OPS-007 — Un contrato de secretos compartido, sin conocer ningún gestor
|
|
2
|
+
|
|
3
|
+
**Estado:** Aceptado
|
|
4
|
+
**Fecha:** 2026-09-10
|
|
5
|
+
|
|
6
|
+
> Decide qué parte del manejo de secretos es de la base; el gestor, sus scripts y su CI siguen siendo de
|
|
7
|
+
> la empresa.
|
|
8
|
+
|
|
9
|
+
## Contexto
|
|
10
|
+
|
|
11
|
+
Una empresa que adopta un gestor de secretos termina con el mismo modelo copiado en cada repositorio:
|
|
12
|
+
la identidad con que se lee el gestor, un script que compara el gestor contra el contrato de variables y
|
|
13
|
+
los workflows que avisan en el PR. Nada dice qué servicio usa qué cuenta ni qué identidad, y nada detecta
|
|
14
|
+
que una copia se quedó atrás. En una instancia real se contaron dieciséis copias de un mismo script en
|
|
15
|
+
tres variantes, y el arreglo que tenía una sola no había llegado ni al esqueleto del que salen los
|
|
16
|
+
servicios nuevos.
|
|
17
|
+
|
|
18
|
+
`integrations/` no sirve para esto: su ciclo es de contenido de trabajo que baja a planning (OPS-003), y
|
|
19
|
+
su README prohíbe guardar secretos ahí.
|
|
20
|
+
|
|
21
|
+
## Decisión
|
|
22
|
+
|
|
23
|
+
**La base declara y compara; no se conecta, no genera y no conoce ningún gestor.**
|
|
24
|
+
|
|
25
|
+
- La declaración vive en `organization/secrets.json`, que es del proyecto: cuentas, proyectos,
|
|
26
|
+
identidades, servicios y los archivos que comparten. Nunca un valor: una clave con forma de secreto es
|
|
27
|
+
un error.
|
|
28
|
+
- Una identidad es un nivel de acceso, no un repositorio. `source: file` es un archivo **fuera de todo
|
|
29
|
+
repositorio**, que carga una persona; `source: ci-secret` vive en el CI.
|
|
30
|
+
- La copia canónica de cada archivo compartido vive en la instancia. `ops secrets check` compara cada
|
|
31
|
+
copia de cada servicio contra ella por hash, sin red, y dice el `cp` que la pone al día. Cauce no
|
|
32
|
+
escribe en los repositorios de producto.
|
|
33
|
+
- El chequeo compara los servicios de una instancia. Una empresa con varios proyectos los declara como
|
|
34
|
+
raíces de la misma instancia, que es lo que hace que un esqueleto y sus derivados se midan contra lo
|
|
35
|
+
mismo.
|
|
36
|
+
|
|
37
|
+
## Alternativas consideradas
|
|
38
|
+
|
|
39
|
+
- **Un adaptador de la empresa que genere los archivos**: flexible, pero obliga al motor a cargar código
|
|
40
|
+
de la instancia y a versionar una interfaz, para resolver lo mismo que una copia comparada por hash.
|
|
41
|
+
- **El adaptador como paquete versionado que cada instancia instala**: mantiene una instancia por
|
|
42
|
+
proyecto a cambio de publicar y versionar un paquete más.
|
|
43
|
+
- **Un workflow reutilizable compartido**: una sola copia, pero supone GitHub y una organización, y deja
|
|
44
|
+
a la base atada a un proveedor de CI.
|
|
45
|
+
- **Hacerlo un proveedor de `integrations/`**: su staging, reconciliación y promoción no se aplican a
|
|
46
|
+
secretos.
|
|
47
|
+
|
|
48
|
+
## Consecuencias
|
|
49
|
+
|
|
50
|
+
**Ganamos:** la copia que se quedó atrás se ve, con su arreglo al lado; rotar una identidad compartida
|
|
51
|
+
es cambiar un archivo; y la base sigue sin saber de ningún gestor.
|
|
52
|
+
|
|
53
|
+
**Costos que aceptamos:** un arreglo sigue siendo un commit por repositorio —el chequeo los lista, no los
|
|
54
|
+
aplica—. Juntar varios proyectos en una instancia comparte también su `planning/`. Y una credencial
|
|
55
|
+
dentro de un repositorio es un error aunque esté ignorada por git: es la copia por repositorio que esta
|
|
56
|
+
decisión viene a sacar.
|
|
57
|
+
|
|
58
|
+
## Estado de implementación
|
|
59
|
+
|
|
60
|
+
Implementado en 0.80.0: `organization/secrets.json`, `ops secrets check` y el recorrido documentado en
|
|
61
|
+
`organization/README.md`. Cauce no trae adaptadores ni un workflow de ejemplo que corra el chequeo en CI;
|
|
62
|
+
correrlo ahí es un paso de la empresa.
|