From 36451d5120014390ab68a0457554299cdb6733dd Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Mon, 1 Apr 2024 20:45:31 +0000 Subject: [PATCH 01/19] feat: add owner groups to workspace data --- coderd/database/dbauthz/dbauthz.go | 4 + coderd/database/dbmem/dbmem.go | 4 + coderd/database/dbmetrics/dbmetrics.go | 7 + coderd/database/dbmock/dbmock.go | 15 + coderd/database/querier.go | 1 + coderd/database/queries.sql.go | 44 +++ coderd/database/queries/groupmembers.sql | 12 + .../provisionerdserver/provisionerdserver.go | 9 + coderd/wsbuilder/wsbuilder.go | 26 ++ provisionersdk/proto/provisioner.pb.go | 266 +++++++++--------- provisionersdk/proto/provisioner.proto | 1 + site/e2e/provisionerGenerated.ts | 4 + 12 files changed, 266 insertions(+), 127 deletions(-) diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index 97a695cb376c6..16538d4221352 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -1145,6 +1145,10 @@ func (q *querier) GetGroupsByOrganizationID(ctx context.Context, organizationID return fetchWithPostFilter(q.auth, q.db.GetGroupsByOrganizationID)(ctx, organizationID) } +func (q *querier) GetGroupsByUserId(ctx context.Context, userID uuid.UUID) ([]database.Group, error) { + panic("not implemented") +} + func (q *querier) GetHealthSettings(ctx context.Context) (string, error) { // No authz checks return q.db.GetHealthSettings(ctx) diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index 8bb8559be779f..8664826465653 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -2264,6 +2264,10 @@ func (q *FakeQuerier) GetGroupsByOrganizationID(_ context.Context, id uuid.UUID) return groups, nil } +func (q *FakeQuerier) GetGroupsByUserId(ctx context.Context, userID uuid.UUID) ([]database.Group, error) { + panic("not implemented") +} + func (q *FakeQuerier) GetHealthSettings(_ context.Context) (string, error) { q.mutex.RLock() defer q.mutex.RUnlock() diff --git a/coderd/database/dbmetrics/dbmetrics.go b/coderd/database/dbmetrics/dbmetrics.go index 5cd452d328e16..3660920b69ad9 100644 --- a/coderd/database/dbmetrics/dbmetrics.go +++ b/coderd/database/dbmetrics/dbmetrics.go @@ -566,6 +566,13 @@ func (m metricsStore) GetGroupsByOrganizationID(ctx context.Context, organizatio return groups, err } +func (m metricsStore) GetGroupsByUserId(ctx context.Context, userID uuid.UUID) ([]database.Group, error) { + start := time.Now() + r0, r1 := m.s.GetGroupsByUserId(ctx, userID) + m.queryLatencies.WithLabelValues("GetGroupsByUserId").Observe(time.Since(start).Seconds()) + return r0, r1 +} + func (m metricsStore) GetHealthSettings(ctx context.Context) (string, error) { start := time.Now() r0, r1 := m.s.GetHealthSettings(ctx) diff --git a/coderd/database/dbmock/dbmock.go b/coderd/database/dbmock/dbmock.go index 32049ba0721b7..9264d0a355765 100644 --- a/coderd/database/dbmock/dbmock.go +++ b/coderd/database/dbmock/dbmock.go @@ -1110,6 +1110,21 @@ func (mr *MockStoreMockRecorder) GetGroupsByOrganizationID(arg0, arg1 any) *gomo return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGroupsByOrganizationID", reflect.TypeOf((*MockStore)(nil).GetGroupsByOrganizationID), arg0, arg1) } +// GetGroupsByUserId mocks base method. +func (m *MockStore) GetGroupsByUserId(arg0 context.Context, arg1 uuid.UUID) ([]database.Group, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetGroupsByUserId", arg0, arg1) + ret0, _ := ret[0].([]database.Group) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetGroupsByUserId indicates an expected call of GetGroupsByUserId. +func (mr *MockStoreMockRecorder) GetGroupsByUserId(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGroupsByUserId", reflect.TypeOf((*MockStore)(nil).GetGroupsByUserId), arg0, arg1) +} + // GetHealthSettings mocks base method. func (m *MockStore) GetHealthSettings(arg0 context.Context) (string, error) { m.ctrl.T.Helper() diff --git a/coderd/database/querier.go b/coderd/database/querier.go index bf1a1909fe765..04acbca4d1f39 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -124,6 +124,7 @@ type sqlcQuerier interface { // If it is the "Everyone" group, then we need to check the organization_members table. GetGroupMembers(ctx context.Context, groupID uuid.UUID) ([]User, error) GetGroupsByOrganizationID(ctx context.Context, organizationID uuid.UUID) ([]Group, error) + GetGroupsByUserId(ctx context.Context, userID uuid.UUID) ([]Group, error) GetHealthSettings(ctx context.Context) (string, error) GetHungProvisionerJobs(ctx context.Context, updatedAt time.Time) ([]ProvisionerJob, error) GetJFrogXrayScanByWorkspaceAndAgentID(ctx context.Context, arg GetJFrogXrayScanByWorkspaceAndAgentIDParams) (JfrogXrayScan, error) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index b3216fc2d8c80..09e85344a3d42 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -1353,6 +1353,50 @@ func (q *sqlQuerier) GetGroupMembers(ctx context.Context, groupID uuid.UUID) ([] return items, nil } +const getGroupsByUserId = `-- name: GetGroupsByUserId :many +SELECT + groups.id, groups.name, groups.organization_id, groups.avatar_url, groups.quota_allowance, groups.display_name, groups.source +FROM + groups +LEFT JOIN + group_members +ON + group_members.group_id = groups.id +WHERE + group_members.user_id = $1 +` + +func (q *sqlQuerier) GetGroupsByUserId(ctx context.Context, userID uuid.UUID) ([]Group, error) { + rows, err := q.db.QueryContext(ctx, getGroupsByUserId, userID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Group + for rows.Next() { + var i Group + if err := rows.Scan( + &i.ID, + &i.Name, + &i.OrganizationID, + &i.AvatarURL, + &i.QuotaAllowance, + &i.DisplayName, + &i.Source, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const insertGroupMember = `-- name: InsertGroupMember :exec INSERT INTO group_members (user_id, group_id) diff --git a/coderd/database/queries/groupmembers.sql b/coderd/database/queries/groupmembers.sql index d755212132383..733559d0ebb38 100644 --- a/coderd/database/queries/groupmembers.sql +++ b/coderd/database/queries/groupmembers.sql @@ -23,6 +23,18 @@ WHERE AND users.deleted = 'false'; +-- name: GetGroupsByUserId :many +SELECT + groups.* +FROM + groups +LEFT JOIN + group_members +ON + group_members.group_id = groups.id +WHERE + group_members.user_id = @user_id; + -- InsertUserGroupsByName adds a user to all provided groups, if they exist. -- name: InsertUserGroupsByName :exec WITH groups AS ( diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go index 6183ffc02862a..d7696145fd8cd 100644 --- a/coderd/provisionerdserver/provisionerdserver.go +++ b/coderd/provisionerdserver/provisionerdserver.go @@ -467,6 +467,14 @@ func (s *server) acquireProtoJob(ctx context.Context, job database.ProvisionerJo if err != nil { return nil, failJob(fmt.Sprintf("get owner: %s", err)) } + ownerGroups, err := s.Database.GetGroupsByUserId(ctx, owner.ID) + ownerGroupNames := make([]string, 0, len(ownerGroups)) + for _, group := range ownerGroups { + ownerGroupNames = append(ownerGroupNames, group.Name) + } + if err != nil { + return nil, failJob(fmt.Sprintf("get owner groups: %s", err)) + } err = s.Pubsub.Publish(codersdk.WorkspaceNotifyChannel(workspace.ID), []byte{}) if err != nil { return nil, failJob(fmt.Sprintf("publish workspace update: %s", err)) @@ -567,6 +575,7 @@ func (s *server) acquireProtoJob(ctx context.Context, job database.ProvisionerJo WorkspaceOwner: owner.Username, WorkspaceOwnerEmail: owner.Email, WorkspaceOwnerName: owner.Name, + WorkspaceOwnerGroups: ownerGroupNames, WorkspaceOwnerOidcAccessToken: workspaceOwnerOIDCAccessToken, WorkspaceId: workspace.ID.String(), WorkspaceOwnerId: owner.ID.String(), diff --git a/coderd/wsbuilder/wsbuilder.go b/coderd/wsbuilder/wsbuilder.go index 810f52502c6f8..6668aec6bc441 100644 --- a/coderd/wsbuilder/wsbuilder.go +++ b/coderd/wsbuilder/wsbuilder.go @@ -197,6 +197,32 @@ func (e BuildError) Unwrap() error { return e.Wrapped } +type Adder interface { + Add() int +} + +type myAdder struct { + val int +} + +func (m *myAdder) Add() int { + return m.val +} + +func sum(adder []Adder) int { + sum := 0 + for _, a := range adder { + sum += a.Add() + } + return sum +} + +var x = sum([]Adder{&myAdder{ + val: 2, +}, &myAdder{ + val: 4, +}}) + // Build computes and inserts a new workspace build into the database. If authFunc is provided, it also performs // authorization preflight checks. func (b *Builder) Build( diff --git a/provisionersdk/proto/provisioner.pb.go b/provisionersdk/proto/provisioner.pb.go index f91be315a5b82..99d7b2e26a695 100644 --- a/provisionersdk/proto/provisioner.pb.go +++ b/provisionersdk/proto/provisioner.pb.go @@ -1637,6 +1637,7 @@ type Metadata struct { WorkspaceOwnerSessionToken string `protobuf:"bytes,11,opt,name=workspace_owner_session_token,json=workspaceOwnerSessionToken,proto3" json:"workspace_owner_session_token,omitempty"` TemplateId string `protobuf:"bytes,12,opt,name=template_id,json=templateId,proto3" json:"template_id,omitempty"` WorkspaceOwnerName string `protobuf:"bytes,13,opt,name=workspace_owner_name,json=workspaceOwnerName,proto3" json:"workspace_owner_name,omitempty"` + WorkspaceOwnerGroups []string `protobuf:"bytes,14,rep,name=workspace_owner_groups,json=workspaceOwnerGroups,proto3" json:"workspace_owner_groups,omitempty"` } func (x *Metadata) Reset() { @@ -1762,6 +1763,13 @@ func (x *Metadata) GetWorkspaceOwnerName() string { return "" } +func (x *Metadata) GetWorkspaceOwnerGroups() []string { + if x != nil { + return x.WorkspaceOwnerGroups + } + return nil +} + // Config represents execution configuration shared by all subsequent requests in the Session type Config struct { state protoimpl.MessageState @@ -2868,7 +2876,7 @@ var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{ 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x73, 0x5f, 0x6e, 0x75, 0x6c, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, - 0x73, 0x4e, 0x75, 0x6c, 0x6c, 0x22, 0x81, 0x05, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x73, 0x4e, 0x75, 0x6c, 0x6c, 0x22, 0xb7, 0x05, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x55, 0x72, 0x6c, 0x12, 0x53, 0x0a, 0x14, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x74, 0x72, 0x61, @@ -2908,133 +2916,137 @@ var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{ 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x14, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x8a, 0x01, 0x0a, 0x06, 0x43, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x12, 0x36, 0x0a, 0x17, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, - 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x61, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x15, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x53, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, 0x65, 0x12, 0x14, 0x0a, 0x05, - 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, - 0x74, 0x65, 0x12, 0x32, 0x0a, 0x15, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, - 0x72, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x13, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x4c, 0x6f, - 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x0e, 0x0a, 0x0c, 0x50, 0x61, 0x72, 0x73, 0x65, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x8b, 0x01, 0x0a, 0x0d, 0x50, 0x61, 0x72, 0x73, 0x65, - 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, - 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x4c, - 0x0a, 0x12, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, - 0x62, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, - 0x65, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x11, 0x74, 0x65, 0x6d, 0x70, 0x6c, - 0x61, 0x74, 0x65, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, - 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x65, - 0x61, 0x64, 0x6d, 0x65, 0x22, 0xb5, 0x02, 0x0a, 0x0b, 0x50, 0x6c, 0x61, 0x6e, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, - 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x53, 0x0a, 0x15, 0x72, 0x69, 0x63, 0x68, 0x5f, - 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, - 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x13, 0x72, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, - 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x43, 0x0a, 0x0f, - 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, - 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x52, 0x0e, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, - 0x73, 0x12, 0x59, 0x0a, 0x17, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x75, - 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, - 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, - 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x15, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, - 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x22, 0xf8, 0x01, 0x0a, - 0x0c, 0x50, 0x6c, 0x61, 0x6e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x14, 0x0a, - 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, - 0x72, 0x6f, 0x72, 0x12, 0x33, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x3a, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x61, - 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, + 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x34, 0x0a, 0x16, 0x77, 0x6f, 0x72, + 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x67, 0x72, 0x6f, + 0x75, 0x70, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x09, 0x52, 0x14, 0x77, 0x6f, 0x72, 0x6b, 0x73, + 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x47, 0x72, 0x6f, 0x75, 0x70, 0x73, 0x22, + 0x8a, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x36, 0x0a, 0x17, 0x74, 0x65, + 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x61, 0x72, + 0x63, 0x68, 0x69, 0x76, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x15, 0x74, 0x65, 0x6d, + 0x70, 0x6c, 0x61, 0x74, 0x65, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x41, 0x72, 0x63, 0x68, 0x69, + 0x76, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x32, 0x0a, 0x15, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, + 0x6c, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x0e, 0x0a, 0x0c, + 0x50, 0x61, 0x72, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x8b, 0x01, 0x0a, + 0x0d, 0x50, 0x61, 0x72, 0x73, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x14, + 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x12, 0x4c, 0x0a, 0x12, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, + 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x54, + 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x52, + 0x11, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, + 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, 0x22, 0xb5, 0x02, 0x0a, 0x0b, 0x50, + 0x6c, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x53, 0x0a, + 0x15, 0x72, 0x69, 0x63, 0x68, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, + 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, - 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, - 0x74, 0x65, 0x72, 0x73, 0x12, 0x61, 0x0a, 0x17, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, - 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x18, - 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, - 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x52, 0x15, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, - 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x22, 0x41, 0x0a, 0x0c, 0x41, 0x70, 0x70, 0x6c, 0x79, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, - 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, - 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x8f, 0x02, 0x0a, 0x0d, 0x41, - 0x70, 0x70, 0x6c, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, - 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, - 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x33, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x3a, 0x0a, - 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, - 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x52, 0x0a, 0x70, - 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x61, 0x0a, 0x17, 0x65, 0x78, 0x74, - 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x64, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, - 0x6c, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x15, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, - 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x22, 0x0f, 0x0a, 0x0d, - 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x8c, 0x02, - 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2d, 0x0a, 0x06, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, - 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x31, 0x0a, 0x05, 0x70, 0x61, 0x72, 0x73, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x48, 0x00, 0x52, 0x05, 0x70, 0x61, 0x72, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x04, 0x70, - 0x6c, 0x61, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x12, 0x31, 0x0a, 0x05, 0x61, - 0x70, 0x70, 0x6c, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x12, 0x34, - 0x0a, 0x06, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, - 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x43, 0x61, 0x6e, - 0x63, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x63, 0x61, - 0x6e, 0x63, 0x65, 0x6c, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xd1, 0x01, 0x0a, - 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, 0x0a, 0x03, 0x6c, 0x6f, 0x67, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x48, 0x00, 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x12, - 0x32, 0x0a, 0x05, 0x70, 0x61, 0x72, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, - 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, - 0x73, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x05, 0x70, 0x61, - 0x72, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, - 0x50, 0x6c, 0x61, 0x6e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x04, - 0x70, 0x6c, 0x61, 0x6e, 0x12, 0x32, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, - 0x72, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x48, - 0x00, 0x52, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, - 0x2a, 0x3f, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x09, 0x0a, 0x05, - 0x54, 0x52, 0x41, 0x43, 0x45, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x45, 0x42, 0x55, 0x47, - 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, - 0x57, 0x41, 0x52, 0x4e, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, - 0x04, 0x2a, 0x3b, 0x0a, 0x0f, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4c, - 0x65, 0x76, 0x65, 0x6c, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x57, 0x4e, 0x45, 0x52, 0x10, 0x00, 0x12, - 0x11, 0x0a, 0x0d, 0x41, 0x55, 0x54, 0x48, 0x45, 0x4e, 0x54, 0x49, 0x43, 0x41, 0x54, 0x45, 0x44, - 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x10, 0x02, 0x2a, 0x37, - 0x0a, 0x13, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x54, 0x41, 0x52, 0x54, 0x10, 0x00, - 0x12, 0x08, 0x0a, 0x04, 0x53, 0x54, 0x4f, 0x50, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, - 0x53, 0x54, 0x52, 0x4f, 0x59, 0x10, 0x02, 0x32, 0x49, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x12, 0x3a, 0x0a, 0x07, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, - 0x6e, 0x12, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, - 0x30, 0x01, 0x42, 0x30, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x76, 0x32, 0x2f, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x73, 0x64, 0x6b, 0x2f, 0x70, - 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x13, 0x72, + 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, + 0x65, 0x73, 0x12, 0x43, 0x0a, 0x0f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, + 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0e, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, + 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x59, 0x0a, 0x17, 0x65, 0x78, 0x74, 0x65, 0x72, + 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, + 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, + 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x15, 0x65, 0x78, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, + 0x72, 0x73, 0x22, 0xf8, 0x01, 0x0a, 0x0c, 0x50, 0x6c, 0x61, 0x6e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, + 0x65, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x33, 0x0a, 0x09, 0x72, 0x65, 0x73, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x3a, + 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x52, 0x0a, + 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x61, 0x0a, 0x17, 0x65, 0x78, + 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x64, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x29, 0x2e, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x45, 0x78, 0x74, 0x65, 0x72, 0x6e, + 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x15, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, + 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x22, 0x41, 0x0a, + 0x0c, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, + 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x22, 0x8f, 0x02, 0x0a, 0x0d, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, + 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x33, + 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, + 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x73, 0x12, 0x3a, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, + 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, + 0x74, 0x65, 0x72, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, + 0x61, 0x0a, 0x17, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x5f, 0x61, 0x75, 0x74, 0x68, + 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x29, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x45, + 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, + 0x64, 0x65, 0x72, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x15, 0x65, 0x78, 0x74, + 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, + 0x72, 0x73, 0x22, 0x0f, 0x0a, 0x0d, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x22, 0x8c, 0x02, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x2d, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x43, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x31, + 0x0a, 0x05, 0x70, 0x61, 0x72, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, + 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x05, 0x70, 0x61, 0x72, 0x73, + 0x65, 0x12, 0x2e, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x6c, + 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x04, 0x70, 0x6c, 0x61, + 0x6e, 0x12, 0x31, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, + 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x05, 0x61, + 0x70, 0x70, 0x6c, 0x79, 0x12, 0x34, 0x0a, 0x06, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x65, 0x72, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x48, 0x00, 0x52, 0x06, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x22, 0xd1, 0x01, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x24, 0x0a, 0x03, 0x6c, 0x6f, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x48, 0x00, + 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x12, 0x32, 0x0a, 0x05, 0x70, 0x61, 0x72, 0x73, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, + 0x48, 0x00, 0x52, 0x05, 0x70, 0x61, 0x72, 0x73, 0x65, 0x12, 0x2f, 0x0a, 0x04, 0x70, 0x6c, 0x61, + 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, + 0x74, 0x65, 0x48, 0x00, 0x52, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x12, 0x32, 0x0a, 0x05, 0x61, 0x70, + 0x70, 0x6c, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x43, 0x6f, 0x6d, + 0x70, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x42, 0x06, + 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x2a, 0x3f, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, + 0x65, 0x6c, 0x12, 0x09, 0x0a, 0x05, 0x54, 0x52, 0x41, 0x43, 0x45, 0x10, 0x00, 0x12, 0x09, 0x0a, + 0x05, 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x46, 0x4f, + 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x41, 0x52, 0x4e, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, + 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x04, 0x2a, 0x3b, 0x0a, 0x0f, 0x41, 0x70, 0x70, 0x53, 0x68, + 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x57, + 0x4e, 0x45, 0x52, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x41, 0x55, 0x54, 0x48, 0x45, 0x4e, 0x54, + 0x49, 0x43, 0x41, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x50, 0x55, 0x42, 0x4c, + 0x49, 0x43, 0x10, 0x02, 0x2a, 0x37, 0x0a, 0x13, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x09, 0x0a, 0x05, 0x53, + 0x54, 0x41, 0x52, 0x54, 0x10, 0x00, 0x12, 0x08, 0x0a, 0x04, 0x53, 0x54, 0x4f, 0x50, 0x10, 0x01, + 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x53, 0x54, 0x52, 0x4f, 0x59, 0x10, 0x02, 0x32, 0x49, 0x0a, + 0x0b, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x12, 0x3a, 0x0a, 0x07, + 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x42, 0x30, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, + 0x65, 0x72, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x72, 0x73, 0x64, 0x6b, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x33, } var ( diff --git a/provisionersdk/proto/provisioner.proto b/provisionersdk/proto/provisioner.proto index fb683293a4f11..439eb5a72b98c 100644 --- a/provisionersdk/proto/provisioner.proto +++ b/provisionersdk/proto/provisioner.proto @@ -225,6 +225,7 @@ message Metadata { string workspace_owner_session_token = 11; string template_id = 12; string workspace_owner_name = 13; + repeated string workspace_owner_groups = 14; } // Config represents execution configuration shared by all subsequent requests in the Session diff --git a/site/e2e/provisionerGenerated.ts b/site/e2e/provisionerGenerated.ts index 962544ba2c913..acda4caf31dcd 100644 --- a/site/e2e/provisionerGenerated.ts +++ b/site/e2e/provisionerGenerated.ts @@ -230,6 +230,7 @@ export interface Metadata { workspaceOwnerSessionToken: string; templateId: string; workspaceOwnerName: string; + workspaceOwnerGroups: string; } /** Config represents execution configuration shared by all subsequent requests in the Session */ @@ -832,6 +833,9 @@ export const Metadata = { if (message.workspaceOwnerName !== "") { writer.uint32(106).string(message.workspaceOwnerName); } + if (message.workspaceOwnerGroups !== "") { + writer.uint32(114).string(message.workspaceOwnerGroups); + } return writer; }, }; From 9a5f7f19874d084d9bdfa4ed46c4b3a1872337ac Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Mon, 1 Apr 2024 20:47:29 +0000 Subject: [PATCH 02/19] remove file --- coderd/wsbuilder/wsbuilder.go | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/coderd/wsbuilder/wsbuilder.go b/coderd/wsbuilder/wsbuilder.go index 6668aec6bc441..810f52502c6f8 100644 --- a/coderd/wsbuilder/wsbuilder.go +++ b/coderd/wsbuilder/wsbuilder.go @@ -197,32 +197,6 @@ func (e BuildError) Unwrap() error { return e.Wrapped } -type Adder interface { - Add() int -} - -type myAdder struct { - val int -} - -func (m *myAdder) Add() int { - return m.val -} - -func sum(adder []Adder) int { - sum := 0 - for _, a := range adder { - sum += a.Add() - } - return sum -} - -var x = sum([]Adder{&myAdder{ - val: 2, -}, &myAdder{ - val: 4, -}}) - // Build computes and inserts a new workspace build into the database. If authFunc is provided, it also performs // authorization preflight checks. func (b *Builder) Build( From a8277a0f53b472172f27082c3ab4081833db7b94 Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Tue, 2 Apr 2024 18:01:41 +0000 Subject: [PATCH 03/19] rename --- coderd/database/dbauthz/dbauthz.go | 2 +- coderd/database/dbmem/dbmem.go | 2 +- coderd/database/dbmetrics/dbmetrics.go | 6 +++--- coderd/database/dbmock/dbmock.go | 12 ++++++------ coderd/database/querier.go | 2 +- coderd/database/queries.sql.go | 8 ++++---- coderd/database/queries/groupmembers.sql | 2 +- coderd/provisionerdserver/provisionerdserver.go | 2 +- site/e2e/provisionerGenerated.ts | 6 +++--- 9 files changed, 21 insertions(+), 21 deletions(-) diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index 16538d4221352..3d7ae9b88b1e0 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -1145,7 +1145,7 @@ func (q *querier) GetGroupsByOrganizationID(ctx context.Context, organizationID return fetchWithPostFilter(q.auth, q.db.GetGroupsByOrganizationID)(ctx, organizationID) } -func (q *querier) GetGroupsByUserId(ctx context.Context, userID uuid.UUID) ([]database.Group, error) { +func (q *querier) GetGroupsByUserID(ctx context.Context, userID uuid.UUID) ([]database.Group, error) { panic("not implemented") } diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index 8664826465653..98c4a4a4ca360 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -2264,7 +2264,7 @@ func (q *FakeQuerier) GetGroupsByOrganizationID(_ context.Context, id uuid.UUID) return groups, nil } -func (q *FakeQuerier) GetGroupsByUserId(ctx context.Context, userID uuid.UUID) ([]database.Group, error) { +func (q *FakeQuerier) GetGroupsByUserID(ctx context.Context, userID uuid.UUID) ([]database.Group, error) { panic("not implemented") } diff --git a/coderd/database/dbmetrics/dbmetrics.go b/coderd/database/dbmetrics/dbmetrics.go index 3660920b69ad9..feb16fadfd29d 100644 --- a/coderd/database/dbmetrics/dbmetrics.go +++ b/coderd/database/dbmetrics/dbmetrics.go @@ -566,10 +566,10 @@ func (m metricsStore) GetGroupsByOrganizationID(ctx context.Context, organizatio return groups, err } -func (m metricsStore) GetGroupsByUserId(ctx context.Context, userID uuid.UUID) ([]database.Group, error) { +func (m metricsStore) GetGroupsByUserID(ctx context.Context, userID uuid.UUID) ([]database.Group, error) { start := time.Now() - r0, r1 := m.s.GetGroupsByUserId(ctx, userID) - m.queryLatencies.WithLabelValues("GetGroupsByUserId").Observe(time.Since(start).Seconds()) + r0, r1 := m.s.GetGroupsByUserID(ctx, userID) + m.queryLatencies.WithLabelValues("GetGroupsByUserID").Observe(time.Since(start).Seconds()) return r0, r1 } diff --git a/coderd/database/dbmock/dbmock.go b/coderd/database/dbmock/dbmock.go index 9264d0a355765..b23a91a0aa8c5 100644 --- a/coderd/database/dbmock/dbmock.go +++ b/coderd/database/dbmock/dbmock.go @@ -1110,19 +1110,19 @@ func (mr *MockStoreMockRecorder) GetGroupsByOrganizationID(arg0, arg1 any) *gomo return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGroupsByOrganizationID", reflect.TypeOf((*MockStore)(nil).GetGroupsByOrganizationID), arg0, arg1) } -// GetGroupsByUserId mocks base method. -func (m *MockStore) GetGroupsByUserId(arg0 context.Context, arg1 uuid.UUID) ([]database.Group, error) { +// GetGroupsByUserID mocks base method. +func (m *MockStore) GetGroupsByUserID(arg0 context.Context, arg1 uuid.UUID) ([]database.Group, error) { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetGroupsByUserId", arg0, arg1) + ret := m.ctrl.Call(m, "GetGroupsByUserID", arg0, arg1) ret0, _ := ret[0].([]database.Group) ret1, _ := ret[1].(error) return ret0, ret1 } -// GetGroupsByUserId indicates an expected call of GetGroupsByUserId. -func (mr *MockStoreMockRecorder) GetGroupsByUserId(arg0, arg1 any) *gomock.Call { +// GetGroupsByUserID indicates an expected call of GetGroupsByUserID. +func (mr *MockStoreMockRecorder) GetGroupsByUserID(arg0, arg1 any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGroupsByUserId", reflect.TypeOf((*MockStore)(nil).GetGroupsByUserId), arg0, arg1) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGroupsByUserID", reflect.TypeOf((*MockStore)(nil).GetGroupsByUserID), arg0, arg1) } // GetHealthSettings mocks base method. diff --git a/coderd/database/querier.go b/coderd/database/querier.go index 04acbca4d1f39..ea5422739870b 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -124,7 +124,7 @@ type sqlcQuerier interface { // If it is the "Everyone" group, then we need to check the organization_members table. GetGroupMembers(ctx context.Context, groupID uuid.UUID) ([]User, error) GetGroupsByOrganizationID(ctx context.Context, organizationID uuid.UUID) ([]Group, error) - GetGroupsByUserId(ctx context.Context, userID uuid.UUID) ([]Group, error) + GetGroupsByUserID(ctx context.Context, userID uuid.UUID) ([]Group, error) GetHealthSettings(ctx context.Context) (string, error) GetHungProvisionerJobs(ctx context.Context, updatedAt time.Time) ([]ProvisionerJob, error) GetJFrogXrayScanByWorkspaceAndAgentID(ctx context.Context, arg GetJFrogXrayScanByWorkspaceAndAgentIDParams) (JfrogXrayScan, error) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 09e85344a3d42..430fb0bf1c292 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -1353,7 +1353,7 @@ func (q *sqlQuerier) GetGroupMembers(ctx context.Context, groupID uuid.UUID) ([] return items, nil } -const getGroupsByUserId = `-- name: GetGroupsByUserId :many +const getGroupsByUserId = `-- name: GetGroupsByUserID :many SELECT groups.id, groups.name, groups.organization_id, groups.avatar_url, groups.quota_allowance, groups.display_name, groups.source FROM @@ -1366,7 +1366,7 @@ WHERE group_members.user_id = $1 ` -func (q *sqlQuerier) GetGroupsByUserId(ctx context.Context, userID uuid.UUID) ([]Group, error) { +func (q *sqlQuerier) GetGroupsByUserID(ctx context.Context, userID uuid.UUID) ([]Group, error) { rows, err := q.db.QueryContext(ctx, getGroupsByUserId, userID) if err != nil { return nil, err @@ -2932,7 +2932,7 @@ func (q *sqlQuerier) GetJFrogXrayScanByWorkspaceAndAgentID(ctx context.Context, } const upsertJFrogXrayScanByWorkspaceAndAgentID = `-- name: UpsertJFrogXrayScanByWorkspaceAndAgentID :exec -INSERT INTO +INSERT INTO jfrog_xray_scans ( agent_id, workspace_id, @@ -2941,7 +2941,7 @@ INSERT INTO medium, results_url ) -VALUES +VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (agent_id, workspace_id) DO UPDATE SET critical = $3, high = $4, medium = $5, results_url = $6 diff --git a/coderd/database/queries/groupmembers.sql b/coderd/database/queries/groupmembers.sql index 733559d0ebb38..7070398236a3d 100644 --- a/coderd/database/queries/groupmembers.sql +++ b/coderd/database/queries/groupmembers.sql @@ -23,7 +23,7 @@ WHERE AND users.deleted = 'false'; --- name: GetGroupsByUserId :many +-- name: GetGroupsByUserID :many SELECT groups.* FROM diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go index d7696145fd8cd..b682b47073114 100644 --- a/coderd/provisionerdserver/provisionerdserver.go +++ b/coderd/provisionerdserver/provisionerdserver.go @@ -467,7 +467,7 @@ func (s *server) acquireProtoJob(ctx context.Context, job database.ProvisionerJo if err != nil { return nil, failJob(fmt.Sprintf("get owner: %s", err)) } - ownerGroups, err := s.Database.GetGroupsByUserId(ctx, owner.ID) + ownerGroups, err := s.Database.GetGroupsByUserID(ctx, owner.ID) ownerGroupNames := make([]string, 0, len(ownerGroups)) for _, group := range ownerGroups { ownerGroupNames = append(ownerGroupNames, group.Name) diff --git a/site/e2e/provisionerGenerated.ts b/site/e2e/provisionerGenerated.ts index acda4caf31dcd..1ba6f6f64a9df 100644 --- a/site/e2e/provisionerGenerated.ts +++ b/site/e2e/provisionerGenerated.ts @@ -230,7 +230,7 @@ export interface Metadata { workspaceOwnerSessionToken: string; templateId: string; workspaceOwnerName: string; - workspaceOwnerGroups: string; + workspaceOwnerGroups: string[]; } /** Config represents execution configuration shared by all subsequent requests in the Session */ @@ -833,8 +833,8 @@ export const Metadata = { if (message.workspaceOwnerName !== "") { writer.uint32(106).string(message.workspaceOwnerName); } - if (message.workspaceOwnerGroups !== "") { - writer.uint32(114).string(message.workspaceOwnerGroups); + for (const v of message.workspaceOwnerGroups) { + writer.uint32(114).string(v!); } return writer; }, From e788b3b3aed5f98fbd53cb4d8ad32601a344440d Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Tue, 2 Apr 2024 18:30:13 +0000 Subject: [PATCH 04/19] remove new query --- coderd/database/dbauthz/dbauthz.go | 4 -- coderd/database/dbmem/dbmem.go | 4 -- coderd/database/dbmetrics/dbmetrics.go | 14 +++--- coderd/database/dbmock/dbmock.go | 15 ------ coderd/database/querier.go | 1 - coderd/database/queries.sql.go | 48 +------------------ coderd/database/queries/groupmembers.sql | 12 ----- .../provisionerdserver/provisionerdserver.go | 19 ++++++-- provisioner/terraform/provision.go | 8 ++++ 9 files changed, 31 insertions(+), 94 deletions(-) diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index 3d7ae9b88b1e0..97a695cb376c6 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -1145,10 +1145,6 @@ func (q *querier) GetGroupsByOrganizationID(ctx context.Context, organizationID return fetchWithPostFilter(q.auth, q.db.GetGroupsByOrganizationID)(ctx, organizationID) } -func (q *querier) GetGroupsByUserID(ctx context.Context, userID uuid.UUID) ([]database.Group, error) { - panic("not implemented") -} - func (q *querier) GetHealthSettings(ctx context.Context) (string, error) { // No authz checks return q.db.GetHealthSettings(ctx) diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index 98c4a4a4ca360..8bb8559be779f 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -2264,10 +2264,6 @@ func (q *FakeQuerier) GetGroupsByOrganizationID(_ context.Context, id uuid.UUID) return groups, nil } -func (q *FakeQuerier) GetGroupsByUserID(ctx context.Context, userID uuid.UUID) ([]database.Group, error) { - panic("not implemented") -} - func (q *FakeQuerier) GetHealthSettings(_ context.Context) (string, error) { q.mutex.RLock() defer q.mutex.RUnlock() diff --git a/coderd/database/dbmetrics/dbmetrics.go b/coderd/database/dbmetrics/dbmetrics.go index feb16fadfd29d..231ad5be5128d 100644 --- a/coderd/database/dbmetrics/dbmetrics.go +++ b/coderd/database/dbmetrics/dbmetrics.go @@ -79,6 +79,13 @@ func (m metricsStore) InTx(f func(database.Store) error, options *sql.TxOptions) return err } +func (m metricsStore) GetGroupsByUserID(ctx context.Context, userID uuid.UUID) ([]database.Group, error) { + start := time.Now() + r0, r1 := m.s.GetGroupsByUserID(ctx, userID) + m.queryLatencies.WithLabelValues("GetGroupsByUserID").Observe(time.Since(start).Seconds()) + return r0, r1 +} + func (m metricsStore) AcquireLock(ctx context.Context, pgAdvisoryXactLock int64) error { start := time.Now() err := m.s.AcquireLock(ctx, pgAdvisoryXactLock) @@ -566,13 +573,6 @@ func (m metricsStore) GetGroupsByOrganizationID(ctx context.Context, organizatio return groups, err } -func (m metricsStore) GetGroupsByUserID(ctx context.Context, userID uuid.UUID) ([]database.Group, error) { - start := time.Now() - r0, r1 := m.s.GetGroupsByUserID(ctx, userID) - m.queryLatencies.WithLabelValues("GetGroupsByUserID").Observe(time.Since(start).Seconds()) - return r0, r1 -} - func (m metricsStore) GetHealthSettings(ctx context.Context) (string, error) { start := time.Now() r0, r1 := m.s.GetHealthSettings(ctx) diff --git a/coderd/database/dbmock/dbmock.go b/coderd/database/dbmock/dbmock.go index b23a91a0aa8c5..32049ba0721b7 100644 --- a/coderd/database/dbmock/dbmock.go +++ b/coderd/database/dbmock/dbmock.go @@ -1110,21 +1110,6 @@ func (mr *MockStoreMockRecorder) GetGroupsByOrganizationID(arg0, arg1 any) *gomo return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGroupsByOrganizationID", reflect.TypeOf((*MockStore)(nil).GetGroupsByOrganizationID), arg0, arg1) } -// GetGroupsByUserID mocks base method. -func (m *MockStore) GetGroupsByUserID(arg0 context.Context, arg1 uuid.UUID) ([]database.Group, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetGroupsByUserID", arg0, arg1) - ret0, _ := ret[0].([]database.Group) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetGroupsByUserID indicates an expected call of GetGroupsByUserID. -func (mr *MockStoreMockRecorder) GetGroupsByUserID(arg0, arg1 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGroupsByUserID", reflect.TypeOf((*MockStore)(nil).GetGroupsByUserID), arg0, arg1) -} - // GetHealthSettings mocks base method. func (m *MockStore) GetHealthSettings(arg0 context.Context) (string, error) { m.ctrl.T.Helper() diff --git a/coderd/database/querier.go b/coderd/database/querier.go index ea5422739870b..bf1a1909fe765 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -124,7 +124,6 @@ type sqlcQuerier interface { // If it is the "Everyone" group, then we need to check the organization_members table. GetGroupMembers(ctx context.Context, groupID uuid.UUID) ([]User, error) GetGroupsByOrganizationID(ctx context.Context, organizationID uuid.UUID) ([]Group, error) - GetGroupsByUserID(ctx context.Context, userID uuid.UUID) ([]Group, error) GetHealthSettings(ctx context.Context) (string, error) GetHungProvisionerJobs(ctx context.Context, updatedAt time.Time) ([]ProvisionerJob, error) GetJFrogXrayScanByWorkspaceAndAgentID(ctx context.Context, arg GetJFrogXrayScanByWorkspaceAndAgentIDParams) (JfrogXrayScan, error) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 430fb0bf1c292..b3216fc2d8c80 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -1353,50 +1353,6 @@ func (q *sqlQuerier) GetGroupMembers(ctx context.Context, groupID uuid.UUID) ([] return items, nil } -const getGroupsByUserId = `-- name: GetGroupsByUserID :many -SELECT - groups.id, groups.name, groups.organization_id, groups.avatar_url, groups.quota_allowance, groups.display_name, groups.source -FROM - groups -LEFT JOIN - group_members -ON - group_members.group_id = groups.id -WHERE - group_members.user_id = $1 -` - -func (q *sqlQuerier) GetGroupsByUserID(ctx context.Context, userID uuid.UUID) ([]Group, error) { - rows, err := q.db.QueryContext(ctx, getGroupsByUserId, userID) - if err != nil { - return nil, err - } - defer rows.Close() - var items []Group - for rows.Next() { - var i Group - if err := rows.Scan( - &i.ID, - &i.Name, - &i.OrganizationID, - &i.AvatarURL, - &i.QuotaAllowance, - &i.DisplayName, - &i.Source, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Close(); err != nil { - return nil, err - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - const insertGroupMember = `-- name: InsertGroupMember :exec INSERT INTO group_members (user_id, group_id) @@ -2932,7 +2888,7 @@ func (q *sqlQuerier) GetJFrogXrayScanByWorkspaceAndAgentID(ctx context.Context, } const upsertJFrogXrayScanByWorkspaceAndAgentID = `-- name: UpsertJFrogXrayScanByWorkspaceAndAgentID :exec -INSERT INTO +INSERT INTO jfrog_xray_scans ( agent_id, workspace_id, @@ -2941,7 +2897,7 @@ INSERT INTO medium, results_url ) -VALUES +VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (agent_id, workspace_id) DO UPDATE SET critical = $3, high = $4, medium = $5, results_url = $6 diff --git a/coderd/database/queries/groupmembers.sql b/coderd/database/queries/groupmembers.sql index 7070398236a3d..d755212132383 100644 --- a/coderd/database/queries/groupmembers.sql +++ b/coderd/database/queries/groupmembers.sql @@ -23,18 +23,6 @@ WHERE AND users.deleted = 'false'; --- name: GetGroupsByUserID :many -SELECT - groups.* -FROM - groups -LEFT JOIN - group_members -ON - group_members.group_id = groups.id -WHERE - group_members.user_id = @user_id; - -- InsertUserGroupsByName adds a user to all provided groups, if they exist. -- name: InsertUserGroupsByName :exec WITH groups AS ( diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go index b682b47073114..e2eacf8e51dd8 100644 --- a/coderd/provisionerdserver/provisionerdserver.go +++ b/coderd/provisionerdserver/provisionerdserver.go @@ -467,14 +467,23 @@ func (s *server) acquireProtoJob(ctx context.Context, job database.ProvisionerJo if err != nil { return nil, failJob(fmt.Sprintf("get owner: %s", err)) } - ownerGroups, err := s.Database.GetGroupsByUserID(ctx, owner.ID) - ownerGroupNames := make([]string, 0, len(ownerGroups)) - for _, group := range ownerGroups { - ownerGroupNames = append(ownerGroupNames, group.Name) - } + orgGroups, err := s.Database.GetGroupsByOrganizationID(ctx, workspace.OrganizationID) if err != nil { return nil, failJob(fmt.Sprintf("get owner groups: %s", err)) } + ownerGroupNames := []string{} + for _, group := range orgGroups { + members, err := s.Database.GetGroupMembers(ctx, group.ID) + if err != nil { + return nil, failJob(fmt.Sprintf("get group members: %s", err)) + } + for _, member := range members { + if member.ID == owner.ID { + ownerGroupNames = append(ownerGroupNames, group.Name) + break + } + } + } err = s.Pubsub.Publish(codersdk.WorkspaceNotifyChannel(workspace.ID), []byte{}) if err != nil { return nil, failJob(fmt.Sprintf("publish workspace update: %s", err)) diff --git a/provisioner/terraform/provision.go b/provisioner/terraform/provision.go index 40f24ecfb8124..e2e6766ae7210 100644 --- a/provisioner/terraform/provision.go +++ b/provisioner/terraform/provision.go @@ -2,12 +2,14 @@ package terraform import ( "context" + "encoding/json" "fmt" "os" "strings" "time" "github.com/spf13/afero" + "golang.org/x/xerrors" "cdr.dev/slog" "github.com/coder/terraform-provider-coder/provider" @@ -186,6 +188,11 @@ func provisionEnv( richParams []*proto.RichParameterValue, externalAuth []*proto.ExternalAuthProvider, ) ([]string, error) { env := safeEnviron() + ownerGroups, err := json.Marshal(metadata.WorkspaceOwnerGroups) + if err != nil { + return nil, xerrors.Errorf("marshal owner groups: %w", err) + } + env = append(env, "CODER_AGENT_URL="+metadata.GetCoderUrl(), "CODER_WORKSPACE_TRANSITION="+strings.ToLower(metadata.GetWorkspaceTransition().String()), @@ -194,6 +201,7 @@ func provisionEnv( "CODER_WORKSPACE_OWNER_EMAIL="+metadata.GetWorkspaceOwnerEmail(), "CODER_WORKSPACE_OWNER_NAME="+metadata.GetWorkspaceOwnerName(), "CODER_WORKSPACE_OWNER_OIDC_ACCESS_TOKEN="+metadata.GetWorkspaceOwnerOidcAccessToken(), + "CODER_WORKSPACE_OWNER_GROUPS="+string(ownerGroups), "CODER_WORKSPACE_ID="+metadata.GetWorkspaceId(), "CODER_WORKSPACE_OWNER_ID="+metadata.GetWorkspaceOwnerId(), "CODER_WORKSPACE_OWNER_SESSION_TOKEN="+metadata.GetWorkspaceOwnerSessionToken(), From 8e2c4fe0bf846b1857d3298d126431a46af9880e Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Tue, 2 Apr 2024 22:33:17 +0000 Subject: [PATCH 05/19] lint --- coderd/database/dbmetrics/dbmetrics.go | 7 ------- provisionersdk/proto/provisioner.proto | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/coderd/database/dbmetrics/dbmetrics.go b/coderd/database/dbmetrics/dbmetrics.go index 231ad5be5128d..5cd452d328e16 100644 --- a/coderd/database/dbmetrics/dbmetrics.go +++ b/coderd/database/dbmetrics/dbmetrics.go @@ -79,13 +79,6 @@ func (m metricsStore) InTx(f func(database.Store) error, options *sql.TxOptions) return err } -func (m metricsStore) GetGroupsByUserID(ctx context.Context, userID uuid.UUID) ([]database.Group, error) { - start := time.Now() - r0, r1 := m.s.GetGroupsByUserID(ctx, userID) - m.queryLatencies.WithLabelValues("GetGroupsByUserID").Observe(time.Since(start).Seconds()) - return r0, r1 -} - func (m metricsStore) AcquireLock(ctx context.Context, pgAdvisoryXactLock int64) error { start := time.Now() err := m.s.AcquireLock(ctx, pgAdvisoryXactLock) diff --git a/provisionersdk/proto/provisioner.proto b/provisionersdk/proto/provisioner.proto index 439eb5a72b98c..1ee779aa76eff 100644 --- a/provisionersdk/proto/provisioner.proto +++ b/provisionersdk/proto/provisioner.proto @@ -225,7 +225,7 @@ message Metadata { string workspace_owner_session_token = 11; string template_id = 12; string workspace_owner_name = 13; - repeated string workspace_owner_groups = 14; + repeated string workspace_owner_groups = 14; } // Config represents execution configuration shared by all subsequent requests in the Session From 6b305f6a1a9041977a12c9f2c9eb367d88b5df51 Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Wed, 3 Apr 2024 15:05:55 +0000 Subject: [PATCH 06/19] update tf provider --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index cd3c83bba8da7..b4b8c3ca17cf3 100644 --- a/go.mod +++ b/go.mod @@ -104,7 +104,7 @@ require ( github.com/coder/flog v1.1.0 github.com/coder/pretty v0.0.0-20230908205945-e89ba86370e0 github.com/coder/retry v1.5.1 - github.com/coder/terraform-provider-coder v0.19.0 + github.com/coder/terraform-provider-coder v0.20.0 github.com/coder/wgtunnel v0.1.13-0.20231127054351-578bfff9b92a github.com/coreos/go-oidc/v3 v3.10.0 github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf From 48108f89d4a70a96bbbdbef5a44be4b75fee9b11 Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Wed, 3 Apr 2024 16:06:28 +0000 Subject: [PATCH 07/19] update tests --- coderd/provisionerdserver/provisionerdserver_test.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/coderd/provisionerdserver/provisionerdserver_test.go b/coderd/provisionerdserver/provisionerdserver_test.go index 05572d381ea00..7e24372e66660 100644 --- a/coderd/provisionerdserver/provisionerdserver_test.go +++ b/coderd/provisionerdserver/provisionerdserver_test.go @@ -182,6 +182,15 @@ func TestAcquireJob(t *testing.T) { defer cancel() user := dbgen.User(t, db, database.User{}) + group1 := dbgen.Group(t, db, database.Group{ + Name: "group1", + OrganizationID: pd.OrganizationID, + }) + err := db.InsertGroupMember(ctx, database.InsertGroupMemberParams{ + UserID: user.ID, + GroupID: group1.ID, + }) + require.NoError(t, err) link := dbgen.UserLink(t, db, database.UserLink{ LoginType: database.LoginTypeOIDC, UserID: user.ID, @@ -340,6 +349,7 @@ func TestAcquireJob(t *testing.T) { WorkspaceOwnerEmail: user.Email, WorkspaceOwnerName: user.Name, WorkspaceOwnerOidcAccessToken: link.OAuthAccessToken, + WorkspaceOwnerGroups: []string{group1.Name}, WorkspaceId: workspace.ID.String(), WorkspaceOwnerId: user.ID.String(), TemplateId: template.ID.String(), From 80cfdc84e4d63d990317af1d1f69f58bc0f541bc Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Wed, 3 Apr 2024 16:07:37 +0000 Subject: [PATCH 08/19] update tf --- go.mod | 2 +- go.sum | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index b4b8c3ca17cf3..bfbf5050ccd5d 100644 --- a/go.mod +++ b/go.mod @@ -104,7 +104,7 @@ require ( github.com/coder/flog v1.1.0 github.com/coder/pretty v0.0.0-20230908205945-e89ba86370e0 github.com/coder/retry v1.5.1 - github.com/coder/terraform-provider-coder v0.20.0 + github.com/coder/terraform-provider-coder v0.20.1 github.com/coder/wgtunnel v0.1.13-0.20231127054351-578bfff9b92a github.com/coreos/go-oidc/v3 v3.10.0 github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf diff --git a/go.sum b/go.sum index 3f620bd14abda..65167707461b7 100644 --- a/go.sum +++ b/go.sum @@ -215,10 +215,17 @@ github.com/coder/serpent v0.7.0 h1:zGpD2GlF3lKIVkMjNGKbkip88qzd5r/TRcc30X/SrT0= github.com/coder/serpent v0.7.0/go.mod h1:REkJ5ZFHQUWFTPLExhXYZ1CaHFjxvGNRlLXLdsI08YA= github.com/coder/ssh v0.0.0-20231128192721-70855dedb788 h1:YoUSJ19E8AtuUFVYBpXuOD6a/zVP3rcxezNsoDseTUw= github.com/coder/ssh v0.0.0-20231128192721-70855dedb788/go.mod h1:aGQbuCLyhRLMzZF067xc84Lh7JDs1FKwCmF1Crl9dxQ= +<<<<<<< HEAD github.com/coder/tailscale v1.1.1-0.20240401202854-d329bbdb530d h1:IMvBC1GrCIiZFxpOYRQacZtdjnmsdWNAMilPz+kvdG4= github.com/coder/tailscale v1.1.1-0.20240401202854-d329bbdb530d/go.mod h1:L8tPrwSi31RAMEMV8rjb0vYTGs7rXt8rAHbqY/p41j4= github.com/coder/terraform-provider-coder v0.19.0 h1:mmUXSXcar1h2wgwoHIUwdEKy9Kw0GW7fLO4Vzzf+4R4= github.com/coder/terraform-provider-coder v0.19.0/go.mod h1:pACHRoXSHBGyY696mLeQ1hR/Ag1G2wFk5bw0mT5Zp2g= +======= +github.com/coder/tailscale v1.1.1-0.20240214140224-3788ab894ba1 h1:A7dZHNidAVH6Kxn5D3hTEH+iRO8slnM0aRer6/cxlyE= +github.com/coder/tailscale v1.1.1-0.20240214140224-3788ab894ba1/go.mod h1:L8tPrwSi31RAMEMV8rjb0vYTGs7rXt8rAHbqY/p41j4= +github.com/coder/terraform-provider-coder v0.20.1 h1:hz0yvDl8rDJyDgUlFH8QrGUxFKrwmyAQpOhaoTMEmtY= +github.com/coder/terraform-provider-coder v0.20.1/go.mod h1:pACHRoXSHBGyY696mLeQ1hR/Ag1G2wFk5bw0mT5Zp2g= +>>>>>>> fce75839b (update tf) github.com/coder/wgtunnel v0.1.13-0.20231127054351-578bfff9b92a h1:KhR9LUVllMZ+e9lhubZ1HNrtJDgH5YLoTvpKwmrGag4= github.com/coder/wgtunnel v0.1.13-0.20231127054351-578bfff9b92a/go.mod h1:QzfptVUdEO+XbkzMKx1kw13i9wwpJlfI1RrZ6SNZ0hA= github.com/coder/wireguard-go v0.0.0-20230807234434-d825b45ccbf5 h1:eDk/42Kj4xN4yfE504LsvcFEo3dWUiCOaBiWJ2uIH2A= From b3cd5f1f3fe41d01f750b61809e68b8a8b6e041f Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Wed, 3 Apr 2024 17:07:30 +0000 Subject: [PATCH 09/19] add groups to dbauthz role --- coderd/database/dbauthz/dbauthz.go | 1 + coderd/provisionerdserver/provisionerdserver.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index 97a695cb376c6..43b2fb7c23e3b 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -174,6 +174,7 @@ var ( // When org scoped provisioner credentials are implemented, // this can be reduced to read a specific org. rbac.ResourceOrganization.Type: {rbac.ActionRead}, + rbac.ResourceGroup.Type: {rbac.ActionRead}, }), Org: map[string][]rbac.Permission{}, User: []rbac.Permission{}, diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go index e2eacf8e51dd8..48d2464724234 100644 --- a/coderd/provisionerdserver/provisionerdserver.go +++ b/coderd/provisionerdserver/provisionerdserver.go @@ -467,7 +467,7 @@ func (s *server) acquireProtoJob(ctx context.Context, job database.ProvisionerJo if err != nil { return nil, failJob(fmt.Sprintf("get owner: %s", err)) } - orgGroups, err := s.Database.GetGroupsByOrganizationID(ctx, workspace.OrganizationID) + orgGroups, err := s.Database.GetGroupsByOrganizationID(ctx, s.OrganizationID) if err != nil { return nil, failJob(fmt.Sprintf("get owner groups: %s", err)) } From 9ae8efb4b9e3f98fc7403ac978d2c81a34f72202 Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Wed, 3 Apr 2024 17:14:23 +0000 Subject: [PATCH 10/19] rebase --- go.sum | 7 ------- 1 file changed, 7 deletions(-) diff --git a/go.sum b/go.sum index 65167707461b7..72d6471d753db 100644 --- a/go.sum +++ b/go.sum @@ -215,17 +215,10 @@ github.com/coder/serpent v0.7.0 h1:zGpD2GlF3lKIVkMjNGKbkip88qzd5r/TRcc30X/SrT0= github.com/coder/serpent v0.7.0/go.mod h1:REkJ5ZFHQUWFTPLExhXYZ1CaHFjxvGNRlLXLdsI08YA= github.com/coder/ssh v0.0.0-20231128192721-70855dedb788 h1:YoUSJ19E8AtuUFVYBpXuOD6a/zVP3rcxezNsoDseTUw= github.com/coder/ssh v0.0.0-20231128192721-70855dedb788/go.mod h1:aGQbuCLyhRLMzZF067xc84Lh7JDs1FKwCmF1Crl9dxQ= -<<<<<<< HEAD github.com/coder/tailscale v1.1.1-0.20240401202854-d329bbdb530d h1:IMvBC1GrCIiZFxpOYRQacZtdjnmsdWNAMilPz+kvdG4= github.com/coder/tailscale v1.1.1-0.20240401202854-d329bbdb530d/go.mod h1:L8tPrwSi31RAMEMV8rjb0vYTGs7rXt8rAHbqY/p41j4= -github.com/coder/terraform-provider-coder v0.19.0 h1:mmUXSXcar1h2wgwoHIUwdEKy9Kw0GW7fLO4Vzzf+4R4= -github.com/coder/terraform-provider-coder v0.19.0/go.mod h1:pACHRoXSHBGyY696mLeQ1hR/Ag1G2wFk5bw0mT5Zp2g= -======= -github.com/coder/tailscale v1.1.1-0.20240214140224-3788ab894ba1 h1:A7dZHNidAVH6Kxn5D3hTEH+iRO8slnM0aRer6/cxlyE= -github.com/coder/tailscale v1.1.1-0.20240214140224-3788ab894ba1/go.mod h1:L8tPrwSi31RAMEMV8rjb0vYTGs7rXt8rAHbqY/p41j4= github.com/coder/terraform-provider-coder v0.20.1 h1:hz0yvDl8rDJyDgUlFH8QrGUxFKrwmyAQpOhaoTMEmtY= github.com/coder/terraform-provider-coder v0.20.1/go.mod h1:pACHRoXSHBGyY696mLeQ1hR/Ag1G2wFk5bw0mT5Zp2g= ->>>>>>> fce75839b (update tf) github.com/coder/wgtunnel v0.1.13-0.20231127054351-578bfff9b92a h1:KhR9LUVllMZ+e9lhubZ1HNrtJDgH5YLoTvpKwmrGag4= github.com/coder/wgtunnel v0.1.13-0.20231127054351-578bfff9b92a/go.mod h1:QzfptVUdEO+XbkzMKx1kw13i9wwpJlfI1RrZ6SNZ0hA= github.com/coder/wireguard-go v0.0.0-20230807234434-d825b45ccbf5 h1:eDk/42Kj4xN4yfE504LsvcFEo3dWUiCOaBiWJ2uIH2A= From da9163e3c36e64527b104bb8915ef21a30104ec9 Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Wed, 3 Apr 2024 17:20:32 +0000 Subject: [PATCH 11/19] use GetWorkspaceOwnerGroups --- provisioner/terraform/provision.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/provisioner/terraform/provision.go b/provisioner/terraform/provision.go index e2e6766ae7210..542006f27e87f 100644 --- a/provisioner/terraform/provision.go +++ b/provisioner/terraform/provision.go @@ -188,7 +188,7 @@ func provisionEnv( richParams []*proto.RichParameterValue, externalAuth []*proto.ExternalAuthProvider, ) ([]string, error) { env := safeEnviron() - ownerGroups, err := json.Marshal(metadata.WorkspaceOwnerGroups) + ownerGroups, err := json.Marshal(metadata.GetWorkspaceOwnerGroups()) if err != nil { return nil, xerrors.Errorf("marshal owner groups: %w", err) } From 0f472ebb2265e3df1b62bf346ccfce646247d885 Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Wed, 3 Apr 2024 20:38:44 +0000 Subject: [PATCH 12/19] use query for group names --- coderd/database/dbauthz/dbauthz.go | 7 +++ coderd/database/dbmem/dbmem.go | 24 +++++++++ coderd/database/dbmetrics/dbmetrics.go | 7 +++ coderd/database/dbmock/dbmock.go | 15 ++++++ coderd/database/querier.go | 1 + coderd/database/queries.sql.go | 51 +++++++++++++++++++ coderd/database/queries/groups.sql | 23 +++++++++ .../provisionerdserver/provisionerdserver.go | 20 ++------ 8 files changed, 133 insertions(+), 15 deletions(-) diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index 43b2fb7c23e3b..50a0f1a21690b 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -1833,6 +1833,13 @@ func (q *querier) GetUserCount(ctx context.Context) (int64, error) { return q.db.GetUserCount(ctx) } +func (q *querier) GetUserGroupNames(ctx context.Context, arg database.GetUserGroupNamesParams) ([]string, error) { + if err := q.authorizeContext(ctx, rbac.ActionRead, rbac.ResourceGroup); err != nil { + return nil, err + } + return q.db.GetUserGroupNames(ctx, arg) +} + func (q *querier) GetUserLatencyInsights(ctx context.Context, arg database.GetUserLatencyInsightsParams) ([]database.GetUserLatencyInsightsRow, error) { // Used by insights endpoints. Need to check both for auditors and for regular users with template acl perms. if err := q.authorizeContext(ctx, rbac.ActionRead, rbac.ResourceTemplateInsights); err != nil { diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index 8bb8559be779f..bf172673ed9e5 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -4334,6 +4334,30 @@ func (q *FakeQuerier) GetUserCount(_ context.Context) (int64, error) { return existing, nil } +func (q *FakeQuerier) GetUserGroupNames(ctx context.Context, arg database.GetUserGroupNamesParams) ([]string, error) { + err := validateDatabaseType(arg) + if err != nil { + return nil, err + } + + q.mutex.RLock() + defer q.mutex.RUnlock() + var groupIds []uuid.UUID + for _, member := range q.groupMembers { + if member.UserID == arg.UserID { + groupIds = append(groupIds, member.GroupID) + } + } + groupNames := []string{} + for _, group := range q.groups { + if slices.Contains(groupIds, group.ID) { + groupNames = append(groupNames, group.Name) + } + } + + return groupNames, nil +} + func (q *FakeQuerier) GetUserLatencyInsights(_ context.Context, arg database.GetUserLatencyInsightsParams) ([]database.GetUserLatencyInsightsRow, error) { err := validateDatabaseType(arg) if err != nil { diff --git a/coderd/database/dbmetrics/dbmetrics.go b/coderd/database/dbmetrics/dbmetrics.go index 5cd452d328e16..77430585b79c7 100644 --- a/coderd/database/dbmetrics/dbmetrics.go +++ b/coderd/database/dbmetrics/dbmetrics.go @@ -1061,6 +1061,13 @@ func (m metricsStore) GetUserCount(ctx context.Context) (int64, error) { return count, err } +func (m metricsStore) GetUserGroupNames(ctx context.Context, arg database.GetUserGroupNamesParams) ([]string, error) { + start := time.Now() + r0, r1 := m.s.GetUserGroupNames(ctx, arg) + m.queryLatencies.WithLabelValues("GetUserGroupNames").Observe(time.Since(start).Seconds()) + return r0, r1 +} + func (m metricsStore) GetUserLatencyInsights(ctx context.Context, arg database.GetUserLatencyInsightsParams) ([]database.GetUserLatencyInsightsRow, error) { start := time.Now() r0, r1 := m.s.GetUserLatencyInsights(ctx, arg) diff --git a/coderd/database/dbmock/dbmock.go b/coderd/database/dbmock/dbmock.go index 32049ba0721b7..04971988b796b 100644 --- a/coderd/database/dbmock/dbmock.go +++ b/coderd/database/dbmock/dbmock.go @@ -2205,6 +2205,21 @@ func (mr *MockStoreMockRecorder) GetUserCount(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserCount", reflect.TypeOf((*MockStore)(nil).GetUserCount), arg0) } +// GetUserGroupNames mocks base method. +func (m *MockStore) GetUserGroupNames(arg0 context.Context, arg1 database.GetUserGroupNamesParams) ([]string, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetUserGroupNames", arg0, arg1) + ret0, _ := ret[0].([]string) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetUserGroupNames indicates an expected call of GetUserGroupNames. +func (mr *MockStoreMockRecorder) GetUserGroupNames(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserGroupNames", reflect.TypeOf((*MockStore)(nil).GetUserGroupNames), arg0, arg1) +} + // GetUserLatencyInsights mocks base method. func (m *MockStore) GetUserLatencyInsights(arg0 context.Context, arg1 database.GetUserLatencyInsightsParams) ([]database.GetUserLatencyInsightsRow, error) { m.ctrl.T.Helper() diff --git a/coderd/database/querier.go b/coderd/database/querier.go index bf1a1909fe765..4024762219f5f 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -226,6 +226,7 @@ type sqlcQuerier interface { GetUserByEmailOrUsername(ctx context.Context, arg GetUserByEmailOrUsernameParams) (User, error) GetUserByID(ctx context.Context, id uuid.UUID) (User, error) GetUserCount(ctx context.Context) (int64, error) + GetUserGroupNames(ctx context.Context, arg GetUserGroupNamesParams) ([]string, error) // GetUserLatencyInsights returns the median and 95th percentile connection // latency that users have experienced. The result can be filtered on // template_ids, meaning only user data from workspaces based on those templates diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index b3216fc2d8c80..6391d900ae2a9 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -1524,6 +1524,57 @@ func (q *sqlQuerier) GetGroupsByOrganizationID(ctx context.Context, organization return items, nil } +const getUserGroupNames = `-- name: GetUserGroupNames :many +SELECT + groups.name +FROM + groups +LEFT JOIN + group_members +ON + group_members.group_id = groups.id AND + group_members.user_id = $1 +LEFT JOIN + organization_members +ON + organization_members.organization_id = groups.id AND + organization_members.user_id = $1 +WHERE + -- In either case, the group_id will only match an org or a group. + (group_members.user_id = $1 OR organization_members.user_id = $1) +AND + -- Ensure the group or organization is the specified organization. + groups.organization_id = $2 +` + +type GetUserGroupNamesParams struct { + UserID uuid.UUID `db:"user_id" json:"user_id"` + OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"` +} + +func (q *sqlQuerier) GetUserGroupNames(ctx context.Context, arg GetUserGroupNamesParams) ([]string, error) { + rows, err := q.db.QueryContext(ctx, getUserGroupNames, arg.UserID, arg.OrganizationID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []string + for rows.Next() { + var name string + if err := rows.Scan(&name); err != nil { + return nil, err + } + items = append(items, name) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const insertAllUsersGroup = `-- name: InsertAllUsersGroup :one INSERT INTO groups ( id, diff --git a/coderd/database/queries/groups.sql b/coderd/database/queries/groups.sql index e772d21a5840f..33e626cadda08 100644 --- a/coderd/database/queries/groups.sql +++ b/coderd/database/queries/groups.sql @@ -28,6 +28,29 @@ FROM WHERE organization_id = $1; +-- name: GetUserGroupNames :many +SELECT + groups.name +FROM + groups +LEFT JOIN + group_members +ON + group_members.group_id = groups.id AND + group_members.user_id = @user_id +LEFT JOIN + organization_members +ON + organization_members.organization_id = groups.id AND + organization_members.user_id = @user_id +WHERE + -- In either case, the group_id will only match an org or a group. + (group_members.user_id = @user_id OR organization_members.user_id = @user_id) +AND + -- Ensure the group or organization is the specified organization. + groups.organization_id = @organization_id; + + -- name: InsertGroup :one INSERT INTO groups ( id, diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go index 48d2464724234..b5d1375e13535 100644 --- a/coderd/provisionerdserver/provisionerdserver.go +++ b/coderd/provisionerdserver/provisionerdserver.go @@ -467,22 +467,12 @@ func (s *server) acquireProtoJob(ctx context.Context, job database.ProvisionerJo if err != nil { return nil, failJob(fmt.Sprintf("get owner: %s", err)) } - orgGroups, err := s.Database.GetGroupsByOrganizationID(ctx, s.OrganizationID) + ownerGroupNames, err := s.Database.GetUserGroupNames(ctx, database.GetUserGroupNamesParams{ + UserID: owner.ID, + OrganizationID: s.OrganizationID, + }) if err != nil { - return nil, failJob(fmt.Sprintf("get owner groups: %s", err)) - } - ownerGroupNames := []string{} - for _, group := range orgGroups { - members, err := s.Database.GetGroupMembers(ctx, group.ID) - if err != nil { - return nil, failJob(fmt.Sprintf("get group members: %s", err)) - } - for _, member := range members { - if member.ID == owner.ID { - ownerGroupNames = append(ownerGroupNames, group.Name) - break - } - } + return nil, failJob(fmt.Sprintf("get owner group names: %s", err)) } err = s.Pubsub.Publish(codersdk.WorkspaceNotifyChannel(workspace.ID), []byte{}) if err != nil { From 9add6291c3e44530f1a970dff33b3ef51e311238 Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Wed, 3 Apr 2024 20:47:53 +0000 Subject: [PATCH 13/19] lint --- coderd/database/dbmem/dbmem.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index bf172673ed9e5..18bdef5d8b77e 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -4334,7 +4334,7 @@ func (q *FakeQuerier) GetUserCount(_ context.Context) (int64, error) { return existing, nil } -func (q *FakeQuerier) GetUserGroupNames(ctx context.Context, arg database.GetUserGroupNamesParams) ([]string, error) { +func (q *FakeQuerier) GetUserGroupNames(_ context.Context, arg database.GetUserGroupNamesParams) ([]string, error) { err := validateDatabaseType(arg) if err != nil { return nil, err From f55ccc197e4a2aab7106367a2e5602ff636e9483 Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Wed, 3 Apr 2024 20:53:27 +0000 Subject: [PATCH 14/19] dbauthz test --- coderd/database/dbauthz/dbauthz_test.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index 71345ccf09dc6..3de286dd81755 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -314,6 +314,15 @@ func (s *MethodTestSuite) TestGroup() { _ = dbgen.GroupMember(s.T(), db, database.GroupMember{}) check.Args(g.ID).Asserts(g, rbac.ActionRead) })) + s.Run("GetUserGroupNames", s.Subtest(func(db database.Store, check *expects) { + o := dbgen.Organization(s.T(), db, database.Organization{}) + u := dbgen.User(s.T(), db, database.User{}) + check.Args(database.GetUserGroupNamesParams{ + OrganizationID: o.ID, + UserID: u.ID, + }).Asserts(rbac.ResourceUserObject(u.ID), rbac.ActionRead) + })) + s.Run("InsertAllUsersGroup", s.Subtest(func(db database.Store, check *expects) { o := dbgen.Organization(s.T(), db, database.Organization{}) check.Args(o.ID).Asserts(rbac.ResourceGroup.InOrg(o.ID), rbac.ActionCreate) From 8afb0399759105e1ea52ff887e8ad55b483ff07c Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Thu, 4 Apr 2024 16:57:58 +0000 Subject: [PATCH 15/19] test --- coderd/database/dbauthz/dbauthz_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index 3de286dd81755..245694f30c879 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -317,10 +317,11 @@ func (s *MethodTestSuite) TestGroup() { s.Run("GetUserGroupNames", s.Subtest(func(db database.Store, check *expects) { o := dbgen.Organization(s.T(), db, database.Organization{}) u := dbgen.User(s.T(), db, database.User{}) + g := dbgen.Group(s.T(), db, database.Group{OrganizationID: o.ID}) check.Args(database.GetUserGroupNamesParams{ OrganizationID: o.ID, UserID: u.ID, - }).Asserts(rbac.ResourceUserObject(u.ID), rbac.ActionRead) + }).Asserts(g, rbac.ActionRead) })) s.Run("InsertAllUsersGroup", s.Subtest(func(db database.Store, check *expects) { From cf0fd5a4e4dd7e1673fde55df505f4a766de467b Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Thu, 4 Apr 2024 17:23:56 +0000 Subject: [PATCH 16/19] fix test --- coderd/database/dbauthz/dbauthz.go | 2 +- coderd/database/dbauthz/dbauthz_test.go | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index 50a0f1a21690b..26dccde0867c2 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -1834,7 +1834,7 @@ func (q *querier) GetUserCount(ctx context.Context) (int64, error) { } func (q *querier) GetUserGroupNames(ctx context.Context, arg database.GetUserGroupNamesParams) ([]string, error) { - if err := q.authorizeContext(ctx, rbac.ActionRead, rbac.ResourceGroup); err != nil { + if err := q.authorizeContext(ctx, rbac.ActionRead, rbac.ResourceGroup.InOrg(arg.OrganizationID)); err != nil { return nil, err } return q.db.GetUserGroupNames(ctx, arg) diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index 245694f30c879..f770f8a834355 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -315,15 +315,13 @@ func (s *MethodTestSuite) TestGroup() { check.Args(g.ID).Asserts(g, rbac.ActionRead) })) s.Run("GetUserGroupNames", s.Subtest(func(db database.Store, check *expects) { - o := dbgen.Organization(s.T(), db, database.Organization{}) - u := dbgen.User(s.T(), db, database.User{}) - g := dbgen.Group(s.T(), db, database.Group{OrganizationID: o.ID}) + g := dbgen.Group(s.T(), db, database.Group{}) + gm := dbgen.GroupMember(s.T(), db, database.GroupMember{GroupID: g.ID}) check.Args(database.GetUserGroupNamesParams{ - OrganizationID: o.ID, - UserID: u.ID, - }).Asserts(g, rbac.ActionRead) + OrganizationID: g.OrganizationID, + UserID: gm.UserID, + }).Asserts(rbac.ResourceGroup.InOrg(g.OrganizationID), rbac.ActionRead) })) - s.Run("InsertAllUsersGroup", s.Subtest(func(db database.Store, check *expects) { o := dbgen.Organization(s.T(), db, database.Organization{}) check.Args(o.ID).Asserts(rbac.ResourceGroup.InOrg(o.ID), rbac.ActionCreate) From a4da4c629641e6c9ff417d426a6ae6f5d79bbfbd Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Thu, 4 Apr 2024 20:51:04 +0000 Subject: [PATCH 17/19] make query return group over name --- coderd/database/dbauthz/dbauthz.go | 11 +-- coderd/database/dbauthz/dbauthz_test.go | 6 +- coderd/database/dbmem/dbmem.go | 48 ++++++------ coderd/database/dbmetrics/dbmetrics.go | 14 ++-- coderd/database/dbmock/dbmock.go | 30 +++---- coderd/database/querier.go | 2 +- coderd/database/queries.sql.go | 78 ++++++++++--------- coderd/database/queries/groups.sql | 4 +- .../provisionerdserver/provisionerdserver.go | 6 +- 9 files changed, 104 insertions(+), 95 deletions(-) diff --git a/coderd/database/dbauthz/dbauthz.go b/coderd/database/dbauthz/dbauthz.go index 26dccde0867c2..b0cf2f8c35f2e 100644 --- a/coderd/database/dbauthz/dbauthz.go +++ b/coderd/database/dbauthz/dbauthz.go @@ -1142,6 +1142,10 @@ func (q *querier) GetGroupMembers(ctx context.Context, id uuid.UUID) ([]database return q.db.GetGroupMembers(ctx, id) } +func (q *querier) GetGroupsByOrganizationAndUserID(ctx context.Context, arg database.GetGroupsByOrganizationAndUserIDParams) ([]database.Group, error) { + return fetchWithPostFilter(q.auth, q.db.GetGroupsByOrganizationAndUserID)(ctx, arg) +} + func (q *querier) GetGroupsByOrganizationID(ctx context.Context, organizationID uuid.UUID) ([]database.Group, error) { return fetchWithPostFilter(q.auth, q.db.GetGroupsByOrganizationID)(ctx, organizationID) } @@ -1833,13 +1837,6 @@ func (q *querier) GetUserCount(ctx context.Context) (int64, error) { return q.db.GetUserCount(ctx) } -func (q *querier) GetUserGroupNames(ctx context.Context, arg database.GetUserGroupNamesParams) ([]string, error) { - if err := q.authorizeContext(ctx, rbac.ActionRead, rbac.ResourceGroup.InOrg(arg.OrganizationID)); err != nil { - return nil, err - } - return q.db.GetUserGroupNames(ctx, arg) -} - func (q *querier) GetUserLatencyInsights(ctx context.Context, arg database.GetUserLatencyInsightsParams) ([]database.GetUserLatencyInsightsRow, error) { // Used by insights endpoints. Need to check both for auditors and for regular users with template acl perms. if err := q.authorizeContext(ctx, rbac.ActionRead, rbac.ResourceTemplateInsights); err != nil { diff --git a/coderd/database/dbauthz/dbauthz_test.go b/coderd/database/dbauthz/dbauthz_test.go index f770f8a834355..3619837732b63 100644 --- a/coderd/database/dbauthz/dbauthz_test.go +++ b/coderd/database/dbauthz/dbauthz_test.go @@ -314,13 +314,13 @@ func (s *MethodTestSuite) TestGroup() { _ = dbgen.GroupMember(s.T(), db, database.GroupMember{}) check.Args(g.ID).Asserts(g, rbac.ActionRead) })) - s.Run("GetUserGroupNames", s.Subtest(func(db database.Store, check *expects) { + s.Run("GetGroupsByOrganizationAndUserID", s.Subtest(func(db database.Store, check *expects) { g := dbgen.Group(s.T(), db, database.Group{}) gm := dbgen.GroupMember(s.T(), db, database.GroupMember{GroupID: g.ID}) - check.Args(database.GetUserGroupNamesParams{ + check.Args(database.GetGroupsByOrganizationAndUserIDParams{ OrganizationID: g.OrganizationID, UserID: gm.UserID, - }).Asserts(rbac.ResourceGroup.InOrg(g.OrganizationID), rbac.ActionRead) + }).Asserts(g, rbac.ActionRead) })) s.Run("InsertAllUsersGroup", s.Subtest(func(db database.Store, check *expects) { o := dbgen.Organization(s.T(), db, database.Organization{}) diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index 18bdef5d8b77e..e807e135b71d4 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -2250,6 +2250,30 @@ func (q *FakeQuerier) GetGroupMembers(_ context.Context, id uuid.UUID) ([]databa return users, nil } +func (q *FakeQuerier) GetGroupsByOrganizationAndUserID(ctx context.Context, arg database.GetGroupsByOrganizationAndUserIDParams) ([]database.Group, error) { + err := validateDatabaseType(arg) + if err != nil { + return nil, err + } + + q.mutex.RLock() + defer q.mutex.RUnlock() + var groupIds []uuid.UUID + for _, member := range q.groupMembers { + if member.UserID == arg.UserID { + groupIds = append(groupIds, member.GroupID) + } + } + groups := []database.Group{} + for _, group := range q.groups { + if slices.Contains(groupIds, group.ID) { + groups = append(groups, group) + } + } + + return groups, nil +} + func (q *FakeQuerier) GetGroupsByOrganizationID(_ context.Context, id uuid.UUID) ([]database.Group, error) { q.mutex.RLock() defer q.mutex.RUnlock() @@ -4334,30 +4358,6 @@ func (q *FakeQuerier) GetUserCount(_ context.Context) (int64, error) { return existing, nil } -func (q *FakeQuerier) GetUserGroupNames(_ context.Context, arg database.GetUserGroupNamesParams) ([]string, error) { - err := validateDatabaseType(arg) - if err != nil { - return nil, err - } - - q.mutex.RLock() - defer q.mutex.RUnlock() - var groupIds []uuid.UUID - for _, member := range q.groupMembers { - if member.UserID == arg.UserID { - groupIds = append(groupIds, member.GroupID) - } - } - groupNames := []string{} - for _, group := range q.groups { - if slices.Contains(groupIds, group.ID) { - groupNames = append(groupNames, group.Name) - } - } - - return groupNames, nil -} - func (q *FakeQuerier) GetUserLatencyInsights(_ context.Context, arg database.GetUserLatencyInsightsParams) ([]database.GetUserLatencyInsightsRow, error) { err := validateDatabaseType(arg) if err != nil { diff --git a/coderd/database/dbmetrics/dbmetrics.go b/coderd/database/dbmetrics/dbmetrics.go index 77430585b79c7..08ef5d2991955 100644 --- a/coderd/database/dbmetrics/dbmetrics.go +++ b/coderd/database/dbmetrics/dbmetrics.go @@ -559,6 +559,13 @@ func (m metricsStore) GetGroupMembers(ctx context.Context, groupID uuid.UUID) ([ return users, err } +func (m metricsStore) GetGroupsByOrganizationAndUserID(ctx context.Context, arg database.GetGroupsByOrganizationAndUserIDParams) ([]database.Group, error) { + start := time.Now() + r0, r1 := m.s.GetGroupsByOrganizationAndUserID(ctx, arg) + m.queryLatencies.WithLabelValues("GetGroupsByOrganizationAndUserID").Observe(time.Since(start).Seconds()) + return r0, r1 +} + func (m metricsStore) GetGroupsByOrganizationID(ctx context.Context, organizationID uuid.UUID) ([]database.Group, error) { start := time.Now() groups, err := m.s.GetGroupsByOrganizationID(ctx, organizationID) @@ -1061,13 +1068,6 @@ func (m metricsStore) GetUserCount(ctx context.Context) (int64, error) { return count, err } -func (m metricsStore) GetUserGroupNames(ctx context.Context, arg database.GetUserGroupNamesParams) ([]string, error) { - start := time.Now() - r0, r1 := m.s.GetUserGroupNames(ctx, arg) - m.queryLatencies.WithLabelValues("GetUserGroupNames").Observe(time.Since(start).Seconds()) - return r0, r1 -} - func (m metricsStore) GetUserLatencyInsights(ctx context.Context, arg database.GetUserLatencyInsightsParams) ([]database.GetUserLatencyInsightsRow, error) { start := time.Now() r0, r1 := m.s.GetUserLatencyInsights(ctx, arg) diff --git a/coderd/database/dbmock/dbmock.go b/coderd/database/dbmock/dbmock.go index 04971988b796b..f6cb941fb15da 100644 --- a/coderd/database/dbmock/dbmock.go +++ b/coderd/database/dbmock/dbmock.go @@ -1095,6 +1095,21 @@ func (mr *MockStoreMockRecorder) GetGroupMembers(arg0, arg1 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGroupMembers", reflect.TypeOf((*MockStore)(nil).GetGroupMembers), arg0, arg1) } +// GetGroupsByOrganizationAndUserID mocks base method. +func (m *MockStore) GetGroupsByOrganizationAndUserID(arg0 context.Context, arg1 database.GetGroupsByOrganizationAndUserIDParams) ([]database.Group, error) { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetGroupsByOrganizationAndUserID", arg0, arg1) + ret0, _ := ret[0].([]database.Group) + ret1, _ := ret[1].(error) + return ret0, ret1 +} + +// GetGroupsByOrganizationAndUserID indicates an expected call of GetGroupsByOrganizationAndUserID. +func (mr *MockStoreMockRecorder) GetGroupsByOrganizationAndUserID(arg0, arg1 any) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetGroupsByOrganizationAndUserID", reflect.TypeOf((*MockStore)(nil).GetGroupsByOrganizationAndUserID), arg0, arg1) +} + // GetGroupsByOrganizationID mocks base method. func (m *MockStore) GetGroupsByOrganizationID(arg0 context.Context, arg1 uuid.UUID) ([]database.Group, error) { m.ctrl.T.Helper() @@ -2205,21 +2220,6 @@ func (mr *MockStoreMockRecorder) GetUserCount(arg0 any) *gomock.Call { return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserCount", reflect.TypeOf((*MockStore)(nil).GetUserCount), arg0) } -// GetUserGroupNames mocks base method. -func (m *MockStore) GetUserGroupNames(arg0 context.Context, arg1 database.GetUserGroupNamesParams) ([]string, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetUserGroupNames", arg0, arg1) - ret0, _ := ret[0].([]string) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetUserGroupNames indicates an expected call of GetUserGroupNames. -func (mr *MockStoreMockRecorder) GetUserGroupNames(arg0, arg1 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserGroupNames", reflect.TypeOf((*MockStore)(nil).GetUserGroupNames), arg0, arg1) -} - // GetUserLatencyInsights mocks base method. func (m *MockStore) GetUserLatencyInsights(arg0 context.Context, arg1 database.GetUserLatencyInsightsParams) ([]database.GetUserLatencyInsightsRow, error) { m.ctrl.T.Helper() diff --git a/coderd/database/querier.go b/coderd/database/querier.go index 4024762219f5f..532f393ac215e 100644 --- a/coderd/database/querier.go +++ b/coderd/database/querier.go @@ -123,6 +123,7 @@ type sqlcQuerier interface { // If the group is a user made group, then we need to check the group_members table. // If it is the "Everyone" group, then we need to check the organization_members table. GetGroupMembers(ctx context.Context, groupID uuid.UUID) ([]User, error) + GetGroupsByOrganizationAndUserID(ctx context.Context, arg GetGroupsByOrganizationAndUserIDParams) ([]Group, error) GetGroupsByOrganizationID(ctx context.Context, organizationID uuid.UUID) ([]Group, error) GetHealthSettings(ctx context.Context) (string, error) GetHungProvisionerJobs(ctx context.Context, updatedAt time.Time) ([]ProvisionerJob, error) @@ -226,7 +227,6 @@ type sqlcQuerier interface { GetUserByEmailOrUsername(ctx context.Context, arg GetUserByEmailOrUsernameParams) (User, error) GetUserByID(ctx context.Context, id uuid.UUID) (User, error) GetUserCount(ctx context.Context) (int64, error) - GetUserGroupNames(ctx context.Context, arg GetUserGroupNamesParams) ([]string, error) // GetUserLatencyInsights returns the median and 95th percentile connection // latency that users have experienced. The result can be filtered on // template_ids, meaning only user data from workspaces based on those templates diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 6391d900ae2a9..c09e12cb0936c 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -1484,17 +1484,36 @@ func (q *sqlQuerier) GetGroupByOrgAndName(ctx context.Context, arg GetGroupByOrg return i, err } -const getGroupsByOrganizationID = `-- name: GetGroupsByOrganizationID :many +const getGroupsByOrganizationAndUserID = `-- name: GetGroupsByOrganizationAndUserID :many SELECT - id, name, organization_id, avatar_url, quota_allowance, display_name, source + groups.id, groups.name, groups.organization_id, groups.avatar_url, groups.quota_allowance, groups.display_name, groups.source FROM - groups + groups +LEFT JOIN + group_members +ON + group_members.group_id = groups.id AND + group_members.user_id = $1 +LEFT JOIN + organization_members +ON + organization_members.organization_id = groups.id AND + organization_members.user_id = $1 WHERE - organization_id = $1 + -- In either case, the group_id will only match an org or a group. + (group_members.user_id = $1 OR organization_members.user_id = $1) +AND + -- Ensure the group or organization is the specified organization. + groups.organization_id = $2 ` -func (q *sqlQuerier) GetGroupsByOrganizationID(ctx context.Context, organizationID uuid.UUID) ([]Group, error) { - rows, err := q.db.QueryContext(ctx, getGroupsByOrganizationID, organizationID) +type GetGroupsByOrganizationAndUserIDParams struct { + UserID uuid.UUID `db:"user_id" json:"user_id"` + OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"` +} + +func (q *sqlQuerier) GetGroupsByOrganizationAndUserID(ctx context.Context, arg GetGroupsByOrganizationAndUserIDParams) ([]Group, error) { + rows, err := q.db.QueryContext(ctx, getGroupsByOrganizationAndUserID, arg.UserID, arg.OrganizationID) if err != nil { return nil, err } @@ -1524,47 +1543,36 @@ func (q *sqlQuerier) GetGroupsByOrganizationID(ctx context.Context, organization return items, nil } -const getUserGroupNames = `-- name: GetUserGroupNames :many +const getGroupsByOrganizationID = `-- name: GetGroupsByOrganizationID :many SELECT - groups.name + id, name, organization_id, avatar_url, quota_allowance, display_name, source FROM - groups -LEFT JOIN - group_members -ON - group_members.group_id = groups.id AND - group_members.user_id = $1 -LEFT JOIN - organization_members -ON - organization_members.organization_id = groups.id AND - organization_members.user_id = $1 + groups WHERE - -- In either case, the group_id will only match an org or a group. - (group_members.user_id = $1 OR organization_members.user_id = $1) -AND - -- Ensure the group or organization is the specified organization. - groups.organization_id = $2 + organization_id = $1 ` -type GetUserGroupNamesParams struct { - UserID uuid.UUID `db:"user_id" json:"user_id"` - OrganizationID uuid.UUID `db:"organization_id" json:"organization_id"` -} - -func (q *sqlQuerier) GetUserGroupNames(ctx context.Context, arg GetUserGroupNamesParams) ([]string, error) { - rows, err := q.db.QueryContext(ctx, getUserGroupNames, arg.UserID, arg.OrganizationID) +func (q *sqlQuerier) GetGroupsByOrganizationID(ctx context.Context, organizationID uuid.UUID) ([]Group, error) { + rows, err := q.db.QueryContext(ctx, getGroupsByOrganizationID, organizationID) if err != nil { return nil, err } defer rows.Close() - var items []string + var items []Group for rows.Next() { - var name string - if err := rows.Scan(&name); err != nil { + var i Group + if err := rows.Scan( + &i.ID, + &i.Name, + &i.OrganizationID, + &i.AvatarURL, + &i.QuotaAllowance, + &i.DisplayName, + &i.Source, + ); err != nil { return nil, err } - items = append(items, name) + items = append(items, i) } if err := rows.Close(); err != nil { return nil, err diff --git a/coderd/database/queries/groups.sql b/coderd/database/queries/groups.sql index 33e626cadda08..b4066776332f6 100644 --- a/coderd/database/queries/groups.sql +++ b/coderd/database/queries/groups.sql @@ -28,9 +28,9 @@ FROM WHERE organization_id = $1; --- name: GetUserGroupNames :many +-- name: GetGroupsByOrganizationAndUserID :many SELECT - groups.name + groups.* FROM groups LEFT JOIN diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go index b5d1375e13535..9665b43f311f5 100644 --- a/coderd/provisionerdserver/provisionerdserver.go +++ b/coderd/provisionerdserver/provisionerdserver.go @@ -467,13 +467,17 @@ func (s *server) acquireProtoJob(ctx context.Context, job database.ProvisionerJo if err != nil { return nil, failJob(fmt.Sprintf("get owner: %s", err)) } - ownerGroupNames, err := s.Database.GetUserGroupNames(ctx, database.GetUserGroupNamesParams{ + ownerGroups, err := s.Database.GetGroupsByOrganizationAndUserID(ctx, database.GetGroupsByOrganizationAndUserIDParams{ UserID: owner.ID, OrganizationID: s.OrganizationID, }) if err != nil { return nil, failJob(fmt.Sprintf("get owner group names: %s", err)) } + ownerGroupNames := []string{} + for _, group := range ownerGroups { + ownerGroupNames = append(ownerGroupNames, group.Name) + } err = s.Pubsub.Publish(codersdk.WorkspaceNotifyChannel(workspace.ID), []byte{}) if err != nil { return nil, failJob(fmt.Sprintf("publish workspace update: %s", err)) From 9b82463525b31e22dbb11c8672b0404c4953dd9f Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Thu, 4 Apr 2024 20:58:08 +0000 Subject: [PATCH 18/19] add sql behavior --- coderd/database/dbmem/dbmem.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coderd/database/dbmem/dbmem.go b/coderd/database/dbmem/dbmem.go index e807e135b71d4..b30184773bb1b 100644 --- a/coderd/database/dbmem/dbmem.go +++ b/coderd/database/dbmem/dbmem.go @@ -2250,7 +2250,7 @@ func (q *FakeQuerier) GetGroupMembers(_ context.Context, id uuid.UUID) ([]databa return users, nil } -func (q *FakeQuerier) GetGroupsByOrganizationAndUserID(ctx context.Context, arg database.GetGroupsByOrganizationAndUserIDParams) ([]database.Group, error) { +func (q *FakeQuerier) GetGroupsByOrganizationAndUserID(_ context.Context, arg database.GetGroupsByOrganizationAndUserIDParams) ([]database.Group, error) { err := validateDatabaseType(arg) if err != nil { return nil, err @@ -2266,7 +2266,7 @@ func (q *FakeQuerier) GetGroupsByOrganizationAndUserID(ctx context.Context, arg } groups := []database.Group{} for _, group := range q.groups { - if slices.Contains(groupIds, group.ID) { + if slices.Contains(groupIds, group.ID) && group.OrganizationID == arg.OrganizationID { groups = append(groups, group) } } From ebae3f80e14494906358e535f5a2f463ae18752a Mon Sep 17 00:00:00 2001 From: Garrett Delfosse Date: Fri, 5 Apr 2024 18:57:55 +0000 Subject: [PATCH 19/19] update query docs --- coderd/database/queries.sql.go | 2 ++ coderd/database/queries/groups.sql | 2 ++ 2 files changed, 4 insertions(+) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index c09e12cb0936c..35c55dd6fe3ec 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -1489,11 +1489,13 @@ SELECT groups.id, groups.name, groups.organization_id, groups.avatar_url, groups.quota_allowance, groups.display_name, groups.source FROM groups + -- If the group is a user made group, then we need to check the group_members table. LEFT JOIN group_members ON group_members.group_id = groups.id AND group_members.user_id = $1 + -- If it is the "Everyone" group, then we need to check the organization_members table. LEFT JOIN organization_members ON diff --git a/coderd/database/queries/groups.sql b/coderd/database/queries/groups.sql index b4066776332f6..53d0b25874987 100644 --- a/coderd/database/queries/groups.sql +++ b/coderd/database/queries/groups.sql @@ -33,11 +33,13 @@ SELECT groups.* FROM groups + -- If the group is a user made group, then we need to check the group_members table. LEFT JOIN group_members ON group_members.group_id = groups.id AND group_members.user_id = @user_id + -- If it is the "Everyone" group, then we need to check the organization_members table. LEFT JOIN organization_members ON