Skip to content

Commit

Permalink
[fga] added create_snapshot permission
Browse files Browse the repository at this point in the history
  • Loading branch information
svenefftinge committed Aug 21, 2023
1 parent 4bf139e commit c5f9575
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 6 deletions.
1 change: 1 addition & 0 deletions components/server/src/authorization/authorizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,7 @@ export class Authorizer {

await this.authorizer.writeRelationships(
set(rel.organization(orgId).installation.installation), //
set(rel.organization(orgId).snapshoter.organization_member(orgId)), //TODO allow orgs to opt-out of snapshotting
);
}

Expand Down
36 changes: 34 additions & 2 deletions components/server/src/authorization/definitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export type InstallationPermission = "create_organization";

export type OrganizationResourceType = "organization";

export type OrganizationRelation = "installation" | "member" | "owner";
export type OrganizationRelation = "installation" | "member" | "owner" | "snapshoter";

export type OrganizationPermission =
| "installation_admin"
Expand Down Expand Up @@ -91,7 +91,7 @@ export type WorkspaceResourceType = "workspace";

export type WorkspaceRelation = "org" | "owner" | "shared";

export type WorkspacePermission = "access" | "start" | "stop" | "delete" | "read_info";
export type WorkspacePermission = "access" | "start" | "stop" | "delete" | "read_info" | "create_snapshot";

export const rel = {
user(id: string) {
Expand Down Expand Up @@ -281,6 +281,38 @@ export const rel = {
},
};
},

get snapshoter() {
const result2 = {
...result,
relation: "snapshoter",
};
return {
user(objectId: string) {
return {
...result2,
subject: {
object: {
objectType: "user",
objectId: objectId,
},
},
} as v1.Relationship;
},
organization_member(objectId: string) {
return {
...result2,
subject: {
object: {
objectType: "organization",
objectId: objectId,
},
optionalRelation: "member",
},
} as v1.Relationship;
},
};
},
};
},

Expand Down
8 changes: 5 additions & 3 deletions components/server/src/workspace/gitpod-server-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1907,6 +1907,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
const user = await this.checkAndBlockUser("takeSnapshot");

const workspace = await this.guardSnaphotAccess(ctx, user.id, workspaceId);
await this.auth.checkPermissionOnWorkspace(user.id, "create_snapshot", workspaceId);

const instance = await this.workspaceDb.trace(ctx).findRunningInstance(workspaceId);
if (!instance) {
Expand Down Expand Up @@ -1974,11 +1975,12 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {

const user = await this.checkAndBlockUser("getSnapshots");

const workspace = await this.workspaceDb.trace(ctx).findById(workspaceId);
if (!workspace || workspace.ownerId !== user.id) {
// we use the workspacService which checks if the requesting user has access to the workspace. If that is the case they have access to snapshots as well.
// below is the old permission check which would also check if the user has access to the snapshot itself. This is not the case anymore.
const workspace = await this.workspaceService.getWorkspace(user.id, workspaceId);
if (workspace.ownerId !== user.id) {
throw new ApplicationError(ErrorCodes.NOT_FOUND, `Workspace ${workspaceId} does not exist.`);
}

const snapshots = await this.workspaceDb.trace(ctx).findSnapshotsByWorkspaceId(workspaceId);
await Promise.all(snapshots.map((s) => this.guardAccess({ kind: "snapshot", subject: s, workspace }, "get")));

Expand Down
6 changes: 5 additions & 1 deletion components/spicedb/schema/schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ schema: |-
relation member: user
// Some users in an organization may additionally have the `owner` role
relation owner: user
// users who can snapshot workspaces
relation snapshoter: user | organization#member
// synthetic permission for installation->admin (because https://github.com/authzed/spicedb/issues/15)
permission installation_admin = installation->admin
Expand Down Expand Up @@ -89,7 +92,6 @@ schema: |-
// * the project has granted access to all members in an organization
// * the project has granted access to _any_ user on this installation
relation viewer: user | organization#member | user:*
permission read_info = viewer + editor + org->owner + org->installation_admin
permission write_info = editor + org->owner + org->installation_admin
permission delete = editor + org->owner + org->installation_admin
Expand Down Expand Up @@ -121,6 +123,8 @@ schema: |-
// Whether a user can read basic info/metadata of a workspace
//+ (hasAccessToRepository && isPrebuild)
permission read_info = owner + shared + org->member
permission create_snapshot = owner & org->snapshoter
}
# relationships to be used for assertions & validation
relationships: |-
Expand Down

0 comments on commit c5f9575

Please sign in to comment.