--- title: "1.29.2 — Immediate account closure and the fleet operator tool" description: "Adds immediate in-app account closure for a signed-in session with Sign in with Apple token revocation, erases every credential and sign-in link when an account closes, and ships an operator tool for surgical config edits, health-gated rolling restarts and node/database health." date: "2026-09-21" tags: ["release"] canonical: "https://django-mojo.sitesmojo.com/changelog/1-29-2/" --- Adds immediate in-app account closure for a signed-in session with Sign in with Apple token revocation, erases every credential and sign-in link when an account closes, and ships an operator tool for surgical config edits, health-gated rolling restarts and node/database health. ### Added - `POST /api/account/close` closes the caller's account at once, for a person confirming the action inside an app. Password accounts send `current_password`; passwordless accounts need a session whose `auth_time` is within `ACCOUNT_CLOSE_REAUTH_WINDOW` (default 600 seconds), enforced even when `FRESH_AUTH_ENFORCE` is off. Only an interactive user session may call it: user API keys, group API keys, group tokens and OAuth grant tokens are rejected. - Sign in with Apple token revocation on closure. Refresh tokens from active Apple connections are collected before local rows are removed and revoked with Apple only after the local erasure has landed. A remote failure is recorded as `account:apple_revoke_failed` and never undoes a completed erasure. - `ACCOUNT_CLOSE_REAUTH_WINDOW` setting (integer seconds, default 600). - `python3 -m mojo.deploy.fleet`, an operator-side tool for incidents: `config keys|get|set|versions|rollback` edit the canonical `django.conf` in S3 by dotted path without re-rendering it (parse-proven, redacted diff, mode-0600 rollback copy, sha256 metadata); `sync` rolls nodes one at a time behind an ASGI and loopback health gate with every config-sync timer held; `nodes status`, `db connections`, `db instance` and `errors` are read-only. Wired by `aws/fleet.json`; credentials come from `var/django.conf` or the ambient AWS chain and are never printed. ### Changed - Account closure, through the email-confirmed flow and the new endpoint alike, now also deletes passkeys, registered push devices, TOTP secrets, OAuth connections, per-user API keys, OAuth grants and authorization codes, detaches reference-mode group API keys, and disables and detaches identity-override group API keys. After closure a passkey login fails with the same generic error as an unknown passkey. - `pii_anonymize()` deletes group memberships last. A product closure handler that reaches data through memberships must still purge it before the framework does. ### Fixed - Closing an account left the person's social sign-in links, machine keys and OAuth grants in place, still carrying their real email. ### Upgrade notes - No migration. The new endpoint shares the `ALLOW_SELF_DEACTIVATION` switch, the `account:deactivated` incident and the five-per-five-minutes IP limit with the email flow; a wrong password also spends the normal per-account login attempt budget. - Only `config set`, `config rollback` and `sync` in the fleet tool change anything; `config set` refuses to add keys and `--dry-run` does everything but the write.