--- name: synapse_login_flows_check kind: function lang: go domain: infra version: "0.1.0" purity: impure signature: "func SynapseLoginFlowsCheck(cfg SynapseLoginFlowsCheckConfig) (SynapseLoginFlowsCheckResult, error)" description: "Verifica que el endpoint /_matrix/client/v3/login del homeserver Synapse devuelve m.login.sso con el IdP de MAS esperado y que m.login.password está desactivado. Hace polling con reintentos hasta confirmar el estado post-migración o agotar los intentos." tags: [matrix, mas, synapse, login, healthcheck, migration, mas-migration, infra, matrix-mas] params: - name: HomeserverURL desc: "URL pública del homeserver (ej. https://matrix-af2f3d.organic-machine.com). Sin trailing slash." - name: ExpectedSsoIdpID desc: "Identificador del IdP MAS esperado en m.login.sso.identity_providers[].id (ej. oidc-mas). Vacío = solo verificar que m.login.sso exista, sin comprobar IdP concreto." - name: MaxRetries desc: "Número máximo de intentos HTTP antes de abortar. Default: 10." - name: RetryDelaySeconds desc: "Segundos de espera entre intentos. Default: 3. Synapse tarda 10-30s en levantar tras restart." - name: HttpTimeoutSeconds desc: "Timeout HTTP por intento en segundos. Default: 5." output: "SynapseLoginFlowsCheckResult{Flows, SsoPresent, IdpFound, PasswordEnabled, LastResponseJSON, AttemptsUsed}. Error nil = migración confirmada. Error CONVERGENCE_FAILED = no convergió tras MaxRetries." uses_functions: [] uses_types: [] returns: [] returns_optional: false error_type: "error_go_core" imports: ["encoding/json", "fmt", "io", "net/http", "strings", "time"] tested: true tests: - "SSO + IdP expected -> success on first attempt" - "legacy response then SSO on 3rd attempt -> success after retries" - "response never changes -> error after maxRetries" - "HTTP timeout -> error" - "malformed JSON -> error" test_file_path: "functions/infra/synapse_login_flows_check_test.go" file_path: "functions/infra/synapse_login_flows_check.go" --- ## Ejemplo ```go cfg := SynapseLoginFlowsCheckConfig{ HomeserverURL: "https://matrix-af2f3d.organic-machine.com", ExpectedSsoIdpID: "oidc-mas", MaxRetries: 10, RetryDelaySeconds: 3, HttpTimeoutSeconds: 5, } res, err := SynapseLoginFlowsCheck(cfg) if err == nil && res.SsoPresent && !res.PasswordEnabled { fmt.Printf("MAS migration confirmed after %d attempt(s)\n", res.AttemptsUsed) // Continue with post-migration smoke tests } else if err != nil { fmt.Printf("Migration NOT confirmed: %s\n", err.Message) fmt.Printf("Last response: %s\n", res.LastResponseJSON) } ``` ## Cuando usarla Usar en el paso 6 del issue 0162 (migración Synapse→MAS), inmediatamente tras reiniciar Synapse con MSC3861 activado. También útil como `e2e_check` continuo en `app.md` del servicio Synapse para detectar regresiones (ej. alguien comenta `msc3861.enabled: true` por error y vuelve a activar password login). ```yaml # En app.md del servicio matrix: e2e_checks: - id: mas_login_flows cmd: "go run . -check-login-flows https://matrix-af2f3d.organic-machine.com oidc-mas" expect_stdout_contains: "MAS migration confirmed" timeout_s: 60 ``` ## Gotchas - **Synapse tarda 10-30s en levantar** tras restart — los defaults (MaxRetries=10, RetryDelaySeconds=3) cubren 30s de espera total. - **PasswordEnabled == true post-migración**: probablemente `password_config.enabled: false` no se aplicó en `homeserver.yaml` o fue sobreescrito por include. Verificar config antes de reintentar. - **IdP id incorrecto**: el id del IdP depende de `mas/config.yaml` → sección `matrix.homeserver`. Verificar el valor exacto con `GET /_matrix/client/v3/login` manual antes de pasar a `ExpectedSsoIdpID`. - **TLS no válido**: si el certificado del HomeserverURL no es verificable, `net/http` retorna error de TLS — la función lo propaga como FETCH_ERROR con el mensaje original de Go (no lo ignora silenciosamente). - **Non-200 responses**: cualquier status HTTP != 200 se trata como error de fetch y dispara reintento. - **ExpectedSsoIdpID vacío**: solo verifica presencia de `m.login.sso` y ausencia de `m.login.password`. Suficiente para validación rápida; usar el ID completo para health-check de producción.