chore(coderd/rbac): add Action{Create,Delete}Agent to ResourceWorkspace (#17932)

This commit is contained in:
Danielle Maywood
2025-05-20 21:20:56 +01:00
committed by GitHub
parent d2d21898f2
commit 3e7ff9d9e1
19 changed files with 253 additions and 11 deletions
+4
View File
@@ -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",
+4
View File
@@ -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",
+22 -3
View File
@@ -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)
}
+31 -2
View File
@@ -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)
+27
View File
@@ -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)
+15
View File
@@ -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()
+1
View File
@@ -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)
+59
View File
@@ -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
+24
View File
@@ -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
*
+6
View File
@@ -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,
+6
View File
@@ -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
View File
@@ -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{},
+10 -1
View File
@@ -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},
+4 -2
View File
@@ -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},
}
+10
View File
@@ -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` |
+2
View File
@@ -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` |
+4
View File
@@ -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",
+4
View File
@@ -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",