diff --git a/.golangci.yaml b/.golangci.yaml index 84a213ea17..f2ecce63da 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -10,6 +10,9 @@ linters-settings: include: # Gradually extend to cover more of the codebase. - 'httpmw\.\w+' + # We want to enforce all values are specified when inserting or updating + # a database row. Ref: #9936 + - 'github.com/coder/coder/v2/coderd/database\.[^G][^e][^t]\w+Params' gocognit: min-complexity: 300 diff --git a/coderd/apikey/apikey.go b/coderd/apikey/apikey.go index 21a4ee9ff8..3ae3c0d6e9 100644 --- a/coderd/apikey/apikey.go +++ b/coderd/apikey/apikey.go @@ -76,6 +76,7 @@ func Generate(params CreateParams) (database.InsertAPIKeyParams, string, error) return database.InsertAPIKeyParams{ ID: keyID, UserID: params.UserID, + LastUsed: time.Time{}, LifetimeSeconds: params.LifetimeSeconds, IPAddress: pqtype.Inet{ IPNet: net.IPNet{ diff --git a/coderd/audit.go b/coderd/audit.go index e898e343b1..b0d75d1a5b 100644 --- a/coderd/audit.go +++ b/coderd/audit.go @@ -154,6 +154,9 @@ func (api *API) generateFakeAuditLog(rw http.ResponseWriter, r *http.Request) { Diff: diff, StatusCode: http.StatusOK, AdditionalFields: params.AdditionalFields, + RequestID: uuid.Nil, // no request ID to attach this to + ResourceIcon: "", + OrganizationID: uuid.New(), }) if err != nil { httpapi.InternalServerError(rw, err) diff --git a/coderd/coderdtest/oidctest/helper.go b/coderd/coderdtest/oidctest/helper.go index 11d9114be2..5f3fe27e2e 100644 --- a/coderd/coderdtest/oidctest/helper.go +++ b/coderd/coderdtest/oidctest/helper.go @@ -1,6 +1,7 @@ package oidctest import ( + "database/sql" "net/http" "testing" "time" @@ -69,11 +70,13 @@ func (*LoginHelper) ExpireOauthToken(t *testing.T, db database.Store, user *code // Expire the oauth link for the given user. updated, err := db.UpdateUserLink(ctx, database.UpdateUserLinkParams{ - OAuthAccessToken: link.OAuthAccessToken, - OAuthRefreshToken: link.OAuthRefreshToken, - OAuthExpiry: time.Now().Add(time.Hour * -1), - UserID: link.UserID, - LoginType: link.LoginType, + OAuthAccessToken: link.OAuthAccessToken, + OAuthAccessTokenKeyID: sql.NullString{}, // dbcrypt will update as required + OAuthRefreshToken: link.OAuthRefreshToken, + OAuthRefreshTokenKeyID: sql.NullString{}, // dbcrypt will update as required + OAuthExpiry: time.Now().Add(time.Hour * -1), + UserID: link.UserID, + LoginType: link.LoginType, }) require.NoError(t, err, "expire user link") diff --git a/coderd/database/dbfake/dbfake.go b/coderd/database/dbfake/dbfake.go index 8651664f47..1e6e4d9d41 100644 --- a/coderd/database/dbfake/dbfake.go +++ b/coderd/database/dbfake/dbfake.go @@ -4142,6 +4142,8 @@ func (q *FakeQuerier) InsertAllUsersGroup(ctx context.Context, orgID uuid.UUID) Name: database.EveryoneGroup, DisplayName: "", OrganizationID: orgID, + AvatarURL: "", + QuotaAllowance: 0, }) } diff --git a/coderd/database/dbgen/dbgen.go b/coderd/database/dbgen/dbgen.go index e769aef736..d460c3fbaf 100644 --- a/coderd/database/dbgen/dbgen.go +++ b/coderd/database/dbgen/dbgen.go @@ -125,7 +125,7 @@ func APIKey(t testing.TB, db database.Store, seed database.APIKey) (key database } func WorkspaceAgent(t testing.TB, db database.Store, orig database.WorkspaceAgent) database.WorkspaceAgent { - workspace, err := db.InsertWorkspaceAgent(genCtx, database.InsertWorkspaceAgentParams{ + agt, err := db.InsertWorkspaceAgent(genCtx, database.InsertWorkspaceAgentParams{ ID: takeFirst(orig.ID, uuid.New()), CreatedAt: takeFirst(orig.CreatedAt, dbtime.Now()), UpdatedAt: takeFirst(orig.UpdatedAt, dbtime.Now()), @@ -154,9 +154,10 @@ func WorkspaceAgent(t testing.TB, db database.Store, orig database.WorkspaceAgen ConnectionTimeoutSeconds: takeFirst(orig.ConnectionTimeoutSeconds, 3600), TroubleshootingURL: takeFirst(orig.TroubleshootingURL, "https://example.com"), MOTDFile: takeFirst(orig.TroubleshootingURL, ""), + DisplayApps: append([]database.DisplayApp{}, orig.DisplayApps...), }) require.NoError(t, err, "insert workspace agent") - return workspace + return agt } func Workspace(t testing.TB, db database.Store, orig database.Workspace) database.Workspace { @@ -204,6 +205,7 @@ func WorkspaceBuild(t testing.TB, db database.Store, orig database.WorkspaceBuil JobID: takeFirst(orig.JobID, uuid.New()), ProvisionerState: takeFirstSlice(orig.ProvisionerState, []byte{}), Deadline: takeFirst(orig.Deadline, dbtime.Now().Add(time.Hour)), + MaxDeadline: takeFirst(orig.MaxDeadline, time.Time{}), Reason: takeFirst(orig.Reason, database.BuildReasonInitiator), }) if err != nil { @@ -348,6 +350,7 @@ func ProvisionerJob(t testing.TB, db database.Store, ps pubsub.Pubsub, orig data Type: takeFirst(orig.Type, database.ProvisionerJobTypeWorkspaceBuild), Input: takeFirstSlice(orig.Input, []byte("{}")), Tags: orig.Tags, + TraceMetadata: pqtype.NullRawMessage{}, }) require.NoError(t, err, "insert job") if ps != nil { @@ -359,6 +362,7 @@ func ProvisionerJob(t testing.TB, db database.Store, ps pubsub.Pubsub, orig data StartedAt: orig.StartedAt, Types: []database.ProvisionerType{database.ProvisionerTypeEcho}, Tags: must(json.Marshal(orig.Tags)), + WorkerID: uuid.NullUUID{}, }) require.NoError(t, err) } @@ -460,6 +464,8 @@ func WorkspaceProxy(t testing.TB, db database.Store, orig database.WorkspaceProx TokenHashedSecret: hashedSecret[:], CreatedAt: takeFirst(orig.CreatedAt, dbtime.Now()), UpdatedAt: takeFirst(orig.UpdatedAt, dbtime.Now()), + DerpEnabled: takeFirst(orig.DerpEnabled, false), + DerpOnly: takeFirst(orig.DerpEnabled, false), }) require.NoError(t, err, "insert proxy") diff --git a/coderd/externalauth.go b/coderd/externalauth.go index f668d6b5a9..8e69f3f239 100644 --- a/coderd/externalauth.go +++ b/coderd/externalauth.go @@ -123,13 +123,15 @@ func (api *API) postExternalAuthDeviceByID(rw http.ResponseWriter, r *http.Reque } _, err = api.Database.InsertExternalAuthLink(ctx, database.InsertExternalAuthLinkParams{ - ProviderID: config.ID, - UserID: apiKey.UserID, - CreatedAt: dbtime.Now(), - UpdatedAt: dbtime.Now(), - OAuthAccessToken: token.AccessToken, - OAuthRefreshToken: token.RefreshToken, - OAuthExpiry: token.Expiry, + ProviderID: config.ID, + UserID: apiKey.UserID, + CreatedAt: dbtime.Now(), + UpdatedAt: dbtime.Now(), + OAuthAccessToken: token.AccessToken, + OAuthAccessTokenKeyID: sql.NullString{}, // dbcrypt will set as required + OAuthRefreshToken: token.RefreshToken, + OAuthRefreshTokenKeyID: sql.NullString{}, // dbcrypt will set as required + OAuthExpiry: token.Expiry, }) if err != nil { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ @@ -140,12 +142,14 @@ func (api *API) postExternalAuthDeviceByID(rw http.ResponseWriter, r *http.Reque } } else { _, err = api.Database.UpdateExternalAuthLink(ctx, database.UpdateExternalAuthLinkParams{ - ProviderID: config.ID, - UserID: apiKey.UserID, - UpdatedAt: dbtime.Now(), - OAuthAccessToken: token.AccessToken, - OAuthRefreshToken: token.RefreshToken, - OAuthExpiry: token.Expiry, + ProviderID: config.ID, + UserID: apiKey.UserID, + UpdatedAt: dbtime.Now(), + OAuthAccessToken: token.AccessToken, + OAuthAccessTokenKeyID: sql.NullString{}, // dbcrypt will update as required + OAuthRefreshToken: token.RefreshToken, + OAuthRefreshTokenKeyID: sql.NullString{}, // dbcrypt will update as required + OAuthExpiry: token.Expiry, }) if err != nil { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ @@ -211,13 +215,15 @@ func (api *API) externalAuthCallback(externalAuthConfig *externalauth.Config) ht } _, err = api.Database.InsertExternalAuthLink(ctx, database.InsertExternalAuthLinkParams{ - ProviderID: externalAuthConfig.ID, - UserID: apiKey.UserID, - CreatedAt: dbtime.Now(), - UpdatedAt: dbtime.Now(), - OAuthAccessToken: state.Token.AccessToken, - OAuthRefreshToken: state.Token.RefreshToken, - OAuthExpiry: state.Token.Expiry, + ProviderID: externalAuthConfig.ID, + UserID: apiKey.UserID, + CreatedAt: dbtime.Now(), + UpdatedAt: dbtime.Now(), + OAuthAccessToken: state.Token.AccessToken, + OAuthAccessTokenKeyID: sql.NullString{}, // dbcrypt will set as required + OAuthRefreshToken: state.Token.RefreshToken, + OAuthRefreshTokenKeyID: sql.NullString{}, // dbcrypt will set as required + OAuthExpiry: state.Token.Expiry, }) if err != nil { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ @@ -228,12 +234,14 @@ func (api *API) externalAuthCallback(externalAuthConfig *externalauth.Config) ht } } else { _, err = api.Database.UpdateExternalAuthLink(ctx, database.UpdateExternalAuthLinkParams{ - ProviderID: externalAuthConfig.ID, - UserID: apiKey.UserID, - UpdatedAt: dbtime.Now(), - OAuthAccessToken: state.Token.AccessToken, - OAuthRefreshToken: state.Token.RefreshToken, - OAuthExpiry: state.Token.Expiry, + ProviderID: externalAuthConfig.ID, + UserID: apiKey.UserID, + UpdatedAt: dbtime.Now(), + OAuthAccessToken: state.Token.AccessToken, + OAuthAccessTokenKeyID: sql.NullString{}, // dbcrypt will update as required + OAuthRefreshToken: state.Token.RefreshToken, + OAuthRefreshTokenKeyID: sql.NullString{}, // dbcrypt will update as required + OAuthExpiry: state.Token.Expiry, }) if err != nil { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ diff --git a/coderd/externalauth/config.go b/coderd/externalauth/config.go index 51ef866354..08f2ef6db9 100644 --- a/coderd/externalauth/config.go +++ b/coderd/externalauth/config.go @@ -2,6 +2,7 @@ package externalauth import ( "context" + "database/sql" "encoding/json" "fmt" "io" @@ -120,18 +121,20 @@ validate: } if token.AccessToken != externalAuthLink.OAuthAccessToken { - // Update it - externalAuthLink, err = db.UpdateExternalAuthLink(ctx, database.UpdateExternalAuthLinkParams{ - ProviderID: c.ID, - UserID: externalAuthLink.UserID, - UpdatedAt: dbtime.Now(), - OAuthAccessToken: token.AccessToken, - OAuthRefreshToken: token.RefreshToken, - OAuthExpiry: token.Expiry, + updatedAuthLink, err := db.UpdateExternalAuthLink(ctx, database.UpdateExternalAuthLinkParams{ + ProviderID: c.ID, + UserID: externalAuthLink.UserID, + UpdatedAt: dbtime.Now(), + OAuthAccessToken: token.AccessToken, + OAuthAccessTokenKeyID: sql.NullString{}, // dbcrypt will update as required + OAuthRefreshToken: token.RefreshToken, + OAuthRefreshTokenKeyID: sql.NullString{}, // dbcrypt will update as required + OAuthExpiry: token.Expiry, }) if err != nil { - return externalAuthLink, false, xerrors.Errorf("update external auth link: %w", err) + return updatedAuthLink, false, xerrors.Errorf("update external auth link: %w", err) } + externalAuthLink = updatedAuthLink } return externalAuthLink, true, nil } diff --git a/coderd/httpmw/apikey.go b/coderd/httpmw/apikey.go index f2a7a0d3ec..9f6ea6fa1f 100644 --- a/coderd/httpmw/apikey.go +++ b/coderd/httpmw/apikey.go @@ -369,13 +369,15 @@ func ExtractAPIKey(rw http.ResponseWriter, r *http.Request, cfg ExtractAPIKeyCon // If the API Key is associated with a user_link (e.g. Github/OIDC) // then we want to update the relevant oauth fields. if link.UserID != uuid.Nil { - // nolint:gocritic + //nolint:gocritic // system needs to update user link link, err = cfg.DB.UpdateUserLink(dbauthz.AsSystemRestricted(ctx), database.UpdateUserLinkParams{ - UserID: link.UserID, - LoginType: link.LoginType, - OAuthAccessToken: link.OAuthAccessToken, - OAuthRefreshToken: link.OAuthRefreshToken, - OAuthExpiry: link.OAuthExpiry, + UserID: link.UserID, + LoginType: link.LoginType, + OAuthAccessToken: link.OAuthAccessToken, + OAuthAccessTokenKeyID: sql.NullString{}, // dbcrypt will update as required + OAuthRefreshToken: link.OAuthRefreshToken, + OAuthRefreshTokenKeyID: sql.NullString{}, // dbcrypt will update as required + OAuthExpiry: link.OAuthExpiry, }) if err != nil { return write(http.StatusInternalServerError, codersdk.Response{ @@ -388,7 +390,7 @@ func ExtractAPIKey(rw http.ResponseWriter, r *http.Request, cfg ExtractAPIKeyCon // We only want to update this occasionally to reduce DB write // load. We update alongside the UserLink and APIKey since it's // easier on the DB to colocate writes. - // nolint:gocritic + //nolint:gocritic // system needs to update user last seen at _, err = cfg.DB.UpdateUserLastSeenAt(dbauthz.AsSystemRestricted(ctx), database.UpdateUserLastSeenAtParams{ ID: key.UserID, LastSeenAt: dbtime.Now(), @@ -405,7 +407,7 @@ func ExtractAPIKey(rw http.ResponseWriter, r *http.Request, cfg ExtractAPIKeyCon // If the key is valid, we also fetch the user roles and status. // The roles are used for RBAC authorize checks, and the status // is to block 'suspended' users from accessing the platform. - // nolint:gocritic + //nolint:gocritic // system needs to update user roles roles, err := cfg.DB.GetAuthorizationUserRoles(dbauthz.AsSystemRestricted(ctx), key.UserID) if err != nil { return write(http.StatusUnauthorized, codersdk.Response{ diff --git a/coderd/organizations.go b/coderd/organizations.go index a9556900b0..ae24edea01 100644 --- a/coderd/organizations.go +++ b/coderd/organizations.go @@ -68,10 +68,11 @@ func (api *API) postOrganizations(rw http.ResponseWriter, r *http.Request) { var organization database.Organization err = api.Database.InTx(func(tx database.Store) error { organization, err = tx.InsertOrganization(ctx, database.InsertOrganizationParams{ - ID: uuid.New(), - Name: req.Name, - CreatedAt: dbtime.Now(), - UpdatedAt: dbtime.Now(), + ID: uuid.New(), + Name: req.Name, + CreatedAt: dbtime.Now(), + UpdatedAt: dbtime.Now(), + Description: "", }) if err != nil { return xerrors.Errorf("create organization: %w", err) diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go index bbda529af6..dd8bed7fef 100644 --- a/coderd/provisionerdserver/provisionerdserver.go +++ b/coderd/provisionerdserver/provisionerdserver.go @@ -263,18 +263,21 @@ func (s *server) AcquireJobWithCancel(stream proto.DRPCProvisionerDaemon_Acquire logger.Error(streamCtx, "recv error and failed to cancel acquire job", slog.Error(recvErr)) // Well, this is awkward. We hit an error receiving from the stream, but didn't cancel before we locked a job // in the database. We need to mark this job as failed so the end user can retry if they want to. + now := dbtime.Now() err := s.Database.UpdateProvisionerJobWithCompleteByID( context.Background(), database.UpdateProvisionerJobWithCompleteByIDParams{ ID: je.job.ID, CompletedAt: sql.NullTime{ - Time: dbtime.Now(), + Time: now, Valid: true, }, + UpdatedAt: now, Error: sql.NullString{ String: "connection to provisioner daemon broken", Valid: true, }, + ErrorCode: sql.NullString{}, }) if err != nil { logger.Error(streamCtx, "error updating failed job", slog.Error(err)) @@ -308,6 +311,7 @@ func (s *server) acquireProtoJob(ctx context.Context, job database.ProvisionerJo Valid: true, }, ErrorCode: job.ErrorCode, + UpdatedAt: dbtime.Now(), }) if err != nil { return xerrors.Errorf("update provisioner job: %w", err) @@ -651,6 +655,7 @@ func (s *server) UpdateJob(ctx context.Context, request *proto.UpdateJobRequest) } if len(request.Logs) > 0 { + //nolint:exhaustruct // We append to the additional fields below. insertParams := database.InsertProvisionerJobLogsParams{ JobID: parsedID, } @@ -1061,7 +1066,8 @@ func (s *server) CompleteJob(ctx context.Context, completed *proto.CompletedJob) Time: dbtime.Now(), Valid: true, }, - Error: completedError, + Error: completedError, + ErrorCode: sql.NullString{}, }) if err != nil { return nil, xerrors.Errorf("update provisioner job: %w", err) @@ -1118,6 +1124,8 @@ func (s *server) CompleteJob(ctx context.Context, completed *proto.CompletedJob) Time: dbtime.Now(), Valid: true, }, + Error: sql.NullString{}, + ErrorCode: sql.NullString{}, }) if err != nil { return xerrors.Errorf("update provisioner job: %w", err) @@ -1275,6 +1283,8 @@ func (s *server) CompleteJob(ctx context.Context, completed *proto.CompletedJob) Time: dbtime.Now(), Valid: true, }, + Error: sql.NullString{}, + ErrorCode: sql.NullString{}, }) if err != nil { return nil, xerrors.Errorf("update provisioner job: %w", err) @@ -1386,6 +1396,8 @@ func InsertWorkspaceResource(ctx context.Context, db database.Store, jobID uuid. TroubleshootingURL: prAgent.GetTroubleshootingUrl(), MOTDFile: prAgent.GetMotdFile(), DisplayApps: convertDisplayApps(prAgent.GetDisplayApps()), + InstanceMetadata: pqtype.NullRawMessage{}, + ResourceMetadata: pqtype.NullRawMessage{}, }) if err != nil { return xerrors.Errorf("insert agent: %w", err) @@ -1628,11 +1640,13 @@ func obtainOIDCAccessToken(ctx context.Context, db database.Store, oidcConfig ht link.OAuthExpiry = token.Expiry link, err = db.UpdateUserLink(ctx, database.UpdateUserLinkParams{ - UserID: userID, - LoginType: database.LoginTypeOIDC, - OAuthAccessToken: link.OAuthAccessToken, - OAuthRefreshToken: link.OAuthRefreshToken, - OAuthExpiry: link.OAuthExpiry, + UserID: userID, + LoginType: database.LoginTypeOIDC, + OAuthAccessToken: link.OAuthAccessToken, + OAuthAccessTokenKeyID: sql.NullString{}, // set by dbcrypt if required + OAuthRefreshToken: link.OAuthRefreshToken, + OAuthRefreshTokenKeyID: sql.NullString{}, // set by dbcrypt if required + OAuthExpiry: link.OAuthExpiry, }) if err != nil { return "", xerrors.Errorf("update user link: %w", err) diff --git a/coderd/unhanger/detector.go b/coderd/unhanger/detector.go index f83b8856c7..c250711b52 100644 --- a/coderd/unhanger/detector.go +++ b/coderd/unhanger/detector.go @@ -273,7 +273,12 @@ func unhangJob(ctx context.Context, log slog.Logger, db database.Store, pub pubs // Insert the messages into the build log. insertParams := database.InsertProvisionerJobLogsParams{ - JobID: job.ID, + JobID: job.ID, + CreatedAt: nil, + Source: nil, + Level: nil, + Stage: nil, + Output: nil, } now := dbtime.Now() for i, msg := range HungJobLogMessages { diff --git a/coderd/userauth.go b/coderd/userauth.go index 09e901114c..419a88b1b1 100644 --- a/coderd/userauth.go +++ b/coderd/userauth.go @@ -1327,14 +1327,16 @@ func (api *API) oauthLogin(r *http.Request, params *oauthLoginParams) ([]*http.C } if link.UserID == uuid.Nil { - //nolint:gocritic + //nolint:gocritic // System needs to insert the user link (linked_id, oauth_token, oauth_expiry). link, err = tx.InsertUserLink(dbauthz.AsSystemRestricted(ctx), database.InsertUserLinkParams{ - UserID: user.ID, - LoginType: params.LoginType, - LinkedID: params.LinkedID, - OAuthAccessToken: params.State.Token.AccessToken, - OAuthRefreshToken: params.State.Token.RefreshToken, - OAuthExpiry: params.State.Token.Expiry, + UserID: user.ID, + LoginType: params.LoginType, + LinkedID: params.LinkedID, + OAuthAccessToken: params.State.Token.AccessToken, + OAuthAccessTokenKeyID: sql.NullString{}, // set by dbcrypt if required + OAuthRefreshToken: params.State.Token.RefreshToken, + OAuthRefreshTokenKeyID: sql.NullString{}, // set by dbcrypt if required + OAuthExpiry: params.State.Token.Expiry, }) if err != nil { return xerrors.Errorf("insert user link: %w", err) @@ -1342,13 +1344,15 @@ func (api *API) oauthLogin(r *http.Request, params *oauthLoginParams) ([]*http.C } if link.UserID != uuid.Nil { - //nolint:gocritic + //nolint:gocritic // System needs to update the user link (linked_id, oauth_token, oauth_expiry). link, err = tx.UpdateUserLink(dbauthz.AsSystemRestricted(ctx), database.UpdateUserLinkParams{ - UserID: user.ID, - LoginType: params.LoginType, - OAuthAccessToken: params.State.Token.AccessToken, - OAuthRefreshToken: params.State.Token.RefreshToken, - OAuthExpiry: params.State.Token.Expiry, + UserID: user.ID, + LoginType: params.LoginType, + OAuthAccessToken: params.State.Token.AccessToken, + OAuthAccessTokenKeyID: sql.NullString{}, // set by dbcrypt if required + OAuthRefreshToken: params.State.Token.RefreshToken, + OAuthRefreshTokenKeyID: sql.NullString{}, // set by dbcrypt if required + OAuthExpiry: params.State.Token.Expiry, }) if err != nil { return xerrors.Errorf("update user link: %w", err) diff --git a/coderd/users.go b/coderd/users.go index bce7136726..9c0a4757e0 100644 --- a/coderd/users.go +++ b/coderd/users.go @@ -1079,10 +1079,11 @@ func (api *API) CreateUser(ctx context.Context, store database.Store, req Create } organization, err := tx.InsertOrganization(ctx, database.InsertOrganizationParams{ - ID: uuid.New(), - Name: req.Username, - CreatedAt: dbtime.Now(), - UpdatedAt: dbtime.Now(), + ID: uuid.New(), + Name: req.Username, + CreatedAt: dbtime.Now(), + UpdatedAt: dbtime.Now(), + Description: "", }) if err != nil { return xerrors.Errorf("create organization: %w", err) @@ -1101,11 +1102,12 @@ func (api *API) CreateUser(ctx context.Context, store database.Store, req Create } params := database.InsertUserParams{ - ID: uuid.New(), - Email: req.Email, - Username: req.Username, - CreatedAt: dbtime.Now(), - UpdatedAt: dbtime.Now(), + ID: uuid.New(), + Email: req.Email, + Username: req.Username, + CreatedAt: dbtime.Now(), + UpdatedAt: dbtime.Now(), + HashedPassword: []byte{}, // All new users are defaulted to members of the site. RBACRoles: []string{}, LoginType: req.LoginType, diff --git a/coderd/wsbuilder/wsbuilder.go b/coderd/wsbuilder/wsbuilder.go index 19c3496349..f7c1699d29 100644 --- a/coderd/wsbuilder/wsbuilder.go +++ b/coderd/wsbuilder/wsbuilder.go @@ -8,6 +8,7 @@ import ( "encoding/json" "fmt" "net/http" + "time" "github.com/google/uuid" "github.com/lib/pq" @@ -350,6 +351,8 @@ func (b *Builder) buildTx(authFunc func(action rbac.Action, object rbac.Objecter Transition: b.trans, JobID: provisionerJob.ID, Reason: b.reason, + Deadline: time.Time{}, // set by provisioner upon completion + MaxDeadline: time.Time{}, // set by provisioner upon completion }) if err != nil { return BuildError{http.StatusInternalServerError, "insert workspace build", err} diff --git a/enterprise/dbcrypt/cliutil.go b/enterprise/dbcrypt/cliutil.go index 8ffc8347e6..2e375a5112 100644 --- a/enterprise/dbcrypt/cliutil.go +++ b/enterprise/dbcrypt/cliutil.go @@ -25,8 +25,8 @@ func Rotate(ctx context.Context, log slog.Logger, sqlDB *sql.DB, ciphers []Ciphe } log.Info(ctx, "encrypting user tokens", slog.F("user_count", len(userIDs))) for idx, uid := range userIDs { - err := cryptDB.InTx(func(tx database.Store) error { - userLinks, err := tx.GetUserLinksByUserID(ctx, uid) + err := cryptDB.InTx(func(cryptTx database.Store) error { + userLinks, err := cryptTx.GetUserLinksByUserID(ctx, uid) if err != nil { return xerrors.Errorf("get user links for user: %w", err) } @@ -35,18 +35,20 @@ func Rotate(ctx context.Context, log slog.Logger, sqlDB *sql.DB, ciphers []Ciphe log.Debug(ctx, "skipping user link", slog.F("user_id", uid), slog.F("current", idx+1), slog.F("cipher", ciphers[0].HexDigest())) continue } - if _, err := tx.UpdateUserLink(ctx, database.UpdateUserLinkParams{ - OAuthAccessToken: userLink.OAuthAccessToken, - OAuthRefreshToken: userLink.OAuthRefreshToken, - OAuthExpiry: userLink.OAuthExpiry, - UserID: uid, - LoginType: userLink.LoginType, + if _, err := cryptTx.UpdateUserLink(ctx, database.UpdateUserLinkParams{ + OAuthAccessToken: userLink.OAuthAccessToken, + OAuthAccessTokenKeyID: sql.NullString{}, // dbcrypt will update as required + OAuthRefreshToken: userLink.OAuthRefreshToken, + OAuthRefreshTokenKeyID: sql.NullString{}, // dbcrypt will update as required + OAuthExpiry: userLink.OAuthExpiry, + UserID: uid, + LoginType: userLink.LoginType, }); err != nil { return xerrors.Errorf("update user link user_id=%s linked_id=%s: %w", userLink.UserID, userLink.LinkedID, err) } } - gitAuthLinks, err := tx.GetExternalAuthLinksByUserID(ctx, uid) + gitAuthLinks, err := cryptTx.GetExternalAuthLinksByUserID(ctx, uid) if err != nil { return xerrors.Errorf("get git auth links for user: %w", err) } @@ -55,13 +57,15 @@ func Rotate(ctx context.Context, log slog.Logger, sqlDB *sql.DB, ciphers []Ciphe log.Debug(ctx, "skipping git auth link", slog.F("user_id", uid), slog.F("current", idx+1), slog.F("cipher", ciphers[0].HexDigest())) continue } - if _, err := tx.UpdateExternalAuthLink(ctx, database.UpdateExternalAuthLinkParams{ - ProviderID: gitAuthLink.ProviderID, - UserID: uid, - UpdatedAt: gitAuthLink.UpdatedAt, - OAuthAccessToken: gitAuthLink.OAuthAccessToken, - OAuthRefreshToken: gitAuthLink.OAuthRefreshToken, - OAuthExpiry: gitAuthLink.OAuthExpiry, + if _, err := cryptTx.UpdateExternalAuthLink(ctx, database.UpdateExternalAuthLinkParams{ + ProviderID: gitAuthLink.ProviderID, + UserID: uid, + UpdatedAt: gitAuthLink.UpdatedAt, + OAuthAccessToken: gitAuthLink.OAuthAccessToken, + OAuthAccessTokenKeyID: sql.NullString{}, // dbcrypt will update as required + OAuthRefreshToken: gitAuthLink.OAuthRefreshToken, + OAuthRefreshTokenKeyID: sql.NullString{}, // dbcrypt will update as required + OAuthExpiry: gitAuthLink.OAuthExpiry, }); err != nil { return xerrors.Errorf("update git auth link user_id=%s provider_id=%s: %w", gitAuthLink.UserID, gitAuthLink.ProviderID, err) } @@ -120,11 +124,13 @@ func Decrypt(ctx context.Context, log slog.Logger, sqlDB *sql.DB, ciphers []Ciph continue } if _, err := tx.UpdateUserLink(ctx, database.UpdateUserLinkParams{ - OAuthAccessToken: userLink.OAuthAccessToken, - OAuthRefreshToken: userLink.OAuthRefreshToken, - OAuthExpiry: userLink.OAuthExpiry, - UserID: uid, - LoginType: userLink.LoginType, + OAuthAccessToken: userLink.OAuthAccessToken, + OAuthAccessTokenKeyID: sql.NullString{}, // we explicitly want to clear the key id + OAuthRefreshToken: userLink.OAuthRefreshToken, + OAuthRefreshTokenKeyID: sql.NullString{}, // we explicitly want to clear the key id + OAuthExpiry: userLink.OAuthExpiry, + UserID: uid, + LoginType: userLink.LoginType, }); err != nil { return xerrors.Errorf("update user link user_id=%s linked_id=%s: %w", userLink.UserID, userLink.LinkedID, err) } @@ -140,12 +146,14 @@ func Decrypt(ctx context.Context, log slog.Logger, sqlDB *sql.DB, ciphers []Ciph continue } if _, err := tx.UpdateExternalAuthLink(ctx, database.UpdateExternalAuthLinkParams{ - ProviderID: gitAuthLink.ProviderID, - UserID: uid, - UpdatedAt: gitAuthLink.UpdatedAt, - OAuthAccessToken: gitAuthLink.OAuthAccessToken, - OAuthRefreshToken: gitAuthLink.OAuthRefreshToken, - OAuthExpiry: gitAuthLink.OAuthExpiry, + ProviderID: gitAuthLink.ProviderID, + UserID: uid, + UpdatedAt: gitAuthLink.UpdatedAt, + OAuthAccessToken: gitAuthLink.OAuthAccessToken, + OAuthAccessTokenKeyID: sql.NullString{}, // we explicitly want to clear the key id + OAuthRefreshToken: gitAuthLink.OAuthRefreshToken, + OAuthRefreshTokenKeyID: sql.NullString{}, // we explicitly want to clear the key id + OAuthExpiry: gitAuthLink.OAuthExpiry, }); err != nil { return xerrors.Errorf("update git auth link user_id=%s provider_id=%s: %w", gitAuthLink.UserID, gitAuthLink.ProviderID, err) } diff --git a/enterprise/replicasync/replicasync.go b/enterprise/replicasync/replicasync.go index 80b03e4d69..1d6cd349b3 100644 --- a/enterprise/replicasync/replicasync.go +++ b/enterprise/replicasync/replicasync.go @@ -420,11 +420,13 @@ func (m *Manager) Close() error { Time: dbtime.Now(), Valid: true, }, - RelayAddress: m.self.RelayAddress, - RegionID: m.self.RegionID, - Hostname: m.self.Hostname, - Version: m.self.Version, - Error: m.self.Error, + RelayAddress: m.self.RelayAddress, + RegionID: m.self.RegionID, + Hostname: m.self.Hostname, + Version: m.self.Version, + Error: m.self.Error, + DatabaseLatency: 0, // A stopped replica has no latency. + Primary: false, // A stopped replica cannot be primary. }) if err != nil { return xerrors.Errorf("update replica: %w", err)