From a394a8fd0dc52152ef401b789d1186000c38a565 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Mon, 29 Jul 2024 17:31:31 +0000 Subject: [PATCH 01/11] chore: add github.com user id association This will eventually be used to show an indicator in the UI to star the repository if you've been using Coder for a while and have not starred the repo. If you have, we'll never show a thing! --- coderd/database/dbauthz/dbauthz.go | 17 ++++++ coderd/database/dbmem/dbmem.go | 20 +++++++ coderd/database/dbmetrics/dbmetrics.go | 7 +++ coderd/database/dbmock/dbmock.go | 14 +++++ coderd/database/dump.sql | 5 +- .../000233_github_com_user_id.down.sql | 1 + .../000233_github_com_user_id.up.sql | 3 + coderd/database/models.go | 2 + coderd/database/querier.go | 1 + coderd/database/queries.sql.go | 59 +++++++++++++++---- coderd/database/queries/users.sql | 8 +++ coderd/externalauth/externalauth.go | 29 ++++++++- coderd/telemetry/telemetry.go | 20 ++++--- coderd/userauth.go | 32 ++++++++-- codersdk/externalauth.go | 1 + 15 files changed, 189 insertions(+), 30 deletions(-) create mode 100644 coderd/database/migrations/000233_github_com_user_id.down.sql create mode 100644 coderd/database/migrations/000233_github_com_user_id.up.sql diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index b7cff64e2a57b..7f26ac0beb04c 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -3260,6 +3260,23 @@ func (q *querier) UpdateUserDeletedByID(ctx context.Context, id uuid.UUID) error return deleteQ(q.log, q.auth, q.db.GetUserByID, q.db.UpdateUserDeletedByID)(ctx, id) } +func (q *querier) UpdateUserGithubComUserID(ctx context.Context, arg database.UpdateUserGithubComUserIDParams) error { + user, err := q.db.GetUserByID(ctx, arg.ID) + if err != nil { + return err + } + + err = q.authorizeContext(ctx, policy.ActionUpdatePersonal, user) + if err != nil { + // Admins can update passwords for other users. + err = q.authorizeContext(ctx, policy.ActionUpdate, user) + if err != nil { + return err + } + } + return q.db.UpdateUserGithubComUserID(ctx, arg) +} + func (q *querier) UpdateUserHashedPassword(ctx context.Context, arg database.UpdateUserHashedPasswordParams) error { user, err := q.db.GetUserByID(ctx, arg.ID) if err != nil { diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index f32de78b72714..6b2f5dd86728b 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -7985,6 +7985,26 @@ func (q *FakeQuerier) UpdateUserDeletedByID(_ context.Context, id uuid.UUID) err return sql.ErrNoRows } +func (q *FakeQuerier) UpdateUserGithubComUserID(ctx context.Context, arg database.UpdateUserGithubComUserIDParams) error { + err := validateDatabaseType(arg) + if err != nil { + return err + } + + q.mutex.Lock() + defer q.mutex.Unlock() + + for i, user := range q.users { + if user.ID != arg.ID { + continue + } + user.GithubComUserID = arg.GithubComUserID + q.users[i] = user + return nil + } + return sql.ErrNoRows +} + func (q *FakeQuerier) UpdateUserHashedPassword(_ context.Context, arg database.UpdateUserHashedPasswordParams) error { if err := validateDatabaseType(arg); err != nil { return err diff --git a/coderd/database/dbmetrics/dbmetrics.go b/coderd/database/dbmetrics/dbmetrics.go index 2b25591568f8c..1a13ff7f0b5a9 100644 --- a/coderd/database/dbmetrics/dbmetrics.go +++ b/coderd/database/dbmetrics/dbmetrics.go @@ -2097,6 +2097,13 @@ func (m metricsStore) UpdateUserDeletedByID(ctx context.Context, id uuid.UUID) e return r0 } +func (m metricsStore) UpdateUserGithubComUserID(ctx context.Context, arg database.UpdateUserGithubComUserIDParams) error { + start := time.Now() + r0 := m.s.UpdateUserGithubComUserID(ctx, arg) + m.queryLatencies.WithLabelValues("UpdateUserGithubComUserID").Observe(time.Since(start).Seconds()) + return r0 +} + func (m metricsStore) UpdateUserHashedPassword(ctx context.Context, arg database.UpdateUserHashedPasswordParams) error { start := time.Now() err := m.s.UpdateUserHashedPassword(ctx, arg) diff --git a/coderd/database/dbmock/dbmock.go b/coderd/database/dbmock/dbmock.go index b91ba6c8bd5d8..b4aa6043510f1 100644 --- a/coderd/database/dbmock/dbmock.go +++ b/coderd/database/dbmock/dbmock.go @@ -4416,6 +4416,20 @@ func (mr *MockStoreMockRecorder) UpdateUserDeletedByID(arg0, arg1 any) *gomock.C return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUserDeletedByID", reflect.TypeOf((*MockStore)(nil).UpdateUserDeletedByID), arg0, arg1) } +// UpdateUserGithubComUserID mocks base method. +func (m *MockStore) UpdateUserGithubComUserID(arg0 context.Context, arg1 database.UpdateUserGithubComUserIDParams) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "UpdateUserGithubComUserID", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// UpdateUserGithubComUserID indicates an expected call of UpdateUserGithubComUserID. +func (mr *MockStoreMockRecorder) UpdateUserGithubComUserID(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateUserGithubComUserID", reflect.TypeOf((*MockStore)(nil).UpdateUserGithubComUserID), arg0, arg1) +} + // UpdateUserHashedPassword mocks base method. func (m *MockStore) UpdateUserHashedPassword(arg0 context.Context, arg1 database.UpdateUserHashedPasswordParams) error { m.ctrl.T.Helper() diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index dc15cf9bd4af8..c3b74732dd825 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -974,7 +974,8 @@ CREATE TABLE users ( last_seen_at timestamp without time zone DEFAULT '0001-01-01 00:00:00'::timestamp without time zone NOT NULL, quiet_hours_schedule text DEFAULT ''::text NOT NULL, theme_preference text DEFAULT ''::text NOT NULL, - name text DEFAULT ''::text NOT NULL + name text DEFAULT ''::text NOT NULL, + github_com_user_id bigint ); 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.'; @@ -983,6 +984,8 @@ COMMENT ON COLUMN users.theme_preference IS '"" can be interpreted as "the user COMMENT ON COLUMN users.name IS 'Name of the Coder user'; +COMMENT ON COLUMN users.github_com_user_id IS 'The GitHub.com numerical user ID. At time of implementation, this is used to check if the user has starred the Coder repository.'; + CREATE VIEW visible_users AS SELECT users.id, users.username, diff --git a/coderd/database/migrations/000233_github_com_user_id.down.sql b/coderd/database/migrations/000233_github_com_user_id.down.sql new file mode 100644 index 0000000000000..bf3cddc82e5e4 --- /dev/null +++ b/coderd/database/migrations/000233_github_com_user_id.down.sql @@ -0,0 +1 @@ +ALTER TABLE users DROP COLUMN github_com_user_id; diff --git a/coderd/database/migrations/000233_github_com_user_id.up.sql b/coderd/database/migrations/000233_github_com_user_id.up.sql new file mode 100644 index 0000000000000..81495695b644f --- /dev/null +++ b/coderd/database/migrations/000233_github_com_user_id.up.sql @@ -0,0 +1,3 @@ +ALTER TABLE users ADD COLUMN github_com_user_id BIGINT; + +COMMENT ON COLUMN users.github_com_user_id IS 'The GitHub.com numerical user ID. At time of implementation, this is used to check if the user has starred the Coder repository.'; diff --git a/coderd/database/models.go b/coderd/database/models.go index 0ee78e286516e..70350f54a704f 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -2475,6 +2475,8 @@ type User struct { ThemePreference string `db:"theme_preference" json:"theme_preference"` // Name of the Coder user Name string `db:"name" json:"name"` + // The GitHub.com numerical user ID. At time of implementation, this is used to check if the user has starred the Coder repository. + GithubComUserID sql.NullInt64 `db:"github_com_user_id" json:"github_com_user_id"` } type UserLink struct { diff --git a/coderd/database/querier.go b/coderd/database/querier.go index 9d0494813e306..95015aa706348 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -421,6 +421,7 @@ type sqlcQuerier interface { UpdateTemplateWorkspacesLastUsedAt(ctx context.Context, arg UpdateTemplateWorkspacesLastUsedAtParams) error UpdateUserAppearanceSettings(ctx context.Context, arg UpdateUserAppearanceSettingsParams) (User, error) UpdateUserDeletedByID(ctx context.Context, id uuid.UUID) error + UpdateUserGithubComUserID(ctx context.Context, arg UpdateUserGithubComUserIDParams) error UpdateUserHashedPassword(ctx context.Context, arg UpdateUserHashedPasswordParams) error UpdateUserLastSeenAt(ctx context.Context, arg UpdateUserLastSeenAtParams) (User, error) UpdateUserLink(ctx context.Context, arg UpdateUserLinkParams) (UserLink, error) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 904f304bd25a9..4e7e0ceb3150d 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -1350,7 +1350,7 @@ func (q *sqlQuerier) GetGroupMembers(ctx context.Context) ([]GroupMember, error) const getGroupMembersByGroupID = `-- name: GetGroupMembersByGroupID :many SELECT - users.id, users.email, users.username, users.hashed_password, users.created_at, users.updated_at, users.status, users.rbac_roles, users.login_type, users.avatar_url, users.deleted, users.last_seen_at, users.quiet_hours_schedule, users.theme_preference, users.name + users.id, users.email, users.username, users.hashed_password, users.created_at, users.updated_at, users.status, users.rbac_roles, users.login_type, users.avatar_url, users.deleted, users.last_seen_at, users.quiet_hours_schedule, users.theme_preference, users.name, users.github_com_user_id FROM users LEFT JOIN @@ -1399,6 +1399,7 @@ func (q *sqlQuerier) GetGroupMembersByGroupID(ctx context.Context, groupID uuid. &i.QuietHoursSchedule, &i.ThemePreference, &i.Name, + &i.GithubComUserID, ); err != nil { return nil, err } @@ -9222,7 +9223,7 @@ func (q *sqlQuerier) GetAuthorizationUserRoles(ctx context.Context, userID uuid. const getUserByEmailOrUsername = `-- name: GetUserByEmailOrUsername :one SELECT - id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name + id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name, github_com_user_id FROM users WHERE @@ -9256,13 +9257,14 @@ func (q *sqlQuerier) GetUserByEmailOrUsername(ctx context.Context, arg GetUserBy &i.QuietHoursSchedule, &i.ThemePreference, &i.Name, + &i.GithubComUserID, ) return i, err } const getUserByID = `-- name: GetUserByID :one SELECT - id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name + id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name, github_com_user_id FROM users WHERE @@ -9290,6 +9292,7 @@ func (q *sqlQuerier) GetUserByID(ctx context.Context, id uuid.UUID) (User, error &i.QuietHoursSchedule, &i.ThemePreference, &i.Name, + &i.GithubComUserID, ) return i, err } @@ -9312,7 +9315,7 @@ func (q *sqlQuerier) GetUserCount(ctx context.Context) (int64, error) { const getUsers = `-- name: GetUsers :many SELECT - id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name, COUNT(*) OVER() AS count + id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name, github_com_user_id, COUNT(*) OVER() AS count FROM users WHERE @@ -9411,6 +9414,7 @@ type GetUsersRow struct { QuietHoursSchedule string `db:"quiet_hours_schedule" json:"quiet_hours_schedule"` ThemePreference string `db:"theme_preference" json:"theme_preference"` Name string `db:"name" json:"name"` + GithubComUserID sql.NullInt64 `db:"github_com_user_id" json:"github_com_user_id"` Count int64 `db:"count" json:"count"` } @@ -9449,6 +9453,7 @@ func (q *sqlQuerier) GetUsers(ctx context.Context, arg GetUsersParams) ([]GetUse &i.QuietHoursSchedule, &i.ThemePreference, &i.Name, + &i.GithubComUserID, &i.Count, ); err != nil { return nil, err @@ -9465,7 +9470,7 @@ func (q *sqlQuerier) GetUsers(ctx context.Context, arg GetUsersParams) ([]GetUse } const getUsersByIDs = `-- name: GetUsersByIDs :many -SELECT id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name FROM users WHERE id = ANY($1 :: uuid [ ]) +SELECT id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name, github_com_user_id FROM users WHERE id = ANY($1 :: uuid [ ]) ` // This shouldn't check for deleted, because it's frequently used @@ -9496,6 +9501,7 @@ func (q *sqlQuerier) GetUsersByIDs(ctx context.Context, ids []uuid.UUID) ([]User &i.QuietHoursSchedule, &i.ThemePreference, &i.Name, + &i.GithubComUserID, ); err != nil { return nil, err } @@ -9524,7 +9530,7 @@ INSERT INTO login_type ) VALUES - ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name + ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name, github_com_user_id ` type InsertUserParams struct { @@ -9568,6 +9574,7 @@ func (q *sqlQuerier) InsertUser(ctx context.Context, arg InsertUserParams) (User &i.QuietHoursSchedule, &i.ThemePreference, &i.Name, + &i.GithubComUserID, ) return i, err } @@ -9626,7 +9633,7 @@ SET updated_at = $3 WHERE id = $1 -RETURNING id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name +RETURNING id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name, github_com_user_id ` type UpdateUserAppearanceSettingsParams struct { @@ -9654,6 +9661,7 @@ func (q *sqlQuerier) UpdateUserAppearanceSettings(ctx context.Context, arg Updat &i.QuietHoursSchedule, &i.ThemePreference, &i.Name, + &i.GithubComUserID, ) return i, err } @@ -9672,6 +9680,25 @@ func (q *sqlQuerier) UpdateUserDeletedByID(ctx context.Context, id uuid.UUID) er return err } +const updateUserGithubComUserID = `-- name: UpdateUserGithubComUserID :exec +UPDATE + users +SET + github_com_user_id = $2 +WHERE + id = $1 +` + +type UpdateUserGithubComUserIDParams struct { + ID uuid.UUID `db:"id" json:"id"` + GithubComUserID sql.NullInt64 `db:"github_com_user_id" json:"github_com_user_id"` +} + +func (q *sqlQuerier) UpdateUserGithubComUserID(ctx context.Context, arg UpdateUserGithubComUserIDParams) error { + _, err := q.db.ExecContext(ctx, updateUserGithubComUserID, arg.ID, arg.GithubComUserID) + return err +} + const updateUserHashedPassword = `-- name: UpdateUserHashedPassword :exec UPDATE users @@ -9698,7 +9725,7 @@ SET last_seen_at = $2, updated_at = $3 WHERE - id = $1 RETURNING id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name + id = $1 RETURNING id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name, github_com_user_id ` type UpdateUserLastSeenAtParams struct { @@ -9726,6 +9753,7 @@ func (q *sqlQuerier) UpdateUserLastSeenAt(ctx context.Context, arg UpdateUserLas &i.QuietHoursSchedule, &i.ThemePreference, &i.Name, + &i.GithubComUserID, ) return i, err } @@ -9743,7 +9771,7 @@ SET '':: bytea END WHERE - id = $2 RETURNING id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name + id = $2 RETURNING id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name, github_com_user_id ` type UpdateUserLoginTypeParams struct { @@ -9770,6 +9798,7 @@ func (q *sqlQuerier) UpdateUserLoginType(ctx context.Context, arg UpdateUserLogi &i.QuietHoursSchedule, &i.ThemePreference, &i.Name, + &i.GithubComUserID, ) return i, err } @@ -9785,7 +9814,7 @@ SET name = $6 WHERE id = $1 -RETURNING id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name +RETURNING id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name, github_com_user_id ` type UpdateUserProfileParams struct { @@ -9823,6 +9852,7 @@ func (q *sqlQuerier) UpdateUserProfile(ctx context.Context, arg UpdateUserProfil &i.QuietHoursSchedule, &i.ThemePreference, &i.Name, + &i.GithubComUserID, ) return i, err } @@ -9834,7 +9864,7 @@ SET quiet_hours_schedule = $2 WHERE id = $1 -RETURNING id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name +RETURNING id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name, github_com_user_id ` type UpdateUserQuietHoursScheduleParams struct { @@ -9861,6 +9891,7 @@ func (q *sqlQuerier) UpdateUserQuietHoursSchedule(ctx context.Context, arg Updat &i.QuietHoursSchedule, &i.ThemePreference, &i.Name, + &i.GithubComUserID, ) return i, err } @@ -9873,7 +9904,7 @@ SET rbac_roles = ARRAY(SELECT DISTINCT UNNEST($1 :: text[])) WHERE id = $2 -RETURNING id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name +RETURNING id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name, github_com_user_id ` type UpdateUserRolesParams struct { @@ -9900,6 +9931,7 @@ func (q *sqlQuerier) UpdateUserRoles(ctx context.Context, arg UpdateUserRolesPar &i.QuietHoursSchedule, &i.ThemePreference, &i.Name, + &i.GithubComUserID, ) return i, err } @@ -9911,7 +9943,7 @@ SET status = $2, updated_at = $3 WHERE - id = $1 RETURNING id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name + id = $1 RETURNING id, email, username, hashed_password, created_at, updated_at, status, rbac_roles, login_type, avatar_url, deleted, last_seen_at, quiet_hours_schedule, theme_preference, name, github_com_user_id ` type UpdateUserStatusParams struct { @@ -9939,6 +9971,7 @@ func (q *sqlQuerier) UpdateUserStatus(ctx context.Context, arg UpdateUserStatusP &i.QuietHoursSchedule, &i.ThemePreference, &i.Name, + &i.GithubComUserID, ) return i, err } diff --git a/coderd/database/queries/users.sql b/coderd/database/queries/users.sql index 6bbfdac112d7a..44148eb936a33 100644 --- a/coderd/database/queries/users.sql +++ b/coderd/database/queries/users.sql @@ -85,6 +85,14 @@ WHERE id = $1 RETURNING *; +-- name: UpdateUserGithubComUserID :exec +UPDATE + users +SET + github_com_user_id = $2 +WHERE + id = $1; + -- name: UpdateUserAppearanceSettings :one UPDATE users diff --git a/coderd/externalauth/externalauth.go b/coderd/externalauth/externalauth.go index b626a5e28fb1f..0f81a147b26c4 100644 --- a/coderd/externalauth/externalauth.go +++ b/coderd/externalauth/externalauth.go @@ -154,7 +154,7 @@ func (c *Config) RefreshToken(ctx context.Context, db database.Store, externalAu retryCtx, retryCtxCancel := context.WithTimeout(ctx, time.Second) defer retryCtxCancel() validate: - valid, _, err := c.ValidateToken(ctx, token) + valid, user, err := c.ValidateToken(ctx, token) if err != nil { return externalAuthLink, xerrors.Errorf("validate external auth token: %w", err) } @@ -190,6 +190,21 @@ validate: } externalAuthLink = updatedAuthLink } + + // Update the associated users github.com username if the token is for github.com. + if IsGithubDotComURL(c.AuthCodeURL("")) && user != nil { + err = db.UpdateUserGithubComUserID(ctx, database.UpdateUserGithubComUserIDParams{ + ID: externalAuthLink.UserID, + GithubComUserID: sql.NullInt64{ + Int64: user.ID, + Valid: true, + }, + }) + if err != nil { + return externalAuthLink, xerrors.Errorf("update user github com user id: %w", err) + } + } + return externalAuthLink, nil } @@ -233,6 +248,7 @@ func (c *Config) ValidateToken(ctx context.Context, link *oauth2.Token) (bool, * err = json.NewDecoder(res.Body).Decode(&ghUser) if err == nil { user = &codersdk.ExternalAuthUser{ + ID: ghUser.GetID(), Login: ghUser.GetLogin(), AvatarURL: ghUser.GetAvatarURL(), ProfileURL: ghUser.GetHTMLURL(), @@ -291,6 +307,7 @@ func (c *Config) AppInstallations(ctx context.Context, token string) ([]codersdk ID: int(installation.GetID()), ConfigureURL: installation.GetHTMLURL(), Account: codersdk.ExternalAuthUser{ + ID: account.GetID(), Login: account.GetLogin(), AvatarURL: account.GetAvatarURL(), ProfileURL: account.GetHTMLURL(), @@ -947,3 +964,13 @@ type roundTripper func(req *http.Request) (*http.Response, error) func (r roundTripper) RoundTrip(req *http.Request) (*http.Response, error) { return r(req) } + +// IsGithubDotComURL returns true if the given URL is a github.com URL. +func IsGithubDotComURL(str string) bool { + str = strings.ToLower(str) + url, err := url.Parse(str) + if err != nil { + return false + } + return url.Host == "github.com" +} diff --git a/coderd/telemetry/telemetry.go b/coderd/telemetry/telemetry.go index f269e856067c5..c89276a2ffa28 100644 --- a/coderd/telemetry/telemetry.go +++ b/coderd/telemetry/telemetry.go @@ -660,11 +660,12 @@ func ConvertUser(dbUser database.User) User { emailHashed = fmt.Sprintf("%x%s", hash[:], dbUser.Email[atSymbol:]) } return User{ - ID: dbUser.ID, - EmailHashed: emailHashed, - RBACRoles: dbUser.RBACRoles, - CreatedAt: dbUser.CreatedAt, - Status: dbUser.Status, + ID: dbUser.ID, + EmailHashed: emailHashed, + RBACRoles: dbUser.RBACRoles, + CreatedAt: dbUser.CreatedAt, + Status: dbUser.Status, + GithubComUserID: dbUser.GithubComUserID.Int64, } } @@ -836,10 +837,11 @@ type User struct { ID uuid.UUID `json:"id"` CreatedAt time.Time `json:"created_at"` // Email is only filled in for the first/admin user! - Email *string `json:"email"` - EmailHashed string `json:"email_hashed"` - RBACRoles []string `json:"rbac_roles"` - Status database.UserStatus `json:"status"` + Email *string `json:"email"` + EmailHashed string `json:"email_hashed"` + RBACRoles []string `json:"rbac_roles"` + Status database.UserStatus `json:"status"` + GithubComUserID int64 `json:"github_com_user_id"` } type Group struct { diff --git a/coderd/userauth.go b/coderd/userauth.go index 303f8a3473bea..f876bf7686341 100644 --- a/coderd/userauth.go +++ b/coderd/userauth.go @@ -31,6 +31,7 @@ import ( "github.com/coder/coder/v2/coderd/database" "github.com/coder/coder/v2/coderd/database/dbauthz" "github.com/coder/coder/v2/coderd/database/dbtime" + "github.com/coder/coder/v2/coderd/externalauth" "github.com/coder/coder/v2/coderd/httpapi" "github.com/coder/coder/v2/coderd/httpmw" "github.com/coder/coder/v2/coderd/promoauth" @@ -661,7 +662,7 @@ func (api *API) userOAuth2Github(rw http.ResponseWriter, r *http.Request) { }).SetInitAuditRequest(func(params *audit.RequestParams) (*audit.Request[database.User], func()) { return audit.InitRequest[database.User](rw, params) }) - cookies, key, err := api.oauthLogin(r, params) + cookies, user, key, err := api.oauthLogin(r, params) defer params.CommitAuditLogs() var httpErr httpError if xerrors.As(err, &httpErr) { @@ -676,6 +677,25 @@ func (api *API) userOAuth2Github(rw http.ResponseWriter, r *http.Request) { }) return } + // If the user is logging in with github.com we update their associated + // GitHub user ID to the new one. + if externalauth.IsGithubDotComURL(api.GithubOAuth2Config.AuthCodeURL("")) && user.GithubComUserID.Int64 != ghUser.GetID() { + err = api.Database.UpdateUserGithubComUserID(ctx, database.UpdateUserGithubComUserIDParams{ + ID: user.ID, + GithubComUserID: sql.NullInt64{ + Int64: ghUser.GetID(), + Valid: true, + }, + }) + if err != nil { + logger.Error(ctx, "oauth2: unable to update user github id", slog.F("user", user.Username), slog.Error(err)) + httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ + Message: "Failed to update user GitHub ID.", + Detail: err.Error(), + }) + return + } + } aReq.New = key aReq.UserID = key.UserID @@ -1030,7 +1050,7 @@ func (api *API) userOIDC(rw http.ResponseWriter, r *http.Request) { }).SetInitAuditRequest(func(params *audit.RequestParams) (*audit.Request[database.User], func()) { return audit.InitRequest[database.User](rw, params) }) - cookies, key, err := api.oauthLogin(r, params) + cookies, user, key, err := api.oauthLogin(r, params) defer params.CommitAuditLogs() var httpErr httpError if xerrors.As(err, &httpErr) { @@ -1320,7 +1340,7 @@ func (e httpError) Error() string { return e.msg } -func (api *API) oauthLogin(r *http.Request, params *oauthLoginParams) ([]*http.Cookie, database.APIKey, error) { +func (api *API) oauthLogin(r *http.Request, params *oauthLoginParams) ([]*http.Cookie, database.User, database.APIKey, error) { var ( ctx = r.Context() user database.User @@ -1610,7 +1630,7 @@ func (api *API) oauthLogin(r *http.Request, params *oauthLoginParams) ([]*http.C return nil }, nil) if err != nil { - return nil, database.APIKey{}, xerrors.Errorf("in tx: %w", err) + return nil, database.User{}, database.APIKey{}, xerrors.Errorf("in tx: %w", err) } var key database.APIKey @@ -1647,13 +1667,13 @@ func (api *API) oauthLogin(r *http.Request, params *oauthLoginParams) ([]*http.C RemoteAddr: r.RemoteAddr, }) if err != nil { - return nil, database.APIKey{}, xerrors.Errorf("create API key: %w", err) + return nil, database.User{}, database.APIKey{}, xerrors.Errorf("create API key: %w", err) } cookies = append(cookies, cookie) key = *newKey } - return cookies, key, nil + return cookies, user, key, nil } // convertUserToOauth will convert a user from password base loginType to diff --git a/codersdk/externalauth.go b/codersdk/externalauth.go index 49e1a8f262be5..475c55b91bed3 100644 --- a/codersdk/externalauth.go +++ b/codersdk/externalauth.go @@ -103,6 +103,7 @@ type ExternalAuthAppInstallation struct { } type ExternalAuthUser struct { + ID int64 `json:"id"` Login string `json:"login"` AvatarURL string `json:"avatar_url"` ProfileURL string `json:"profile_url"` From 8f6a6543e00416e27f3bd03069bfd97f7ee1509d Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Mon, 29 Jul 2024 18:13:25 +0000 Subject: [PATCH 02/11] gen --- coderd/apidoc/docs.go | 3 +++ coderd/apidoc/swagger.json | 3 +++ docs/api/git.md | 2 ++ docs/api/schemas.md | 17 +++++++++++------ site/src/api/typesGenerated.ts | 1 + 5 files changed, 20 insertions(+), 6 deletions(-) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index b72db00912ff7..981be686df469 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -9811,6 +9811,9 @@ const docTemplate = `{ "avatar_url": { "type": "string" }, + "id": { + "type": "integer" + }, "login": { "type": "string" }, diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index bf7216f1f313b..14efc71711687 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -8801,6 +8801,9 @@ "avatar_url": { "type": "string" }, + "id": { + "type": "integer" + }, "login": { "type": "string" }, diff --git a/docs/api/git.md b/docs/api/git.md index 71a0d2921f5fa..929ab3e868b8f 100644 --- a/docs/api/git.md +++ b/docs/api/git.md @@ -71,6 +71,7 @@ curl -X GET http://coder-server:8080/api/v2/external-auth/{externalauth} \ { "account": { "avatar_url": "string", + "id": 0, "login": "string", "name": "string", "profile_url": "string" @@ -81,6 +82,7 @@ curl -X GET http://coder-server:8080/api/v2/external-auth/{externalauth} \ ], "user": { "avatar_url": "string", + "id": 0, "login": "string", "name": "string", "profile_url": "string" diff --git a/docs/api/schemas.md b/docs/api/schemas.md index c1ec9979a0a13..53ad820daf60c 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -2521,6 +2521,7 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o { "account": { "avatar_url": "string", + "id": 0, "login": "string", "name": "string", "profile_url": "string" @@ -2531,6 +2532,7 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o ], "user": { "avatar_url": "string", + "id": 0, "login": "string", "name": "string", "profile_url": "string" @@ -2556,6 +2558,7 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o { "account": { "avatar_url": "string", + "id": 0, "login": "string", "name": "string", "profile_url": "string" @@ -2669,6 +2672,7 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o ```json { "avatar_url": "string", + "id": 0, "login": "string", "name": "string", "profile_url": "string" @@ -2677,12 +2681,13 @@ CreateWorkspaceRequest provides options for creating a new workspace. Only one o ### Properties -| Name | Type | Required | Restrictions | Description | -| ------------- | ------ | -------- | ------------ | ----------- | -| `avatar_url` | string | false | | | -| `login` | string | false | | | -| `name` | string | false | | | -| `profile_url` | string | false | | | +| Name | Type | Required | Restrictions | Description | +| ------------- | ------- | -------- | ------------ | ----------- | +| `avatar_url` | string | false | | | +| `id` | integer | false | | | +| `login` | string | false | | | +| `name` | string | false | | | +| `profile_url` | string | false | | | ## codersdk.Feature diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 0ad30e1310cff..08bd69cd58448 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -572,6 +572,7 @@ export interface ExternalAuthLinkProvider { // From codersdk/externalauth.go export interface ExternalAuthUser { + readonly id: number; readonly login: string; readonly avatar_url: string; readonly profile_url: string; From 86c3f282a311a491bc1d49e04c1736f83bad7c54 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Mon, 29 Jul 2024 18:21:46 +0000 Subject: [PATCH 03/11] Fix model query --- coderd/database/modelqueries.go | 1 + 1 file changed, 1 insertion(+) diff --git a/coderd/database/modelqueries.go b/coderd/database/modelqueries.go index 78826ea7cc8b5..532449089535f 100644 --- a/coderd/database/modelqueries.go +++ b/coderd/database/modelqueries.go @@ -361,6 +361,7 @@ func (q *sqlQuerier) GetAuthorizedUsers(ctx context.Context, arg GetUsersParams, &i.QuietHoursSchedule, &i.ThemePreference, &i.Name, + &i.GithubComUserID, &i.Count, ); err != nil { return nil, err From 8b5e8662939abb3b48b78efd854017d26ae26cf5 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Mon, 29 Jul 2024 18:31:09 +0000 Subject: [PATCH 04/11] Fix linting --- coderd/database/dbmem/dbmem.go | 2 +- coderd/externalauth/externalauth.go | 4 ++-- .../pages/ExternalAuthPage/ExternalAuthPageView.stories.tsx | 4 ++++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index 6b2f5dd86728b..09c0585964795 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -7985,7 +7985,7 @@ func (q *FakeQuerier) UpdateUserDeletedByID(_ context.Context, id uuid.UUID) err return sql.ErrNoRows } -func (q *FakeQuerier) UpdateUserGithubComUserID(ctx context.Context, arg database.UpdateUserGithubComUserIDParams) error { +func (q *FakeQuerier) UpdateUserGithubComUserID(_ context.Context, arg database.UpdateUserGithubComUserIDParams) error { err := validateDatabaseType(arg) if err != nil { return err diff --git a/coderd/externalauth/externalauth.go b/coderd/externalauth/externalauth.go index 0f81a147b26c4..855a148f020f0 100644 --- a/coderd/externalauth/externalauth.go +++ b/coderd/externalauth/externalauth.go @@ -968,9 +968,9 @@ func (r roundTripper) RoundTrip(req *http.Request) (*http.Response, error) { // IsGithubDotComURL returns true if the given URL is a github.com URL. func IsGithubDotComURL(str string) bool { str = strings.ToLower(str) - url, err := url.Parse(str) + ghUrl, err := url.Parse(str) if err != nil { return false } - return url.Host == "github.com" + return ghUrl.Host == "github.com" } diff --git a/site/src/pages/ExternalAuthPage/ExternalAuthPageView.stories.tsx b/site/src/pages/ExternalAuthPage/ExternalAuthPageView.stories.tsx index 676597bdb4617..4b1d07ddb2734 100644 --- a/site/src/pages/ExternalAuthPage/ExternalAuthPageView.stories.tsx +++ b/site/src/pages/ExternalAuthPage/ExternalAuthPageView.stories.tsx @@ -22,6 +22,7 @@ WebAuthenticated.args = { app_installable: false, display_name: "BitBucket", user: { + id: 0, avatar_url: "https://avatars.githubusercontent.com/u/7122116?v=4", login: "kylecarbs", name: "Kyle Carberry", @@ -104,6 +105,7 @@ DeviceAuthenticatedNotInstalled.args = { app_install_url: "https://example.com", app_installable: true, user: { + id: 0, avatar_url: "https://avatars.githubusercontent.com/u/7122116?v=4", login: "kylecarbs", name: "Kyle Carberry", @@ -123,6 +125,7 @@ DeviceAuthenticatedInstalled.args = { configure_url: "https://example.com", id: 1, account: { + id: 0, avatar_url: "https://github.com/coder.png", login: "coder", name: "Coder", @@ -133,6 +136,7 @@ DeviceAuthenticatedInstalled.args = { app_install_url: "https://example.com", app_installable: true, user: { + id: 0, avatar_url: "https://avatars.githubusercontent.com/u/7122116?v=4", login: "kylecarbs", name: "Kyle Carberry", From 5bae8efbbf182e8880139b69d433ad5656c51541 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Mon, 29 Jul 2024 18:32:15 +0000 Subject: [PATCH 05/11] Ignore auditing github.com user id --- enterprise/audit/table.go | 1 + 1 file changed, 1 insertion(+) diff --git a/enterprise/audit/table.go b/enterprise/audit/table.go index 0a3608dae7169..dcecd88971af8 100644 --- a/enterprise/audit/table.go +++ b/enterprise/audit/table.go @@ -144,6 +144,7 @@ var auditableResourcesTypes = map[any]map[string]Action{ "quiet_hours_schedule": ActionTrack, "theme_preference": ActionIgnore, "name": ActionTrack, + "github_com_user_id": ActionIgnore, }, &database.Workspace{}: { "id": ActionTrack, From 78d2bcc2da15a6cdbab180c240ac08a55966a74c Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Mon, 29 Jul 2024 20:58:19 +0000 Subject: [PATCH 06/11] Add test --- coderd/database/dbauthz/dbauthz_test.go | 6 ++++++ docs/admin/audit-logs.md | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index 876c0d797f64a..627558dbe1f73 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -1105,6 +1105,12 @@ func (s *MethodTestSuite) TestUser() { u := dbgen.User(s.T(), db, database.User{}) check.Args(u.ID).Asserts(u, policy.ActionDelete).Returns() })) + s.Run("UpdateUserGithubComUserID", s.Subtest(func(db database.Store, check *expects) { + u := dbgen.User(s.T(), db, database.User{}) + check.Args(database.UpdateUserGithubComUserIDParams{ + ID: u.ID, + }).Asserts(u, policy.ActionUpdatePersonal) + })) s.Run("UpdateUserHashedPassword", s.Subtest(func(db database.Store, check *expects) { u := dbgen.User(s.T(), db, database.User{}) check.Args(database.UpdateUserHashedPasswordParams{ diff --git a/docs/admin/audit-logs.md b/docs/admin/audit-logs.md index 87f07cf243125..a6f8e4e5117da 100644 --- a/docs/admin/audit-logs.md +++ b/docs/admin/audit-logs.md @@ -24,7 +24,7 @@ We track the following resources: | Organization
|
FieldTracked
created_atfalse
descriptiontrue
display_nametrue
icontrue
idfalse
is_defaulttrue
nametrue
updated_attrue
| | Template
write, delete |
FieldTracked
active_version_idtrue
activity_bumptrue
allow_user_autostarttrue
allow_user_autostoptrue
allow_user_cancel_workspace_jobstrue
autostart_block_days_of_weektrue
autostop_requirement_days_of_weektrue
autostop_requirement_weekstrue
created_atfalse
created_bytrue
created_by_avatar_urlfalse
created_by_usernamefalse
default_ttltrue
deletedfalse
deprecatedtrue
descriptiontrue
display_nametrue
failure_ttltrue
group_acltrue
icontrue
idtrue
max_port_sharing_leveltrue
nametrue
organization_display_namefalse
organization_iconfalse
organization_idfalse
organization_namefalse
provisionertrue
require_active_versiontrue
time_til_dormanttrue
time_til_dormant_autodeletetrue
updated_atfalse
user_acltrue
| | TemplateVersion
create, write |
FieldTracked
archivedtrue
created_atfalse
created_bytrue
created_by_avatar_urlfalse
created_by_usernamefalse
external_auth_providersfalse
idtrue
job_idfalse
messagefalse
nametrue
organization_idfalse
readmetrue
template_idtrue
updated_atfalse
| -| User
create, write, delete |
FieldTracked
avatar_urlfalse
created_atfalse
deletedtrue
emailtrue
hashed_passwordtrue
idtrue
last_seen_atfalse
login_typetrue
nametrue
quiet_hours_scheduletrue
rbac_rolestrue
statustrue
theme_preferencefalse
updated_atfalse
usernametrue
| +| User
create, write, delete |
FieldTracked
avatar_urlfalse
created_atfalse
deletedtrue
emailtrue
github_com_user_idfalse
hashed_passwordtrue
idtrue
last_seen_atfalse
login_typetrue
nametrue
quiet_hours_scheduletrue
rbac_rolestrue
statustrue
theme_preferencefalse
updated_atfalse
usernametrue
| | Workspace
create, write, delete |
FieldTracked
automatic_updatestrue
autostart_scheduletrue
created_atfalse
deletedfalse
deleting_attrue
dormant_attrue
favoritetrue
idtrue
last_used_atfalse
nametrue
organization_idfalse
owner_idtrue
template_idtrue
ttltrue
updated_atfalse
| | WorkspaceBuild
start, stop |
FieldTracked
build_numberfalse
created_atfalse
daily_costfalse
deadlinefalse
idfalse
initiator_by_avatar_urlfalse
initiator_by_usernamefalse
initiator_idfalse
job_idfalse
max_deadlinefalse
provisioner_statefalse
reasonfalse
template_version_idtrue
transitionfalse
updated_atfalse
workspace_idfalse
| | WorkspaceProxy
|
FieldTracked
created_attrue
deletedfalse
derp_enabledtrue
derp_onlytrue
display_nametrue
icontrue
idtrue
nametrue
region_idtrue
token_hashed_secrettrue
updated_atfalse
urltrue
versiontrue
wildcard_hostnametrue
| From b1229f5bf373313d1425968d24dd88fb57d04142 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Tue, 30 Jul 2024 15:47:08 +0000 Subject: [PATCH 07/11] Fix gh url var name --- coderd/externalauth/externalauth.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coderd/externalauth/externalauth.go b/coderd/externalauth/externalauth.go index 855a148f020f0..e03b43eb1f868 100644 --- a/coderd/externalauth/externalauth.go +++ b/coderd/externalauth/externalauth.go @@ -968,9 +968,9 @@ func (r roundTripper) RoundTrip(req *http.Request) (*http.Response, error) { // IsGithubDotComURL returns true if the given URL is a github.com URL. func IsGithubDotComURL(str string) bool { str = strings.ToLower(str) - ghUrl, err := url.Parse(str) + ghURL, err := url.Parse(str) if err != nil { return false } - return ghUrl.Host == "github.com" + return ghURL.Host == "github.com" } From ff84b7306557041e833577669f0c120b1abe00fc Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Wed, 31 Jul 2024 15:35:00 +0000 Subject: [PATCH 08/11] Update migration --- ...ub_com_user_id.down.sql => 000234_github_com_user_id.down.sql} | 0 ...github_com_user_id.up.sql => 000234_github_com_user_id.up.sql} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename coderd/database/migrations/{000233_github_com_user_id.down.sql => 000234_github_com_user_id.down.sql} (100%) rename coderd/database/migrations/{000233_github_com_user_id.up.sql => 000234_github_com_user_id.up.sql} (100%) diff --git a/coderd/database/migrations/000233_github_com_user_id.down.sql b/coderd/database/migrations/000234_github_com_user_id.down.sql similarity index 100% rename from coderd/database/migrations/000233_github_com_user_id.down.sql rename to coderd/database/migrations/000234_github_com_user_id.down.sql diff --git a/coderd/database/migrations/000233_github_com_user_id.up.sql b/coderd/database/migrations/000234_github_com_user_id.up.sql similarity index 100% rename from coderd/database/migrations/000233_github_com_user_id.up.sql rename to coderd/database/migrations/000234_github_com_user_id.up.sql From f9214ed4226bd445c01fe19d0428f0bf7ab3e2b8 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Wed, 31 Jul 2024 11:36:18 -0400 Subject: [PATCH 09/11] Update coderd/database/dbauthz/dbauthz.go Co-authored-by: Steven Masley --- coderd/database/dbauthz/dbauthz.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index 7f26ac0beb04c..941ab4caccfac 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -3268,7 +3268,7 @@ func (q *querier) UpdateUserGithubComUserID(ctx context.Context, arg database.Up err = q.authorizeContext(ctx, policy.ActionUpdatePersonal, user) if err != nil { - // Admins can update passwords for other users. + // System user can also update err = q.authorizeContext(ctx, policy.ActionUpdate, user) if err != nil { return err From f6bed7302331ed56ad3c7902dc9fe8f3e5ddfd78 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Wed, 31 Jul 2024 15:37:59 +0000 Subject: [PATCH 10/11] Fix updating to when the token changes --- coderd/externalauth/externalauth.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/coderd/externalauth/externalauth.go b/coderd/externalauth/externalauth.go index e03b43eb1f868..d93120fc5da14 100644 --- a/coderd/externalauth/externalauth.go +++ b/coderd/externalauth/externalauth.go @@ -189,19 +189,19 @@ validate: return updatedAuthLink, xerrors.Errorf("update external auth link: %w", err) } externalAuthLink = updatedAuthLink - } - // Update the associated users github.com username if the token is for github.com. - if IsGithubDotComURL(c.AuthCodeURL("")) && user != nil { - err = db.UpdateUserGithubComUserID(ctx, database.UpdateUserGithubComUserIDParams{ - ID: externalAuthLink.UserID, - GithubComUserID: sql.NullInt64{ - Int64: user.ID, - Valid: true, - }, - }) - if err != nil { - return externalAuthLink, xerrors.Errorf("update user github com user id: %w", err) + // Update the associated users github.com username if the token is for github.com. + if IsGithubDotComURL(c.AuthCodeURL("")) && user != nil { + err = db.UpdateUserGithubComUserID(ctx, database.UpdateUserGithubComUserIDParams{ + ID: externalAuthLink.UserID, + GithubComUserID: sql.NullInt64{ + Int64: user.ID, + Valid: true, + }, + }) + if err != nil { + return externalAuthLink, xerrors.Errorf("update user github com user id: %w", err) + } } } From 7f4f9fcc76e5d18e4c61704c49f1190bddafd449 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Fri, 2 Aug 2024 16:15:21 +0000 Subject: [PATCH 11/11] Fix migration --- ...ub_com_user_id.down.sql => 000237_github_com_user_id.down.sql} | 0 ...github_com_user_id.up.sql => 000237_github_com_user_id.up.sql} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename coderd/database/migrations/{000234_github_com_user_id.down.sql => 000237_github_com_user_id.down.sql} (100%) rename coderd/database/migrations/{000234_github_com_user_id.up.sql => 000237_github_com_user_id.up.sql} (100%) diff --git a/coderd/database/migrations/000234_github_com_user_id.down.sql b/coderd/database/migrations/000237_github_com_user_id.down.sql similarity index 100% rename from coderd/database/migrations/000234_github_com_user_id.down.sql rename to coderd/database/migrations/000237_github_com_user_id.down.sql diff --git a/coderd/database/migrations/000234_github_com_user_id.up.sql b/coderd/database/migrations/000237_github_com_user_id.up.sql similarity index 100% rename from coderd/database/migrations/000234_github_com_user_id.up.sql rename to coderd/database/migrations/000237_github_com_user_id.up.sql