fix: add database constraint to enforce minimum username length (#19453)

Username length and format, via regex, are already enforced at the
application layer, but we have some code paths with database queries
where we could optimize away many of the DB query calls if we could be
sure at the database level that the username is never an empty string.

For example: https://github.com/coder/coder/pull/19395

---------

Signed-off-by: Callum Styan <callumstyan@gmail.com>
This commit is contained in:
Callum Styan
2025-08-21 07:56:41 -07:00
committed by GitHub
parent 72f58c0483
commit bcdade7d8c
5 changed files with 13 additions and 3 deletions
+1
View File
@@ -7,6 +7,7 @@ type CheckConstraint string
// CheckConstraint enums.
const (
CheckOneTimePasscodeSet CheckConstraint = "one_time_passcode_set" // users
CheckUsersUsernameMinLength CheckConstraint = "users_username_min_length" // users
CheckMaxProvisionerLogsLength CheckConstraint = "max_provisioner_logs_length" // provisioner_jobs
CheckValidationMonotonicOrder CheckConstraint = "validation_monotonic_order" // template_version_parameters
CheckUsageEventTypeCheck CheckConstraint = "usage_event_type_check" // usage_events
+2 -1
View File
@@ -1015,7 +1015,8 @@ CREATE TABLE users (
hashed_one_time_passcode bytea,
one_time_passcode_expires_at timestamp with time zone,
is_system boolean DEFAULT false NOT NULL,
CONSTRAINT one_time_passcode_set CHECK ((((hashed_one_time_passcode IS NULL) AND (one_time_passcode_expires_at IS NULL)) OR ((hashed_one_time_passcode IS NOT NULL) AND (one_time_passcode_expires_at IS NOT NULL))))
CONSTRAINT one_time_passcode_set CHECK ((((hashed_one_time_passcode IS NULL) AND (one_time_passcode_expires_at IS NULL)) OR ((hashed_one_time_passcode IS NOT NULL) AND (one_time_passcode_expires_at IS NOT NULL)))),
CONSTRAINT users_username_min_length CHECK ((length(username) >= 1))
);
COMMENT ON COLUMN users.quiet_hours_schedule IS 'Daily (!) cron schedule (with optional CRON_TZ) signifying the start of the user''s quiet hours. If empty, the default quiet hours on the instance is used instead.';
@@ -0,0 +1,2 @@
ALTER TABLE users
DROP CONSTRAINT IF EXISTS users_username_min_length;
@@ -0,0 +1,3 @@
ALTER TABLE users
ADD CONSTRAINT users_username_min_length
CHECK (length(username) >= 1);
+5 -2
View File
@@ -1552,8 +1552,11 @@ func TestUpdateSystemUser(t *testing.T) {
// When: attempting to update a system user's name.
_, err = db.UpdateUserProfile(ctx, database.UpdateUserProfileParams{
ID: systemUser.ID,
Name: "not prebuilds",
ID: systemUser.ID,
Email: systemUser.Email,
Username: systemUser.Username,
AvatarURL: systemUser.AvatarURL,
Name: "not prebuilds",
})
// Then: the attempt is rejected by a postgres trigger.
// require.ErrorContains(t, err, "Cannot modify or delete system users")