mirror of
https://github.com/coder/coder.git
synced 2025-07-08 11:39:50 +00:00
fix(enterprise/dbcrypt): do not skip deleted users when encrypting or deleting (#9694)
- Broadens scope of data generation in TestServerDBCrypt over all user login types, statuses, and deletion status. - Adds support for specifying user status / user deletion status in dbgen - Adds more comprehensive logging in TestServerDBCrypt upon test failure (to be generalized and expanded upon in a follow-up) - Adds AllUserIDs query, updates dbcrypt to use this instead of GetUsers.
This commit is contained in:
@ -664,6 +664,15 @@ func (q *querier) ActivityBumpWorkspace(ctx context.Context, arg uuid.UUID) erro
|
||||
return update(q.log, q.auth, fetch, q.db.ActivityBumpWorkspace)(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) AllUserIDs(ctx context.Context) ([]uuid.UUID, error) {
|
||||
// Although this technically only reads users, only system-related functions should be
|
||||
// allowed to call this.
|
||||
if err := q.authorizeContext(ctx, rbac.ActionRead, rbac.ResourceSystem); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return q.db.AllUserIDs(ctx)
|
||||
}
|
||||
|
||||
func (q *querier) CleanTailnetCoordinators(ctx context.Context) error {
|
||||
if err := q.authorizeContext(ctx, rbac.ActionDelete, rbac.ResourceTailnetCoordinator); err != nil {
|
||||
return err
|
||||
|
@ -812,6 +812,16 @@ func (q *FakeQuerier) ActivityBumpWorkspace(ctx context.Context, workspaceID uui
|
||||
return sql.ErrNoRows
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) AllUserIDs(_ context.Context) ([]uuid.UUID, error) {
|
||||
q.mutex.RLock()
|
||||
defer q.mutex.RUnlock()
|
||||
userIDs := make([]uuid.UUID, 0, len(q.users))
|
||||
for idx := range q.users {
|
||||
userIDs[idx] = q.users[idx].ID
|
||||
}
|
||||
return userIDs, nil
|
||||
}
|
||||
|
||||
func (*FakeQuerier) CleanTailnetCoordinators(_ context.Context) error {
|
||||
return ErrUnimplemented
|
||||
}
|
||||
|
@ -227,7 +227,7 @@ func User(t testing.TB, db database.Store, orig database.User) database.User {
|
||||
|
||||
user, err = db.UpdateUserStatus(genCtx, database.UpdateUserStatusParams{
|
||||
ID: user.ID,
|
||||
Status: database.UserStatusActive,
|
||||
Status: takeFirst(orig.Status, database.UserStatusActive),
|
||||
UpdatedAt: dbtime.Now(),
|
||||
})
|
||||
require.NoError(t, err, "insert user")
|
||||
@ -240,6 +240,14 @@ func User(t testing.TB, db database.Store, orig database.User) database.User {
|
||||
})
|
||||
require.NoError(t, err, "user last seen")
|
||||
}
|
||||
|
||||
if orig.Deleted {
|
||||
err = db.UpdateUserDeletedByID(genCtx, database.UpdateUserDeletedByIDParams{
|
||||
ID: user.ID,
|
||||
Deleted: orig.Deleted,
|
||||
})
|
||||
require.NoError(t, err, "set user as deleted")
|
||||
}
|
||||
return user
|
||||
}
|
||||
|
||||
|
@ -100,6 +100,13 @@ func (m metricsStore) ActivityBumpWorkspace(ctx context.Context, arg uuid.UUID)
|
||||
return r0
|
||||
}
|
||||
|
||||
func (m metricsStore) AllUserIDs(ctx context.Context) ([]uuid.UUID, error) {
|
||||
start := time.Now()
|
||||
r0, r1 := m.s.AllUserIDs(ctx)
|
||||
m.queryLatencies.WithLabelValues("AllUserIDs").Observe(time.Since(start).Seconds())
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
func (m metricsStore) CleanTailnetCoordinators(ctx context.Context) error {
|
||||
start := time.Now()
|
||||
err := m.s.CleanTailnetCoordinators(ctx)
|
||||
|
@ -82,6 +82,21 @@ func (mr *MockStoreMockRecorder) ActivityBumpWorkspace(arg0, arg1 interface{}) *
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ActivityBumpWorkspace", reflect.TypeOf((*MockStore)(nil).ActivityBumpWorkspace), arg0, arg1)
|
||||
}
|
||||
|
||||
// AllUserIDs mocks base method.
|
||||
func (m *MockStore) AllUserIDs(arg0 context.Context) ([]uuid.UUID, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AllUserIDs", arg0)
|
||||
ret0, _ := ret[0].([]uuid.UUID)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// AllUserIDs indicates an expected call of AllUserIDs.
|
||||
func (mr *MockStoreMockRecorder) AllUserIDs(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AllUserIDs", reflect.TypeOf((*MockStore)(nil).AllUserIDs), arg0)
|
||||
}
|
||||
|
||||
// CleanTailnetCoordinators mocks base method.
|
||||
func (m *MockStore) CleanTailnetCoordinators(arg0 context.Context) error {
|
||||
m.ctrl.T.Helper()
|
||||
|
@ -31,6 +31,8 @@ type sqlcQuerier interface {
|
||||
// We only bump if workspace shutdown is manual.
|
||||
// We only bump when 5% of the deadline has elapsed.
|
||||
ActivityBumpWorkspace(ctx context.Context, workspaceID uuid.UUID) error
|
||||
// AllUserIDs returns all UserIDs regardless of user status or deletion.
|
||||
AllUserIDs(ctx context.Context) ([]uuid.UUID, error)
|
||||
CleanTailnetCoordinators(ctx context.Context) error
|
||||
DeleteAPIKeyByID(ctx context.Context, id string) error
|
||||
DeleteAPIKeysByUserID(ctx context.Context, userID uuid.UUID) error
|
||||
|
@ -5846,6 +5846,34 @@ func (q *sqlQuerier) UpdateUserLinkedID(ctx context.Context, arg UpdateUserLinke
|
||||
return i, err
|
||||
}
|
||||
|
||||
const allUserIDs = `-- name: AllUserIDs :many
|
||||
SELECT DISTINCT id FROM USERS
|
||||
`
|
||||
|
||||
// AllUserIDs returns all UserIDs regardless of user status or deletion.
|
||||
func (q *sqlQuerier) AllUserIDs(ctx context.Context) ([]uuid.UUID, error) {
|
||||
rows, err := q.db.QueryContext(ctx, allUserIDs)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer rows.Close()
|
||||
var items []uuid.UUID
|
||||
for rows.Next() {
|
||||
var id uuid.UUID
|
||||
if err := rows.Scan(&id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
items = append(items, id)
|
||||
}
|
||||
if err := rows.Close(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return items, nil
|
||||
}
|
||||
|
||||
const getActiveUserCount = `-- name: GetActiveUserCount :one
|
||||
SELECT
|
||||
COUNT(*)
|
||||
|
@ -16,3 +16,4 @@ AND
|
||||
INSERT INTO dbcrypt_keys
|
||||
(number, active_key_digest, created_at, test)
|
||||
VALUES (@number::int, @active_key_digest::text, CURRENT_TIMESTAMP, @test::text);
|
||||
|
||||
|
@ -262,3 +262,8 @@ WHERE
|
||||
last_seen_at < @last_seen_after :: timestamp
|
||||
AND status = 'active'::user_status
|
||||
RETURNING id, email, last_seen_at;
|
||||
|
||||
-- AllUserIDs returns all UserIDs regardless of user status or deletion.
|
||||
-- name: AllUserIDs :many
|
||||
SELECT DISTINCT id FROM USERS;
|
||||
|
||||
|
Reference in New Issue
Block a user