gh_UserManager/docs/CUTOVER_RUNBOOK.md
bermooda-company 1f995295a6 last changes
2026-10-22 16:58:51 +03:30

5.3 KiB

Cutover Runbook — bermooda_usermanager → UserManager (IdP)

Operational steps for cutting Hamsoo over to UserManager as the identity provider, and for rolling back if verification fails. Every gate below has a command; do not advance while a gate is red.

1. Preconditions (all must be green)

Gate Command Required result
Hamsoo suite manage.py test --noinput (in hamsoo_backend) OK (1 documented skip)
UserManager suite manage.py test --noinput (in apps/api) OK
Migration drift manage.py makemigrations --check (in apps/api) No changes detected
Export python apps/identity/migration/export_identity_dump.py --db-name <legacy-db> --output dump.json counts match the legacy tables
Import dry-run manage.py import_legacy_identity <dump> --report import_report.json has_problems: false, exit 0, 0 collisions
Phone OTP covered by manage.py test apps.sms (43 tests) OK
Shadow divergence Hamsoo: manage.py auth_divergence_report blocking = 0

Export notes:

  • The exporter reads MySQL directly (authmanager_useraccount, workspacemanager_workspace, workspacemanager_workspacemember) and needs no Django. It runs with any Python that has pymysql or mysqlclient; in a venv without a driver it falls back to the machine's global CPython 3.12 site-packages (mysqlclient).
  • Connection settings: --db-host/--db-port/--db-name/--db-user/--db-password or LEGACY_DB_* environment variables. No password default.
  • Rehearsal source on this machine: auth_staging_new_2 (144 users / 198 workspaces / 0 members — verified against the 10-11 dump). Point --db-name at the production legacy database for the real cutover.

2. Production environment

UserManager (apps/api)

Variable Value Notes
DJANGO_ENV production boot refuses dev defaults
DJANGO_SECRET_KEY secret
JWT_SIGNING_KEY secret (≥32 bytes) boot fails on dev default
OIDC_ISSUER https://<idp-host> embedded in iss; must match what clients validate
SSO_COOKIE_DOMAIN .hamsoo.me parent-domain cookie for SSO
SSO_TRUSTED_REDIRECT_HOSTS hamsoo.me,www.hamsoo.me post-login allow-list
SMS_PROVIDER kavenegar boot refuses console in production
KAVENEGAR_API_KEY / KAVENEGAR_SENDER secret / sender id
EMAIL_FROM_ADDRESS no-reply domain address
MAIL_DOMAIN, MAIL_INBOUND_SECRET mailbox domain + secret
MEDIA_ROOT persistent volume mailbox uploads
DJANGO_ALLOWED_HOSTS, CORS_ALLOWED_ORIGINS, CSRF_TRUSTED_ORIGINS IdP host + https://hamsoo.me

Hamsoo backend (hamsoo_backend)

Variable Value Notes
IS_PRODUCTION 1
IDENTITY_PLATFORM_BASE_URL https://<idp-host>
IDENTITY_PLATFORM_ISSUER same as OIDC_ISSUER iss validation
IDENTITY_PLATFORM_CLIENT_ID / CLIENT_SECRET secret BFF-only; never expose to the browser
IDENTITY_PLATFORM_REDIRECT_URI https://hamsoo.me/sso/callback registered in the hamsoo OAuth client
IDENTITY_PLATFORM_JWKS_URL / AUDIENCE JWKS endpoint / audience
SSO_FRONTEND_BASE_URL https://hamsoo.me

3. Cutover sequence

  1. Freeze writes to the legacy usermanager (announce maintenance window).
  2. Export the legacy database → fresh dump (schema_version 1).
  3. Dry-run import_legacy_identity <dump> --report import_report.json; confirm has_problems: false and zero phone/username/email collisions.
  4. Backup the UserManager database (mysqldump/snapshot).
  5. Apply import_legacy_identity <dump> --apply --report import_report.json. The import is idempotent — re-running only updates, never duplicates.
  6. Verify counts from the report (users / organizations / memberships / profiles match the dry-run numbers exactly).
  7. Phone OTP spot-check: sign in with a migrated number, receive + verify a code, receive access + refresh tokens.
  8. Switch traffic: point Hamsoo at the IdP env (section 2), deploy hamsoo_backend + frontend, enable the SSO login path.
  9. Watch manage.py auth_divergence_report during the window — every blocking row is a session that would break; target is 0 before full traffic.

4. Rollback

Roll back before the legacy service is decommissioned — the legacy database is the restore point for the whole window.

  1. Stop the SSO login path in Hamsoo (feature flag / previous frontend build).
  2. Re-point Hamsoo auth config to the previous identity service (previous env values + previous deployment).
  3. Restore UserManager DB from the step-4 backup if it was mutated (the import only added rows; restoring removes them cleanly).
  4. Confirm: legacy login works, auth_divergence_report shows no new blocking rows for the rolled-back path.
  5. Keep the dump + import_report.json artifacts for the next attempt.

Rolling back does not lose data as long as the legacy database was frozen only for the window and un-frozen at step 1 of rollback.

5. After cutover (deferred, needs explicit approval)

  • Remove bermooda_usermanager code/tables and the shadow tables.
  • Rewrite git history for the RSA key committed in 54d5891 (rotate first).
  • Normalize legacy phone numbers (normalize_phones backfill).
  • Decommission the legacy service.