mirror of
https://github.com/coder/coder.git
synced 2026-06-02 20:48:20 +00:00
chore(coderd/rbac): add Action{Create,Delete}Agent to ResourceWorkspace (#17932)
This commit is contained in:
Generated
+4
@@ -14901,7 +14901,9 @@ const docTemplate = `{
|
||||
"application_connect",
|
||||
"assign",
|
||||
"create",
|
||||
"create_agent",
|
||||
"delete",
|
||||
"delete_agent",
|
||||
"read",
|
||||
"read_personal",
|
||||
"ssh",
|
||||
@@ -14917,7 +14919,9 @@ const docTemplate = `{
|
||||
"ActionApplicationConnect",
|
||||
"ActionAssign",
|
||||
"ActionCreate",
|
||||
"ActionCreateAgent",
|
||||
"ActionDelete",
|
||||
"ActionDeleteAgent",
|
||||
"ActionRead",
|
||||
"ActionReadPersonal",
|
||||
"ActionSSH",
|
||||
|
||||
Generated
+4
@@ -13509,7 +13509,9 @@
|
||||
"application_connect",
|
||||
"assign",
|
||||
"create",
|
||||
"create_agent",
|
||||
"delete",
|
||||
"delete_agent",
|
||||
"read",
|
||||
"read_personal",
|
||||
"ssh",
|
||||
@@ -13525,7 +13527,9 @@
|
||||
"ActionApplicationConnect",
|
||||
"ActionAssign",
|
||||
"ActionCreate",
|
||||
"ActionCreateAgent",
|
||||
"ActionDelete",
|
||||
"ActionDeleteAgent",
|
||||
"ActionRead",
|
||||
"ActionReadPersonal",
|
||||
"ActionSSH",
|
||||
|
||||
@@ -177,7 +177,7 @@ var (
|
||||
// Unsure why provisionerd needs update and read personal
|
||||
rbac.ResourceUser.Type: {policy.ActionRead, policy.ActionReadPersonal, policy.ActionUpdatePersonal},
|
||||
rbac.ResourceWorkspaceDormant.Type: {policy.ActionDelete, policy.ActionRead, policy.ActionUpdate, policy.ActionWorkspaceStop},
|
||||
rbac.ResourceWorkspace.Type: {policy.ActionDelete, policy.ActionRead, policy.ActionUpdate, policy.ActionWorkspaceStart, policy.ActionWorkspaceStop},
|
||||
rbac.ResourceWorkspace.Type: {policy.ActionDelete, policy.ActionRead, policy.ActionUpdate, policy.ActionWorkspaceStart, policy.ActionWorkspaceStop, policy.ActionCreateAgent},
|
||||
rbac.ResourceApiKey.Type: {policy.WildcardSymbol},
|
||||
// When org scoped provisioner credentials are implemented,
|
||||
// this can be reduced to read a specific org.
|
||||
@@ -339,7 +339,7 @@ var (
|
||||
rbac.ResourceProvisionerDaemon.Type: {policy.ActionCreate, policy.ActionRead, policy.ActionUpdate},
|
||||
rbac.ResourceUser.Type: rbac.ResourceUser.AvailableActions(),
|
||||
rbac.ResourceWorkspaceDormant.Type: {policy.ActionUpdate, policy.ActionDelete, policy.ActionWorkspaceStop},
|
||||
rbac.ResourceWorkspace.Type: {policy.ActionUpdate, policy.ActionDelete, policy.ActionWorkspaceStart, policy.ActionWorkspaceStop, policy.ActionSSH},
|
||||
rbac.ResourceWorkspace.Type: {policy.ActionUpdate, policy.ActionDelete, policy.ActionWorkspaceStart, policy.ActionWorkspaceStop, policy.ActionSSH, policy.ActionCreateAgent, policy.ActionDeleteAgent},
|
||||
rbac.ResourceWorkspaceProxy.Type: {policy.ActionCreate, policy.ActionUpdate, policy.ActionDelete},
|
||||
rbac.ResourceDeploymentConfig.Type: {policy.ActionCreate, policy.ActionUpdate, policy.ActionDelete},
|
||||
rbac.ResourceNotificationMessage.Type: {policy.ActionCreate, policy.ActionRead, policy.ActionUpdate, policy.ActionDelete},
|
||||
@@ -3180,6 +3180,10 @@ func (q *querier) GetWorkspaceByOwnerIDAndName(ctx context.Context, arg database
|
||||
return fetch(q.log, q.auth, q.db.GetWorkspaceByOwnerIDAndName)(ctx, arg)
|
||||
}
|
||||
|
||||
func (q *querier) GetWorkspaceByResourceID(ctx context.Context, resourceID uuid.UUID) (database.Workspace, error) {
|
||||
return fetch(q.log, q.auth, q.db.GetWorkspaceByResourceID)(ctx, resourceID)
|
||||
}
|
||||
|
||||
func (q *querier) GetWorkspaceByWorkspaceAppID(ctx context.Context, workspaceAppID uuid.UUID) (database.Workspace, error) {
|
||||
return fetch(q.log, q.auth, q.db.GetWorkspaceByWorkspaceAppID)(ctx, workspaceAppID)
|
||||
}
|
||||
@@ -3713,9 +3717,24 @@ func (q *querier) InsertWorkspace(ctx context.Context, arg database.InsertWorksp
|
||||
}
|
||||
|
||||
func (q *querier) InsertWorkspaceAgent(ctx context.Context, arg database.InsertWorkspaceAgentParams) (database.WorkspaceAgent, error) {
|
||||
if err := q.authorizeContext(ctx, policy.ActionCreate, rbac.ResourceSystem); err != nil {
|
||||
// NOTE(DanielleMaywood):
|
||||
// Currently, the only way to link a Resource back to a Workspace is by following this chain:
|
||||
//
|
||||
// WorkspaceResource -> WorkspaceBuild -> Workspace
|
||||
//
|
||||
// It is possible for this function to be called without there existing
|
||||
// a `WorkspaceBuild` to link back to. This means that we want to allow
|
||||
// execution to continue if there isn't a workspace found to allow this
|
||||
// behavior to continue.
|
||||
workspace, err := q.db.GetWorkspaceByResourceID(ctx, arg.ResourceID)
|
||||
if err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||
return database.WorkspaceAgent{}, err
|
||||
}
|
||||
|
||||
if err := q.authorizeContext(ctx, policy.ActionCreateAgent, workspace); err != nil {
|
||||
return database.WorkspaceAgent{}, err
|
||||
}
|
||||
|
||||
return q.db.InsertWorkspaceAgent(ctx, arg)
|
||||
}
|
||||
|
||||
|
||||
@@ -1928,6 +1928,22 @@ func (s *MethodTestSuite) TestWorkspace() {
|
||||
})
|
||||
check.Args(ws.ID).Asserts(ws, policy.ActionRead)
|
||||
}))
|
||||
s.Run("GetWorkspaceByResourceID", s.Subtest(func(db database.Store, check *expects) {
|
||||
u := dbgen.User(s.T(), db, database.User{})
|
||||
o := dbgen.Organization(s.T(), db, database.Organization{})
|
||||
j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{Type: database.ProvisionerJobTypeWorkspaceBuild})
|
||||
tpl := dbgen.Template(s.T(), db, database.Template{CreatedBy: u.ID, OrganizationID: o.ID})
|
||||
tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{
|
||||
TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true},
|
||||
JobID: j.ID,
|
||||
OrganizationID: o.ID,
|
||||
CreatedBy: u.ID,
|
||||
})
|
||||
ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{OwnerID: u.ID, TemplateID: tpl.ID, OrganizationID: o.ID})
|
||||
_ = dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: j.ID, TemplateVersionID: tv.ID})
|
||||
res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: j.ID})
|
||||
check.Args(res.ID).Asserts(ws, policy.ActionRead)
|
||||
}))
|
||||
s.Run("GetWorkspaces", s.Subtest(func(_ database.Store, check *expects) {
|
||||
// No asserts here because SQLFilter.
|
||||
check.Args(database.GetWorkspacesParams{}).Asserts()
|
||||
@@ -4018,12 +4034,25 @@ func (s *MethodTestSuite) TestSystemFunctions() {
|
||||
Returns(slice.New(a, b))
|
||||
}))
|
||||
s.Run("InsertWorkspaceAgent", s.Subtest(func(db database.Store, check *expects) {
|
||||
dbtestutil.DisableForeignKeysAndTriggers(s.T(), db)
|
||||
u := dbgen.User(s.T(), db, database.User{})
|
||||
o := dbgen.Organization(s.T(), db, database.Organization{})
|
||||
j := dbgen.ProvisionerJob(s.T(), db, nil, database.ProvisionerJob{Type: database.ProvisionerJobTypeWorkspaceBuild})
|
||||
tpl := dbgen.Template(s.T(), db, database.Template{CreatedBy: u.ID, OrganizationID: o.ID})
|
||||
tv := dbgen.TemplateVersion(s.T(), db, database.TemplateVersion{
|
||||
TemplateID: uuid.NullUUID{UUID: tpl.ID, Valid: true},
|
||||
JobID: j.ID,
|
||||
OrganizationID: o.ID,
|
||||
CreatedBy: u.ID,
|
||||
})
|
||||
ws := dbgen.Workspace(s.T(), db, database.WorkspaceTable{OwnerID: u.ID, TemplateID: tpl.ID, OrganizationID: o.ID})
|
||||
_ = dbgen.WorkspaceBuild(s.T(), db, database.WorkspaceBuild{WorkspaceID: ws.ID, JobID: j.ID, TemplateVersionID: tv.ID})
|
||||
res := dbgen.WorkspaceResource(s.T(), db, database.WorkspaceResource{JobID: j.ID})
|
||||
check.Args(database.InsertWorkspaceAgentParams{
|
||||
ID: uuid.New(),
|
||||
ResourceID: res.ID,
|
||||
Name: "dev",
|
||||
APIKeyScope: database.AgentKeyScopeEnumAll,
|
||||
}).Asserts(rbac.ResourceSystem, policy.ActionCreate)
|
||||
}).Asserts(ws, policy.ActionCreateAgent)
|
||||
}))
|
||||
s.Run("InsertWorkspaceApp", s.Subtest(func(db database.Store, check *expects) {
|
||||
dbtestutil.DisableForeignKeysAndTriggers(s.T(), db)
|
||||
|
||||
@@ -8053,6 +8053,33 @@ func (q *FakeQuerier) GetWorkspaceByOwnerIDAndName(_ context.Context, arg databa
|
||||
return database.Workspace{}, sql.ErrNoRows
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) GetWorkspaceByResourceID(ctx context.Context, resourceID uuid.UUID) (database.Workspace, error) {
|
||||
q.mutex.RLock()
|
||||
defer q.mutex.RUnlock()
|
||||
|
||||
for _, resource := range q.workspaceResources {
|
||||
if resource.ID != resourceID {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, build := range q.workspaceBuilds {
|
||||
if build.JobID != resource.JobID {
|
||||
continue
|
||||
}
|
||||
|
||||
for _, workspace := range q.workspaces {
|
||||
if workspace.ID != build.WorkspaceID {
|
||||
continue
|
||||
}
|
||||
|
||||
return q.extendWorkspace(workspace), nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return database.Workspace{}, sql.ErrNoRows
|
||||
}
|
||||
|
||||
func (q *FakeQuerier) GetWorkspaceByWorkspaceAppID(_ context.Context, workspaceAppID uuid.UUID) (database.Workspace, error) {
|
||||
if err := validateDatabaseType(workspaceAppID); err != nil {
|
||||
return database.Workspace{}, err
|
||||
|
||||
@@ -1887,6 +1887,13 @@ func (m queryMetricsStore) GetWorkspaceByOwnerIDAndName(ctx context.Context, arg
|
||||
return workspace, err
|
||||
}
|
||||
|
||||
func (m queryMetricsStore) GetWorkspaceByResourceID(ctx context.Context, resourceID uuid.UUID) (database.Workspace, error) {
|
||||
start := time.Now()
|
||||
r0, r1 := m.s.GetWorkspaceByResourceID(ctx, resourceID)
|
||||
m.queryLatencies.WithLabelValues("GetWorkspaceByResourceID").Observe(time.Since(start).Seconds())
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
func (m queryMetricsStore) GetWorkspaceByWorkspaceAppID(ctx context.Context, workspaceAppID uuid.UUID) (database.Workspace, error) {
|
||||
start := time.Now()
|
||||
workspace, err := m.s.GetWorkspaceByWorkspaceAppID(ctx, workspaceAppID)
|
||||
|
||||
@@ -3963,6 +3963,21 @@ func (mr *MockStoreMockRecorder) GetWorkspaceByOwnerIDAndName(ctx, arg any) *gom
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceByOwnerIDAndName", reflect.TypeOf((*MockStore)(nil).GetWorkspaceByOwnerIDAndName), ctx, arg)
|
||||
}
|
||||
|
||||
// GetWorkspaceByResourceID mocks base method.
|
||||
func (m *MockStore) GetWorkspaceByResourceID(ctx context.Context, resourceID uuid.UUID) (database.Workspace, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetWorkspaceByResourceID", ctx, resourceID)
|
||||
ret0, _ := ret[0].(database.Workspace)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// GetWorkspaceByResourceID indicates an expected call of GetWorkspaceByResourceID.
|
||||
func (mr *MockStoreMockRecorder) GetWorkspaceByResourceID(ctx, resourceID any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetWorkspaceByResourceID", reflect.TypeOf((*MockStore)(nil).GetWorkspaceByResourceID), ctx, resourceID)
|
||||
}
|
||||
|
||||
// GetWorkspaceByWorkspaceAppID mocks base method.
|
||||
func (m *MockStore) GetWorkspaceByWorkspaceAppID(ctx context.Context, workspaceAppID uuid.UUID) (database.Workspace, error) {
|
||||
m.ctrl.T.Helper()
|
||||
|
||||
@@ -422,6 +422,7 @@ type sqlcQuerier interface {
|
||||
GetWorkspaceByAgentID(ctx context.Context, agentID uuid.UUID) (Workspace, error)
|
||||
GetWorkspaceByID(ctx context.Context, id uuid.UUID) (Workspace, error)
|
||||
GetWorkspaceByOwnerIDAndName(ctx context.Context, arg GetWorkspaceByOwnerIDAndNameParams) (Workspace, error)
|
||||
GetWorkspaceByResourceID(ctx context.Context, resourceID uuid.UUID) (Workspace, error)
|
||||
GetWorkspaceByWorkspaceAppID(ctx context.Context, workspaceAppID uuid.UUID) (Workspace, error)
|
||||
GetWorkspaceModulesByJobID(ctx context.Context, jobID uuid.UUID) ([]WorkspaceModule, error)
|
||||
GetWorkspaceModulesCreatedAfter(ctx context.Context, createdAt time.Time) ([]WorkspaceModule, error)
|
||||
|
||||
@@ -18143,6 +18143,65 @@ func (q *sqlQuerier) GetWorkspaceByOwnerIDAndName(ctx context.Context, arg GetWo
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getWorkspaceByResourceID = `-- name: GetWorkspaceByResourceID :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, owner_avatar_url, owner_username, organization_name, organization_display_name, organization_icon, organization_description, template_name, template_display_name, template_icon, template_description
|
||||
FROM
|
||||
workspaces_expanded as workspaces
|
||||
WHERE
|
||||
workspaces.id = (
|
||||
SELECT
|
||||
workspace_id
|
||||
FROM
|
||||
workspace_builds
|
||||
WHERE
|
||||
workspace_builds.job_id = (
|
||||
SELECT
|
||||
job_id
|
||||
FROM
|
||||
workspace_resources
|
||||
WHERE
|
||||
workspace_resources.id = $1
|
||||
)
|
||||
)
|
||||
LIMIT
|
||||
1
|
||||
`
|
||||
|
||||
func (q *sqlQuerier) GetWorkspaceByResourceID(ctx context.Context, resourceID uuid.UUID) (Workspace, error) {
|
||||
row := q.db.QueryRowContext(ctx, getWorkspaceByResourceID, resourceID)
|
||||
var i Workspace
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.OwnerID,
|
||||
&i.OrganizationID,
|
||||
&i.TemplateID,
|
||||
&i.Deleted,
|
||||
&i.Name,
|
||||
&i.AutostartSchedule,
|
||||
&i.Ttl,
|
||||
&i.LastUsedAt,
|
||||
&i.DormantAt,
|
||||
&i.DeletingAt,
|
||||
&i.AutomaticUpdates,
|
||||
&i.Favorite,
|
||||
&i.NextStartAt,
|
||||
&i.OwnerAvatarUrl,
|
||||
&i.OwnerUsername,
|
||||
&i.OrganizationName,
|
||||
&i.OrganizationDisplayName,
|
||||
&i.OrganizationIcon,
|
||||
&i.OrganizationDescription,
|
||||
&i.TemplateName,
|
||||
&i.TemplateDisplayName,
|
||||
&i.TemplateIcon,
|
||||
&i.TemplateDescription,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const getWorkspaceByWorkspaceAppID = `-- name: GetWorkspaceByWorkspaceAppID :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, owner_avatar_url, owner_username, organization_name, organization_display_name, organization_icon, organization_description, template_name, template_display_name, template_icon, template_description
|
||||
|
||||
@@ -8,6 +8,30 @@ WHERE
|
||||
LIMIT
|
||||
1;
|
||||
|
||||
-- name: GetWorkspaceByResourceID :one
|
||||
SELECT
|
||||
*
|
||||
FROM
|
||||
workspaces_expanded as workspaces
|
||||
WHERE
|
||||
workspaces.id = (
|
||||
SELECT
|
||||
workspace_id
|
||||
FROM
|
||||
workspace_builds
|
||||
WHERE
|
||||
workspace_builds.job_id = (
|
||||
SELECT
|
||||
job_id
|
||||
FROM
|
||||
workspace_resources
|
||||
WHERE
|
||||
workspace_resources.id = @resource_id
|
||||
)
|
||||
)
|
||||
LIMIT
|
||||
1;
|
||||
|
||||
-- name: GetWorkspaceByWorkspaceAppID :one
|
||||
SELECT
|
||||
*
|
||||
|
||||
@@ -308,7 +308,9 @@ var (
|
||||
// Valid Actions
|
||||
// - "ActionApplicationConnect" :: connect to workspace apps via browser
|
||||
// - "ActionCreate" :: create a new workspace
|
||||
// - "ActionCreateAgent" :: create a new workspace agent
|
||||
// - "ActionDelete" :: delete workspace
|
||||
// - "ActionDeleteAgent" :: delete an existing workspace agent
|
||||
// - "ActionRead" :: read workspace data to view on the UI
|
||||
// - "ActionSSH" :: ssh into a given workspace
|
||||
// - "ActionWorkspaceStart" :: allows starting a workspace
|
||||
@@ -338,7 +340,9 @@ var (
|
||||
// Valid Actions
|
||||
// - "ActionApplicationConnect" :: connect to workspace apps via browser
|
||||
// - "ActionCreate" :: create a new workspace
|
||||
// - "ActionCreateAgent" :: create a new workspace agent
|
||||
// - "ActionDelete" :: delete workspace
|
||||
// - "ActionDeleteAgent" :: delete an existing workspace agent
|
||||
// - "ActionRead" :: read workspace data to view on the UI
|
||||
// - "ActionSSH" :: ssh into a given workspace
|
||||
// - "ActionWorkspaceStart" :: allows starting a workspace
|
||||
@@ -406,7 +410,9 @@ func AllActions() []policy.Action {
|
||||
policy.ActionApplicationConnect,
|
||||
policy.ActionAssign,
|
||||
policy.ActionCreate,
|
||||
policy.ActionCreateAgent,
|
||||
policy.ActionDelete,
|
||||
policy.ActionDeleteAgent,
|
||||
policy.ActionRead,
|
||||
policy.ActionReadPersonal,
|
||||
policy.ActionSSH,
|
||||
|
||||
@@ -24,6 +24,9 @@ const (
|
||||
|
||||
ActionReadPersonal Action = "read_personal"
|
||||
ActionUpdatePersonal Action = "update_personal"
|
||||
|
||||
ActionCreateAgent Action = "create_agent"
|
||||
ActionDeleteAgent Action = "delete_agent"
|
||||
)
|
||||
|
||||
type PermissionDefinition struct {
|
||||
@@ -67,6 +70,9 @@ var workspaceActions = map[Action]ActionDefinition{
|
||||
// Running a workspace
|
||||
ActionSSH: actDef("ssh into a given workspace"),
|
||||
ActionApplicationConnect: actDef("connect to workspace apps via browser"),
|
||||
|
||||
ActionCreateAgent: actDef("create a new workspace agent"),
|
||||
ActionDeleteAgent: actDef("delete an existing workspace agent"),
|
||||
}
|
||||
|
||||
// RBACPermissions is indexed by the type
|
||||
|
||||
+13
-3
@@ -272,7 +272,7 @@ func ReloadBuiltinRoles(opts *RoleOptions) {
|
||||
// This adds back in the Workspace permissions.
|
||||
Permissions(map[string][]policy.Action{
|
||||
ResourceWorkspace.Type: ownerWorkspaceActions,
|
||||
ResourceWorkspaceDormant.Type: {policy.ActionRead, policy.ActionDelete, policy.ActionCreate, policy.ActionUpdate, policy.ActionWorkspaceStop},
|
||||
ResourceWorkspaceDormant.Type: {policy.ActionRead, policy.ActionDelete, policy.ActionCreate, policy.ActionUpdate, policy.ActionWorkspaceStop, policy.ActionCreateAgent, policy.ActionDeleteAgent},
|
||||
})...),
|
||||
Org: map[string][]Permission{},
|
||||
User: []Permission{},
|
||||
@@ -291,7 +291,7 @@ func ReloadBuiltinRoles(opts *RoleOptions) {
|
||||
User: append(allPermsExcept(ResourceWorkspaceDormant, ResourceUser, ResourceOrganizationMember),
|
||||
Permissions(map[string][]policy.Action{
|
||||
// Reduced permission set on dormant workspaces. No build, ssh, or exec
|
||||
ResourceWorkspaceDormant.Type: {policy.ActionRead, policy.ActionDelete, policy.ActionCreate, policy.ActionUpdate, policy.ActionWorkspaceStop},
|
||||
ResourceWorkspaceDormant.Type: {policy.ActionRead, policy.ActionDelete, policy.ActionCreate, policy.ActionUpdate, policy.ActionWorkspaceStop, policy.ActionCreateAgent, policy.ActionDeleteAgent},
|
||||
// Users cannot do create/update/delete on themselves, but they
|
||||
// can read their own details.
|
||||
ResourceUser.Type: {policy.ActionRead, policy.ActionReadPersonal, policy.ActionUpdatePersonal},
|
||||
@@ -412,7 +412,7 @@ func ReloadBuiltinRoles(opts *RoleOptions) {
|
||||
Org: map[string][]Permission{
|
||||
// Org admins should not have workspace exec perms.
|
||||
organizationID.String(): append(allPermsExcept(ResourceWorkspace, ResourceWorkspaceDormant, ResourceAssignRole), Permissions(map[string][]policy.Action{
|
||||
ResourceWorkspaceDormant.Type: {policy.ActionRead, policy.ActionDelete, policy.ActionCreate, policy.ActionUpdate, policy.ActionWorkspaceStop},
|
||||
ResourceWorkspaceDormant.Type: {policy.ActionRead, policy.ActionDelete, policy.ActionCreate, policy.ActionUpdate, policy.ActionWorkspaceStop, policy.ActionCreateAgent, policy.ActionDeleteAgent},
|
||||
ResourceWorkspace.Type: slice.Omit(ResourceWorkspace.AvailableActions(), policy.ActionApplicationConnect, policy.ActionSSH),
|
||||
})...),
|
||||
},
|
||||
@@ -529,6 +529,16 @@ func ReloadBuiltinRoles(opts *RoleOptions) {
|
||||
ResourceType: ResourceWorkspace.Type,
|
||||
Action: policy.ActionDelete,
|
||||
},
|
||||
{
|
||||
Negate: true,
|
||||
ResourceType: ResourceWorkspace.Type,
|
||||
Action: policy.ActionCreateAgent,
|
||||
},
|
||||
{
|
||||
Negate: true,
|
||||
ResourceType: ResourceWorkspace.Type,
|
||||
Action: policy.ActionDeleteAgent,
|
||||
},
|
||||
},
|
||||
},
|
||||
User: []Permission{},
|
||||
|
||||
@@ -226,6 +226,15 @@ func TestRolePermissions(t *testing.T) {
|
||||
false: {setOtherOrg, setOrgNotMe, memberMe, templateAdmin, userAdmin},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "CreateDeleteWorkspaceAgent",
|
||||
Actions: []policy.Action{policy.ActionCreateAgent, policy.ActionDeleteAgent},
|
||||
Resource: rbac.ResourceWorkspace.WithID(workspaceID).InOrg(orgID).WithOwner(currentUser.String()),
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {owner, orgMemberMe, orgAdmin},
|
||||
false: {setOtherOrg, memberMe, userAdmin, templateAdmin, orgTemplateAdmin, orgUserAdmin, orgAuditor, orgMemberMeBanWorkspace},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "Templates",
|
||||
Actions: []policy.Action{policy.ActionCreate, policy.ActionUpdate, policy.ActionDelete},
|
||||
@@ -462,7 +471,7 @@ func TestRolePermissions(t *testing.T) {
|
||||
},
|
||||
{
|
||||
Name: "WorkspaceDormant",
|
||||
Actions: append(crud, policy.ActionWorkspaceStop),
|
||||
Actions: append(crud, policy.ActionWorkspaceStop, policy.ActionCreateAgent, policy.ActionDeleteAgent),
|
||||
Resource: rbac.ResourceWorkspaceDormant.WithID(uuid.New()).InOrg(orgID).WithOwner(memberMe.Actor.ID),
|
||||
AuthorizeMap: map[bool][]hasAuthSubjects{
|
||||
true: {orgMemberMe, orgAdmin, owner},
|
||||
|
||||
@@ -49,7 +49,9 @@ const (
|
||||
ActionApplicationConnect RBACAction = "application_connect"
|
||||
ActionAssign RBACAction = "assign"
|
||||
ActionCreate RBACAction = "create"
|
||||
ActionCreateAgent RBACAction = "create_agent"
|
||||
ActionDelete RBACAction = "delete"
|
||||
ActionDeleteAgent RBACAction = "delete_agent"
|
||||
ActionRead RBACAction = "read"
|
||||
ActionReadPersonal RBACAction = "read_personal"
|
||||
ActionSSH RBACAction = "ssh"
|
||||
@@ -97,9 +99,9 @@ var RBACResourceActions = map[RBACResource][]RBACAction{
|
||||
ResourceTemplate: {ActionCreate, ActionDelete, ActionRead, ActionUpdate, ActionUse, ActionViewInsights},
|
||||
ResourceUser: {ActionCreate, ActionDelete, ActionRead, ActionReadPersonal, ActionUpdate, ActionUpdatePersonal},
|
||||
ResourceWebpushSubscription: {ActionCreate, ActionDelete, ActionRead},
|
||||
ResourceWorkspace: {ActionApplicationConnect, ActionCreate, ActionDelete, ActionRead, ActionSSH, ActionWorkspaceStart, ActionWorkspaceStop, ActionUpdate},
|
||||
ResourceWorkspace: {ActionApplicationConnect, ActionCreate, ActionCreateAgent, ActionDelete, ActionDeleteAgent, ActionRead, ActionSSH, ActionWorkspaceStart, ActionWorkspaceStop, ActionUpdate},
|
||||
ResourceWorkspaceAgentDevcontainers: {ActionCreate},
|
||||
ResourceWorkspaceAgentResourceMonitor: {ActionCreate, ActionRead, ActionUpdate},
|
||||
ResourceWorkspaceDormant: {ActionApplicationConnect, ActionCreate, ActionDelete, ActionRead, ActionSSH, ActionWorkspaceStart, ActionWorkspaceStop, ActionUpdate},
|
||||
ResourceWorkspaceDormant: {ActionApplicationConnect, ActionCreate, ActionCreateAgent, ActionDelete, ActionDeleteAgent, ActionRead, ActionSSH, ActionWorkspaceStart, ActionWorkspaceStop, ActionUpdate},
|
||||
ResourceWorkspaceProxy: {ActionCreate, ActionDelete, ActionRead, ActionUpdate},
|
||||
}
|
||||
|
||||
Generated
+10
@@ -169,7 +169,9 @@ Status Code **200**
|
||||
| `action` | `application_connect` |
|
||||
| `action` | `assign` |
|
||||
| `action` | `create` |
|
||||
| `action` | `create_agent` |
|
||||
| `action` | `delete` |
|
||||
| `action` | `delete_agent` |
|
||||
| `action` | `read` |
|
||||
| `action` | `read_personal` |
|
||||
| `action` | `ssh` |
|
||||
@@ -336,7 +338,9 @@ Status Code **200**
|
||||
| `action` | `application_connect` |
|
||||
| `action` | `assign` |
|
||||
| `action` | `create` |
|
||||
| `action` | `create_agent` |
|
||||
| `action` | `delete` |
|
||||
| `action` | `delete_agent` |
|
||||
| `action` | `read` |
|
||||
| `action` | `read_personal` |
|
||||
| `action` | `ssh` |
|
||||
@@ -503,7 +507,9 @@ Status Code **200**
|
||||
| `action` | `application_connect` |
|
||||
| `action` | `assign` |
|
||||
| `action` | `create` |
|
||||
| `action` | `create_agent` |
|
||||
| `action` | `delete` |
|
||||
| `action` | `delete_agent` |
|
||||
| `action` | `read` |
|
||||
| `action` | `read_personal` |
|
||||
| `action` | `ssh` |
|
||||
@@ -639,7 +645,9 @@ Status Code **200**
|
||||
| `action` | `application_connect` |
|
||||
| `action` | `assign` |
|
||||
| `action` | `create` |
|
||||
| `action` | `create_agent` |
|
||||
| `action` | `delete` |
|
||||
| `action` | `delete_agent` |
|
||||
| `action` | `read` |
|
||||
| `action` | `read_personal` |
|
||||
| `action` | `ssh` |
|
||||
@@ -997,7 +1005,9 @@ Status Code **200**
|
||||
| `action` | `application_connect` |
|
||||
| `action` | `assign` |
|
||||
| `action` | `create` |
|
||||
| `action` | `create_agent` |
|
||||
| `action` | `delete` |
|
||||
| `action` | `delete_agent` |
|
||||
| `action` | `read` |
|
||||
| `action` | `read_personal` |
|
||||
| `action` | `ssh` |
|
||||
|
||||
Generated
+2
@@ -5913,7 +5913,9 @@ Git clone makes use of this by parsing the URL from: 'Username for "https://gith
|
||||
| `application_connect` |
|
||||
| `assign` |
|
||||
| `create` |
|
||||
| `create_agent` |
|
||||
| `delete` |
|
||||
| `delete_agent` |
|
||||
| `read` |
|
||||
| `read_personal` |
|
||||
| `ssh` |
|
||||
|
||||
@@ -173,7 +173,9 @@ export const RBACResourceActions: Partial<
|
||||
workspace: {
|
||||
application_connect: "connect to workspace apps via browser",
|
||||
create: "create a new workspace",
|
||||
create_agent: "create a new workspace agent",
|
||||
delete: "delete workspace",
|
||||
delete_agent: "delete an existing workspace agent",
|
||||
read: "read workspace data to view on the UI",
|
||||
ssh: "ssh into a given workspace",
|
||||
start: "allows starting a workspace",
|
||||
@@ -191,7 +193,9 @@ export const RBACResourceActions: Partial<
|
||||
workspace_dormant: {
|
||||
application_connect: "connect to workspace apps via browser",
|
||||
create: "create a new workspace",
|
||||
create_agent: "create a new workspace agent",
|
||||
delete: "delete workspace",
|
||||
delete_agent: "delete an existing workspace agent",
|
||||
read: "read workspace data to view on the UI",
|
||||
ssh: "ssh into a given workspace",
|
||||
start: "allows starting a workspace",
|
||||
|
||||
Generated
+4
@@ -2131,7 +2131,9 @@ export type RBACAction =
|
||||
| "application_connect"
|
||||
| "assign"
|
||||
| "create"
|
||||
| "create_agent"
|
||||
| "delete"
|
||||
| "delete_agent"
|
||||
| "read"
|
||||
| "read_personal"
|
||||
| "ssh"
|
||||
@@ -2147,7 +2149,9 @@ export const RBACActions: RBACAction[] = [
|
||||
"application_connect",
|
||||
"assign",
|
||||
"create",
|
||||
"create_agent",
|
||||
"delete",
|
||||
"delete_agent",
|
||||
"read",
|
||||
"read_personal",
|
||||
"ssh",
|
||||
|
||||
Reference in New Issue
Block a user