mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: backend support for creating and storing service accounts (#22698)
Add is_service_account column to users table with CHECK constraints enforcing login_type='none' and empty email for service accounts. Update user creation API to validate service account constraints. Related to: https://linear.app/codercom/issue/PLAT-27/feat-backend-support-for-creating-and-storing-service-accounts
This commit is contained in:
@@ -4,10 +4,12 @@ ALTER TABLE users ADD COLUMN IF NOT EXISTS
|
||||
|
||||
-- Copy "theme_preference" back to "users"
|
||||
UPDATE users
|
||||
SET theme_preference = (SELECT value
|
||||
FROM user_configs
|
||||
WHERE user_configs.user_id = users.id
|
||||
AND user_configs.key = 'theme_preference');
|
||||
-- Use COALESCE(SELECT, <default>) to avoid forcing an insert of user_configs
|
||||
-- for every users insert in order for this down migration to succeed.
|
||||
SET theme_preference = COALESCE(
|
||||
(SELECT value FROM user_configs WHERE user_configs.user_id = users.id AND user_configs.key = 'theme_preference'),
|
||||
''
|
||||
);
|
||||
|
||||
-- Drop the "user_configs" table.
|
||||
DROP TABLE user_configs;
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
-- Since we can't simply delete a user that potentially has all kinds of tables
|
||||
-- referencing it, give service accounts with empty emails a unique placeholder
|
||||
-- so the original unique indexes can be restored. We only run down migrations
|
||||
-- in dev, so hopefully this is not a big deal.
|
||||
UPDATE users SET
|
||||
email = 'ex-service-account-' || id::text || '@localhost',
|
||||
is_service_account = false
|
||||
WHERE is_service_account = true AND email = '';
|
||||
|
||||
-- Restore original unique indexes.
|
||||
DROP INDEX IF EXISTS idx_users_email;
|
||||
DROP INDEX IF EXISTS users_email_lower_idx;
|
||||
CREATE UNIQUE INDEX idx_users_email ON users USING btree (email) WHERE (deleted = false);
|
||||
CREATE UNIQUE INDEX users_email_lower_idx ON users USING btree (lower(email)) WHERE (deleted = false);
|
||||
|
||||
ALTER TABLE users DROP CONSTRAINT IF EXISTS users_email_not_empty;
|
||||
ALTER TABLE users DROP CONSTRAINT IF EXISTS users_service_account_login_type;
|
||||
ALTER TABLE users DROP COLUMN is_service_account;
|
||||
@@ -0,0 +1,23 @@
|
||||
ALTER TABLE users ADD COLUMN is_service_account boolean NOT NULL DEFAULT false;
|
||||
|
||||
COMMENT ON COLUMN users.is_service_account IS 'Determines if a user is an admin-managed account that cannot login';
|
||||
|
||||
-- Service accounts must use login_type 'none'.
|
||||
ALTER TABLE users ADD CONSTRAINT users_service_account_login_type CHECK (is_service_account = false OR login_type = 'none');
|
||||
|
||||
-- Paranoia check: mark any (unlikely) existing user with an empty email as a
|
||||
-- service account so that adding the constraint below does not fail.
|
||||
-- NOTE: considered setting email to nobody@localhost instead but for all we
|
||||
-- know it may already exist, so chose the lesser of two evils.
|
||||
UPDATE users SET is_service_account = true, login_type = 'none' WHERE email = '';
|
||||
|
||||
-- Service accounts must have empty email; other users must not.
|
||||
ALTER TABLE users ADD CONSTRAINT users_email_not_empty CHECK ((is_service_account = true) = (email = ''));
|
||||
|
||||
-- Exclude empty emails from uniqueness so multiple service accounts can omit an
|
||||
-- email without conflicting. This is the less invasive alternative to making
|
||||
-- email nullable, which would require a big refactor.
|
||||
DROP INDEX idx_users_email;
|
||||
DROP INDEX users_email_lower_idx;
|
||||
CREATE UNIQUE INDEX idx_users_email ON users USING btree (email) WHERE (deleted = false AND email != '');
|
||||
CREATE UNIQUE INDEX users_email_lower_idx ON users USING btree (lower(email)) WHERE (deleted = false AND email != '');
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
-- Fixture for migration 000433_add_is_service_account_to_users.
|
||||
-- Inserts a user with an empty email to ensure the migration
|
||||
-- correctly marks them as a service account before adding the
|
||||
-- users_email_not_empty constraint.
|
||||
|
||||
INSERT INTO users (
|
||||
id,
|
||||
email,
|
||||
username,
|
||||
hashed_password,
|
||||
created_at,
|
||||
updated_at,
|
||||
status,
|
||||
rbac_roles,
|
||||
login_type
|
||||
)
|
||||
VALUES (
|
||||
'8ddb584a-68b8-48ac-998f-86f091ccb380',
|
||||
'',
|
||||
'fixture-empty-email-user-to-service-account',
|
||||
'',
|
||||
'2024-01-01 00:00:00+00',
|
||||
'2024-01-01 00:00:00+00',
|
||||
'active',
|
||||
'{}',
|
||||
'password'
|
||||
);
|
||||
@@ -0,0 +1,41 @@
|
||||
-- Fixture for migration 000433_add_is_service_account_to_users.
|
||||
-- Inserts multiple service accounts with empty emails to help test
|
||||
-- the down migration, which must assign each a unique placeholder
|
||||
-- email before restoring the original unique index on email.
|
||||
|
||||
INSERT INTO users (
|
||||
id,
|
||||
email,
|
||||
username,
|
||||
hashed_password,
|
||||
created_at,
|
||||
updated_at,
|
||||
status,
|
||||
rbac_roles,
|
||||
login_type,
|
||||
is_service_account
|
||||
)
|
||||
VALUES (
|
||||
'b2ce097d-2287-4d64-a550-ed821969545d',
|
||||
'',
|
||||
'fixture-service-account-1',
|
||||
'',
|
||||
'2024-01-01 00:00:00+00',
|
||||
'2024-01-01 00:00:00+00',
|
||||
'active',
|
||||
'{}',
|
||||
'none',
|
||||
true
|
||||
),
|
||||
(
|
||||
'3e218a4a-3b4a-4242-b24e-9430277e619d',
|
||||
'',
|
||||
'fixture-service-account-2',
|
||||
'',
|
||||
'2024-01-01 00:00:00+00',
|
||||
'2024-01-01 00:00:00+00',
|
||||
'active',
|
||||
'{}',
|
||||
'none',
|
||||
true
|
||||
);
|
||||
Reference in New Issue
Block a user