Skip to content

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

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

fix!: convert legacy login_type=none users into service accounts#27182
jakehwll wants to merge 14 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 000544_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 000544_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 000544_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
@jakehwll
jakehwll marked this pull request as ready for review July 16, 2026 10:22
@github-actions github-actions Bot added the release/breaking This label is applied to PRs to detect breaking changes as part of the release process label Jul 16, 2026
@coderagents

coderagents Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Documentation Check

This PR deprecates login_type=none in favor of Premium service accounts. It gates new-user creation (POST /users, coder users create, and --disable-login) behind --service-account, and ships an irreversible migration (000544_legacy_none_to_service_account) that converts existing login_type='none' users into service accounts and blanks their email. Both are user-facing changes, and the migration is a breaking change, so per the content guidelines the docs must cover the deprecation and the upgrade/migration path.

Updates Needed

  • docs/admin/users/headless-auth.md - Document that login_type=none (and the deprecated --disable-login) is no longer allowed for user creation and now requires --service-account. This page currently documents service accounts but never mentions the none login type it replaces.
  • docs/admin/users/headless-auth.md - Add a breaking-change/upgrade note: on upgrade, existing login_type='none' (non-system) users are automatically converted to service accounts, and their email is permanently blanked (one-way, unrecoverable). Advise operators to export/record those emails before upgrading. This matches the "add upgrade notes" follow-up in the PR's own decision log.

Notes

  • docs/reference/cli/users_create.md is auto-generated from cli/ and already reflects the none deprecation, so no manual edit is needed there.

Automated review via Coder Agents

@jakehwll

Copy link
Copy Markdown
Contributor Author

🤖 Posted by Coder Agents on behalf of Jake Howell.

Closing in favour of #26851, which takes the password-preserving conversion path (keeps emails and existing tokens) instead of converting to service accounts and blanking emails. These two PRs were always mutually exclusive; #26851 is the chosen approach and is being prepared for merge.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

release/breaking This label is applied to PRs to detect breaking changes as part of the release process

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant