diff --git a/components/server/src/auth/resource-access.spec.ts b/components/server/src/auth/resource-access.spec.ts index d65694526985a6..4cb20d6172085b 100644 --- a/components/server/src/auth/resource-access.spec.ts +++ b/components/server/src/auth/resource-access.spec.ts @@ -833,6 +833,76 @@ class TestResourceAccess { teamRole: "owner", expectation: true, }, + // prebuild + { + name: "prebuild get owner", + resourceKind: "prebuild", + workspaceType: "prebuild", + isOwner: true, + teamRole: undefined, + expectation: true, + }, + { + name: "prebuild get other", + resourceKind: "prebuild", + workspaceType: "prebuild", + isOwner: false, + teamRole: undefined, + expectation: false, + }, + { + name: "prebuild get team member", + resourceKind: "prebuild", + workspaceType: "prebuild", + isOwner: false, + teamRole: "member", + expectation: true, + }, + { + name: "prebuild get team owner (same as member)", + resourceKind: "prebuild", + workspaceType: "prebuild", + isOwner: false, + teamRole: "owner", + expectation: true, + }, + // prebuild with repo access + { + name: "prebuild get owner", + resourceKind: "prebuild", + workspaceType: "prebuild", + isOwner: true, + teamRole: undefined, + repositoryAccess: true, + expectation: true, + }, + { + name: "prebuild get other", + resourceKind: "prebuild", + workspaceType: "prebuild", + isOwner: false, + teamRole: undefined, + repositoryAccess: true, + expectation: true, + }, + { + name: "prebuild get team member", + resourceKind: "prebuild", + workspaceType: "prebuild", + isOwner: false, + teamRole: "member", + repositoryAccess: true, + expectation: true, + }, + { + name: "prebuild get team owner (same as member)", + resourceKind: "prebuild", + workspaceType: "prebuild", + isOwner: false, + teamRole: "owner", + repositoryAccess: true, + expectation: true, + }, ]; for (const t of tests) { diff --git a/components/server/src/auth/resource-access.ts b/components/server/src/auth/resource-access.ts index 0ff63ed717c87e..b24e48a9f1d01e 100644 --- a/components/server/src/auth/resource-access.ts +++ b/components/server/src/auth/resource-access.ts @@ -7,6 +7,7 @@ import { CommitContext, GitpodToken, + PrebuiltWorkspace, Repository, Snapshot, Team, @@ -36,7 +37,8 @@ export type GuardedResource = | GuardedContentBlob | GuardEnvVar | GuardedTeam - | GuardedWorkspaceLog; + | GuardedWorkspaceLog + | GuardedPrebuild; const ALL_GUARDED_RESOURCE_KINDS = new Set([ "workspace", @@ -119,6 +121,13 @@ export interface GuardedWorkspaceLog { teamMembers?: TeamMemberInfo[]; } +export interface GuardedPrebuild { + kind: "prebuild"; + subject: PrebuiltWorkspace; + workspace: Workspace; + teamMembers?: TeamMemberInfo[]; +} + export type ResourceAccessOp = "create" | "update" | "get" | "delete"; export const ResourceAccessGuard = Symbol("ResourceAccessGuard"); @@ -208,7 +217,17 @@ export class OwnerResourceGuard implements ResourceAccessGuard { return resource.members.some((m) => m.userId === this.userId && m.role === "owner"); } case "workspaceLog": - return resource.subject.ownerId === this.userId; + // Owners may do everything, team members can "get" + return ( + resource.subject.ownerId === this.userId || + (operation === "get" && !!resource.teamMembers?.some((m) => m.userId === this.userId)) + ); + case "prebuild": + // Owners may do everything, team members can "get" + return ( + resource.workspace.ownerId === this.userId || + (operation === "get" && !!resource.teamMembers?.some((m) => m.userId === this.userId)) + ); } } } @@ -477,6 +496,8 @@ export class RepositoryResourceGuard implements ResourceAccessGuard { case "snapshot": workspace = resource.workspace; break; + case "prebuild": + workspace = resource.workspace; default: // We do not handle resource kinds here! return false;