--- name: wellknown_oidc_patch kind: function lang: go domain: infra version: "0.1.0" purity: impure signature: "func WellknownOidcPatch(cfg WellknownOidcPatchConfig) (WellknownOidcPatchResult, error)" description: "Parchea el JSON .well-known/matrix/client aniadiendo org.matrix.msc2965.authentication (MAS issuer + account URL) para que los clientes Matrix descubran el OIDC provider dinamicamente. Preserva todos los campos existentes (m.homeserver, org.matrix.msc4143.rtc_foci, etc.). Crea backup antes de escribir. Soporta DryRun." tags: ["matrix", "mas", "oidc", "well-known", "msc2965", "migration", "mas-migration", "infra", "matrix-mas"] uses_functions: [] uses_types: ["error_go_core"] returns: [] returns_optional: false error_type: "error_go_core" imports: ["encoding/json", "fmt", "os", "path/filepath", "time"] tested: true tests: - "patch adds key and preserves existing fields" - "idempotent: second call returns Modified=false" - "dry run does not write file" - "nonexistent file returns error" test_file_path: "functions/infra/wellknown_oidc_patch_test.go" file_path: "functions/infra/wellknown_oidc_patch.go" params: - name: WellknownJsonPath desc: "Ruta absoluta al archivo .well-known/matrix/client JSON (copiado del VPS antes de llamar; el operador copia de vuelta tras la llamada)" - name: Issuer desc: "URL del MAS issuer, DEBE terminar en '/' (RFC 8414). Ej: https://auth-af2f3d.organic-machine.com/" - name: AccountURL desc: "URL del account page del MAS. Ej: https://auth-af2f3d.organic-machine.com/account" - name: BackupDir desc: "Directorio donde se escribe wellknown_.json antes de modificar. Se crea con mkdir -p si no existe." - name: DryRun desc: "Si true, calcula Before/After y Modified pero no escribe ningun archivo ni crea backup." output: "WellknownOidcPatchResult con BackupPath (vacio en DryRun/no-op), Before y After JSON pretty-printed, y Modified=false si el valor ya era identico." --- ## Ejemplo ```go cfg := infra.WellknownOidcPatchConfig{ WellknownJsonPath: "/tmp/wellknown_client.json", Issuer: "https://auth-af2f3d.organic-machine.com/", AccountURL: "https://auth-af2f3d.organic-machine.com/account", BackupDir: "/tmp/wellknown_backups", DryRun: true, } res, err := infra.WellknownOidcPatch(cfg) if err != nil { log.Fatal(err) } fmt.Println("Modified:", res.Modified) fmt.Println("After:\n", res.After) // Si el resultado es correcto, volver a llamar con DryRun: false para escribir. ``` ## Cuando usarla Paso 5 de la migracion 0162 (Synapse → MAS): antes de hacer hot-reload nginx del container `wellknown`. Tambien util si cambia el issuer MAS en el futuro (basta llamarla de nuevo con el nuevo URL — la idempotencia garantiza que no duplica la clave). ## Gotchas - **Issuer DEBE terminar en `/`**: los clientes Matrix siguen RFC 8414 estrictamente. Un issuer sin `/` final causa fallos de descubrimiento silenciosos. - **Usar mapa dinamico, no struct**: la funcion parsea el JSON en `map[string]any` para preservar campos desconocidos. No asumir que el archivo solo tiene `m.homeserver`. - **Tras escribir, recargar nginx**: `ssh docker exec nginx -s reload`. Esta funcion no lo hace — es responsabilidad del operador. - **Synapse tambien puede servir el well-known**: `/_matrix/client/.well-known` puede provenir de Synapse ademas del container wellknown. Verificar con `curl -s https://matrix.organic-machine.com/.well-known/matrix/client` y `curl -s https://matrix.organic-machine.com/_matrix/client/.well-known/matrix/client` para saber cual usa cada cliente. - **DryRun no crea backup ni BackupDir**: usar DryRun para verificar el diff antes de ejecutar en produccion.