Skip to content

feat(users): site setting to disable self-service username changes (#298) - #299

Merged
tbcsec merged 1 commit into
mainfrom
feat/username-change-toggle
Aug 24, 2026
Merged

feat(users): site setting to disable self-service username changes (#298)#299
tbcsec merged 1 commit into
mainfrom
feat/username-change-toggle

Conversation

@tbcsec

@tbcsec tbcsec commented Aug 24, 2026

Copy link
Copy Markdown
Owner

Summary

Closes #298 — the first v1.6.0 issue. Adds a global operational setting,
username_changes_enabled (default on), so deployments with
provisioned names (schools, corporate events) can pin usernames to what
was issued.

Behaviour

  • Off gates only the self-service path: POST /api/auth/change-username
    returns 403 ("Username changes are disabled on this platform"). The
    gate sits before password verification, so a disabled endpoint never
    acts as a password oracle; the per-request throttle still applies first.
  • Admin rename is unaffectedmanage_users holders keep renaming
    from Admin → Users. That's the provisioning path the setting protects.
  • The toggle lives on Admin → Site settings → General
    (manage_site_settings), rides the existing operational PUT, and emits
    the existing site.settings_updated audit event.
  • Omitted-in-PUT = unchanged, following the update_checks_enabled
    contract: a scripted whole-object PUT that omits the field can't
    silently re-enable a feature an admin turned off.
  • Exposed on the public GET /api/site-settings (like
    registration_open), so the profile page hides its username card with
    no extra request. While hidden, the cooldown mechanics of feat(users): self-service username change — cooldown, admin rename, audited #284 are
    untouched for when it's re-enabled.

Implementation

  • SiteSettings.username_changes_enabled + one migration
    (server_default TRUE — verified against real Postgres via the dev
    stack: d1a6b83f47c2 → e7b2c94a63d1 applied cleanly).
  • SiteSettingsOut (public) / OperationalSettingsOut /
    OperationalSettingsUpdate (nullable, omission-safe) + PUT wiring.
  • Frontend: SiteSettings/OperationalSettings types +
    FALLBACK_SETTINGS, a General-tab On/Off card (strings born
    extracted
    into admin.settings, ADR-0029, es/fr/pl synced), and
    username-card.tsx returning null when the flag is off.

Tests

  • Backend: 403 + gate-before-password ordering (wrong password while
    disabled is still 403), admin rename while disabled, re-enable restores
    self-service, public exposure + operational round-trip + omission
    semantics. The public-payload exact key-set tests updated for the new
    field.
  • Frontend: new card-hidden-when-disabled case (component renders nothing).

Verification

  • Backend: full pytest1122 passed
  • Frontend: tsc clean, eslint clean, vitest 373 passed,
    npm run build succeeds (Y.js singleton check passes)
  • Live E2E against the dev stack: default true → admin disables →
    public reflects false → participant rename 403s with the right detail →
    admin rename 200s → restored to default.

Note: one unrelated full-suite run hung at 98% CPU near the audit-log
tests and would not reproduce (solo and prefix runs green, and this
plumbing passed CI 7× today). Flagged separately for investigation rather
than papered over here.

🤖 Generated with Claude Code

)

Adds `username_changes_enabled` (default on) so deployments with
provisioned names can pin usernames to what was issued:

- Off gates only the self-service path: POST /api/auth/change-username
  403s, checked before the password verification so a disabled endpoint
  never acts as a password oracle. An admin rename (manage_users, Admin →
  Users) is deliberately unaffected — it's the provisioning path this
  setting exists to protect.
- The toggle lives on Admin → Site settings → General (manage_site_settings)
  and rides the existing operational PUT, emitting site.settings_updated.
  Omitted-in-PUT = unchanged, the update_checks_enabled contract — a
  scripted whole-object PUT must not silently re-enable it.
- Exposed on the public GET /api/site-settings (like registration_open),
  so the profile page hides its username card with no extra request.
- One migration, server_default TRUE (verified against real Postgres);
  new admin strings born extracted (ADR-0029), es/fr/pl synced.

Tests: 403 + gate-before-password ordering, admin rename while disabled,
re-enable restores, public exposure + operational round-trip + omission
semantics; frontend card-hidden case. Full suites green (backend 1122,
frontend 373), plus a live E2E against the dev stack.

Closes #298

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@tbcsec
tbcsec merged commit 9099743 into main Aug 24, 2026
4 checks passed
@tbcsec
tbcsec deleted the feat/username-change-toggle branch August 24, 2026 12:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature]: site setting to disable self-service username changes

1 participant