mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat: add endpoint for retrieving workspace acl (#19375)
Implements `/acl [get]` for workspaces, with tests. Blocked by experiment enablement
This commit is contained in:
@@ -184,20 +184,24 @@ func TemplateVersionParameter(param database.TemplateVersionParameter) (codersdk
|
||||
}, nil
|
||||
}
|
||||
|
||||
func MinimalUser(user database.User) codersdk.MinimalUser {
|
||||
return codersdk.MinimalUser{
|
||||
ID: user.ID,
|
||||
Username: user.Username,
|
||||
AvatarURL: user.AvatarURL,
|
||||
}
|
||||
}
|
||||
|
||||
func ReducedUser(user database.User) codersdk.ReducedUser {
|
||||
return codersdk.ReducedUser{
|
||||
MinimalUser: codersdk.MinimalUser{
|
||||
ID: user.ID,
|
||||
Username: user.Username,
|
||||
AvatarURL: user.AvatarURL,
|
||||
},
|
||||
Email: user.Email,
|
||||
Name: user.Name,
|
||||
CreatedAt: user.CreatedAt,
|
||||
UpdatedAt: user.UpdatedAt,
|
||||
LastSeenAt: user.LastSeenAt,
|
||||
Status: codersdk.UserStatus(user.Status),
|
||||
LoginType: codersdk.LoginType(user.LoginType),
|
||||
MinimalUser: MinimalUser(user),
|
||||
Email: user.Email,
|
||||
Name: user.Name,
|
||||
CreatedAt: user.CreatedAt,
|
||||
UpdatedAt: user.UpdatedAt,
|
||||
LastSeenAt: user.LastSeenAt,
|
||||
Status: codersdk.UserStatus(user.Status),
|
||||
LoginType: codersdk.LoginType(user.LoginType),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3236,6 +3236,17 @@ func (q *querier) GetWebpushVAPIDKeys(ctx context.Context) (database.GetWebpushV
|
||||
return q.db.GetWebpushVAPIDKeys(ctx)
|
||||
}
|
||||
|
||||
func (q *querier) GetWorkspaceACLByID(ctx context.Context, id uuid.UUID) (database.GetWorkspaceACLByIDRow, error) {
|
||||
workspace, err := q.db.GetWorkspaceByID(ctx, id)
|
||||
if err != nil {
|
||||
return database.GetWorkspaceACLByIDRow{}, err
|
||||
}
|
||||
if err := q.authorizeContext(ctx, policy.ActionCreate, workspace); err != nil {
|
||||
return database.GetWorkspaceACLByIDRow{}, err
|
||||
}
|
||||
return q.db.GetWorkspaceACLByID(ctx, id)
|
||||
}
|
||||
|
||||
func (q *querier) GetWorkspaceAgentAndLatestBuildByAuthToken(ctx context.Context, authToken uuid.UUID) (database.GetWorkspaceAgentAndLatestBuildByAuthTokenRow, error) {
|
||||
// This is a system function
|
||||
if err := q.authorizeContext(ctx, policy.ActionRead, rbac.ResourceSystem); err != nil {
|
||||
|
||||
@@ -1887,21 +1887,18 @@ func (s *MethodTestSuite) TestWorkspace() {
|
||||
// no asserts here because SQLFilter
|
||||
check.Args([]uuid.UUID{}, emptyPreparedAuthorized{}).Asserts()
|
||||
}))
|
||||
s.Run("UpdateWorkspaceACLByID", s.Subtest(func(db database.Store, check *expects) {
|
||||
u := dbgen.User(s.T(), db, database.User{})
|
||||
o := dbgen.Organization(s.T(), db, database.Organization{})
|
||||
tpl := dbgen.Template(s.T(), db, database.Template{
|
||||
OrganizationID: o.ID,
|
||||
CreatedBy: u.ID,
|
||||
})
|
||||
ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{
|
||||
OwnerID: u.ID,
|
||||
OrganizationID: o.ID,
|
||||
TemplateID: tpl.ID,
|
||||
})
|
||||
check.Args(database.UpdateWorkspaceACLByIDParams{
|
||||
ID: ws.ID,
|
||||
}).Asserts(ws, policy.ActionCreate)
|
||||
s.Run("GetWorkspaceACLByID", s.Mocked(func(dbM *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
|
||||
ws := testutil.Fake(s.T(), faker, database.Workspace{})
|
||||
dbM.EXPECT().GetWorkspaceByID(gomock.Any(), ws.ID).Return(ws, nil).AnyTimes()
|
||||
dbM.EXPECT().GetWorkspaceACLByID(gomock.Any(), ws.ID).Return(database.GetWorkspaceACLByIDRow{}, nil).AnyTimes()
|
||||
check.Args(ws.ID).Asserts(ws, policy.ActionCreate)
|
||||
}))
|
||||
s.Run("UpdateWorkspaceACLByID", s.Mocked(func(dbM *dbmock.MockStore, faker *gofakeit.Faker, check *expects) {
|
||||
ws := testutil.Fake(s.T(), faker, database.Workspace{})
|
||||
params := database.UpdateWorkspaceACLByIDParams{ID: ws.ID}
|
||||
dbM.EXPECT().GetWorkspaceByID(gomock.Any(), ws.ID).Return(ws, nil).AnyTimes()
|
||||
dbM.EXPECT().UpdateWorkspaceACLByID(gomock.Any(), params).Return(nil).AnyTimes()
|
||||
check.Args(params).Asserts(ws, policy.ActionCreate)
|
||||
}))
|
||||
s.Run("GetLatestWorkspaceBuildByWorkspaceID", s.Subtest(func(db database.Store, check *expects) {
|
||||
u := dbgen.User(s.T(), db, database.User{})
|
||||
|
||||
@@ -1748,6 +1748,13 @@ func (m queryMetricsStore) GetWebpushVAPIDKeys(ctx context.Context) (database.Ge
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
func (m queryMetricsStore) GetWorkspaceACLByID(ctx context.Context, id uuid.UUID) (database.GetWorkspaceACLByIDRow, error) {
|
||||
start := time.Now()
|
||||
r0, r1 := m.s.GetWorkspaceACLByID(ctx, id)
|
||||
m.queryLatencies.WithLabelValues("GetWorkspaceACLByID").Observe(time.Since(start).Seconds())
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
func (m queryMetricsStore) GetWorkspaceAgentAndLatestBuildByAuthToken(ctx context.Context, authToken uuid.UUID) (database.GetWorkspaceAgentAndLatestBuildByAuthTokenRow, error) {
|
||||
start := time.Now()
|
||||
r0, r1 := m.s.GetWorkspaceAgentAndLatestBuildByAuthToken(ctx, authToken)
|
||||
|
||||
@@ -3721,6 +3721,21 @@ func (mr *MockStoreMockRecorder) GetWebpushVAPIDKeys(ctx any) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWebpushVAPIDKeys", reflect.TypeOf((*MockStore)(nil).GetWebpushVAPIDKeys), ctx)
|
||||
}
|
||||
|
||||
// GetWorkspaceACLByID mocks base method.
|
||||
func (m *MockStore) GetWorkspaceACLByID(ctx context.Context, id uuid.UUID) (database.GetWorkspaceACLByIDRow, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetWorkspaceACLByID", ctx, id)
|
||||
ret0, _ := ret[0].(database.GetWorkspaceACLByIDRow)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetWorkspaceACLByID indicates an expected call of GetWorkspaceACLByID.
|
||||
func (mr *MockStoreMockRecorder) GetWorkspaceACLByID(ctx, id any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceACLByID", reflect.TypeOf((*MockStore)(nil).GetWorkspaceACLByID), ctx, id)
|
||||
}
|
||||
|
||||
// GetWorkspaceAgentAndLatestBuildByAuthToken mocks base method.
|
||||
func (m *MockStore) GetWorkspaceAgentAndLatestBuildByAuthToken(ctx context.Context, authToken uuid.UUID) (database.GetWorkspaceAgentAndLatestBuildByAuthTokenRow, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
@@ -416,6 +416,7 @@ type sqlcQuerier interface {
|
||||
GetUsersByIDs(ctx context.Context, ids []uuid.UUID) ([]User, error)
|
||||
GetWebpushSubscriptionsByUserID(ctx context.Context, userID uuid.UUID) ([]WebpushSubscription, error)
|
||||
GetWebpushVAPIDKeys(ctx context.Context) (GetWebpushVAPIDKeysRow, error)
|
||||
GetWorkspaceACLByID(ctx context.Context, id uuid.UUID) (GetWorkspaceACLByIDRow, error)
|
||||
GetWorkspaceAgentAndLatestBuildByAuthToken(ctx context.Context, authToken uuid.UUID) (GetWorkspaceAgentAndLatestBuildByAuthTokenRow, error)
|
||||
GetWorkspaceAgentByID(ctx context.Context, id uuid.UUID) (WorkspaceAgent, error)
|
||||
GetWorkspaceAgentByInstanceID(ctx context.Context, authInstanceID string) (WorkspaceAgent, error)
|
||||
|
||||
@@ -20128,6 +20128,28 @@ func (q *sqlQuerier) GetDeploymentWorkspaceStats(ctx context.Context) (GetDeploy
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getWorkspaceACLByID = `-- name: GetWorkspaceACLByID :one
|
||||
SELECT
|
||||
group_acl as groups,
|
||||
user_acl as users
|
||||
FROM
|
||||
workspaces
|
||||
WHERE
|
||||
id = $1
|
||||
`
|
||||
|
||||
type GetWorkspaceACLByIDRow struct {
|
||||
Groups WorkspaceACL `db:"groups" json:"groups"`
|
||||
Users WorkspaceACL `db:"users" json:"users"`
|
||||
}
|
||||
|
||||
func (q *sqlQuerier) GetWorkspaceACLByID(ctx context.Context, id uuid.UUID) (GetWorkspaceACLByIDRow, error) {
|
||||
row := q.db.QueryRowContext(ctx, getWorkspaceACLByID, id)
|
||||
var i GetWorkspaceACLByIDRow
|
||||
err := row.Scan(&i.Groups, &i.Users)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getWorkspaceByAgentID = `-- name: GetWorkspaceByAgentID :one
|
||||
SELECT
|
||||
id, created_at, updated_at, owner_id, organization_id, template_id, deleted, name, autostart_schedule, ttl, last_used_at, dormant_at, deleting_at, automatic_updates, favorite, next_start_at, group_acl, user_acl, owner_avatar_url, owner_username, owner_name, organization_name, organization_display_name, organization_icon, organization_description, template_name, template_display_name, template_icon, template_description
|
||||
|
||||
@@ -906,6 +906,15 @@ GROUP BY workspaces.id, workspaces.name, latest_build.job_status, latest_build.j
|
||||
-- name: GetWorkspacesByTemplateID :many
|
||||
SELECT * FROM workspaces WHERE template_id = $1 AND deleted = false;
|
||||
|
||||
-- name: GetWorkspaceACLByID :one
|
||||
SELECT
|
||||
group_acl as groups,
|
||||
user_acl as users
|
||||
FROM
|
||||
workspaces
|
||||
WHERE
|
||||
id = @id;
|
||||
|
||||
-- name: UpdateWorkspaceACLByID :exec
|
||||
UPDATE
|
||||
workspaces
|
||||
|
||||
Reference in New Issue
Block a user