Skip to content

fix!: convert legacy login_type=none users into service accounts#27182

Draft
jakehwll wants to merge 7 commits into
mainfrom
jakehwll/DEVEX-226-grandfather-legacy-login-type-none
Draft

fix!: convert legacy login_type=none users into service accounts#27182
jakehwll wants to merge 7 commits into
mainfrom
jakehwll/DEVEX-226-grandfather-legacy-login-type-none

Conversation

@jakehwll

@jakehwll jakehwll commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

🤖 This PR was modified by Coder Agents on behalf of Jake Howell.

Alternative to #26851 for DEVEX-226. These two PRs are mutually exclusive — only one should land; close the other.

⚠️ Breaking change

This migration blanks the email address of every converted user and is one-way / irreversible. Original emails are not recoverable. See rationale below.

What this does

Deprecates login_type=none in favour of premium service accounts, taking the convert-to-service-account path:

  • Existing users are converted — migration 000534_legacy_none_to_service_account sets is_service_account = true on legacy login_type='none' accounts (non-system) and blanks their email to satisfy the schema constraints. System users are left untouched.
  • Creation is gatedPOST /users and coder users create reject login_type=none (and the deprecated --disable-login) unless a service account is requested.

How it differs from #26851

This PR (convert to service account) #26851 (convert to password)
New login_type=none users blocked blocked
Existing login_type=none users become service accounts; email blanked become password users; email preserved
Reversible no (destructive, one-way) no (login_type origin not recorded)
DB migration 000534_legacy_none_to_service_account 000534_legacy_none_login_to_password

Both share the same creation-gating (cli/usercreate.go, coderd/users.go) and test updates (coderd/userauth_test.go, coderd/users_test.go).

Why the email must be blanked

Migration 000433_add_is_service_account_to_users enforces:

  • users_email_not_empty: (is_service_account = true) = (email = '') — service accounts must have an empty email.
  • users_service_account_login_type: is_service_account = false OR login_type = 'none' — satisfied, since these users are already login_type='none'.

The email uniqueness indexes were also redefined to exclude empty emails (WHERE deleted = false AND email != ''), so blanking multiple rows to '' does not cause unique-constraint conflicts. Converting these users to service accounts therefore requires clearing their email — hence the destructive, breaking nature of this PR.

Decision log
  • Goal: literally migrate existing login_type=none users onto the premium service-accounts feature ("Outcome 1"), not merely gate new creation.
  • Constraint discovered: the is_service_account CHECK constraints (migration 000433) require an empty email for service accounts. The email uniqueness indexes exclude empty emails, so blanking is safe from a uniqueness standpoint but destroys the original address.
  • Decision: accept the destructive email blanking as the cost of true service-account conversion, and document it as a breaking, irreversible migration. The down migration is a documented no-op.
  • Implementation: creation-gating in cli/usercreate.go and coderd/users.go, matching test updates, plus the 000534_legacy_none_to_service_account.{up,down}.sql migration.
  • Follow-up if this path is chosen: add upgrade notes warning operators that existing login_type=none users become service accounts and lose their stored email; advise exporting emails beforehand if needed.

Note: the branch name (...-grandfather-...) predates this change of approach; the PR now converts rather than grandfathers.

jakehwll added 5 commits June 30, 2026 04:08
Grandfather existing login_type='none' users instead of converting them.
The users_email_not_empty and users_service_account_login_type CHECK
constraints make flipping real users to is_service_account=true
infeasible without blanking emails, so leave existing accounts untouched
and gate only at creation time.
@linear-code

linear-code Bot commented Jul 13, 2026

Copy link
Copy Markdown

DEVEX-226

Convert existing non-system login_type='none' users into service accounts
(is_service_account=true). The users_email_not_empty CHECK constraint
(migration 000433) requires service accounts to have an empty email, so
this blanks the email of each converted user. This is a destructive,
breaking, one-way migration: original emails are not recoverable.
@jakehwll jakehwll changed the title fix!: gate login_type=none at creation, grandfather existing users fix!: convert legacy login_type=none users into service accounts Jul 13, 2026
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.

1 participant