Skip to content

Commit ded77f3

Browse files
authored
[server] don't error on project not_found (#18400)
1 parent 5a7b346 commit ded77f3

File tree

5 files changed

+50
-50
lines changed

5 files changed

+50
-50
lines changed

components/gitpod-protocol/src/messaging/error.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,17 @@ export namespace ApplicationError {
2525
export function hasErrorCode(e: any): e is Error & { code: ErrorCode; data?: any } {
2626
return e && e.code !== undefined;
2727
}
28+
29+
export async function notFoundToUndefined<T>(p: Promise<T>): Promise<T | undefined> {
30+
try {
31+
return await p;
32+
} catch (e) {
33+
if (hasErrorCode(e) && e.code === ErrorCodes.NOT_FOUND) {
34+
return undefined;
35+
}
36+
throw e;
37+
}
38+
}
2839
}
2940

3041
export namespace ErrorCode {

components/server/src/workspace/env-var-service.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
} from "@gitpod/gitpod-protocol";
1616
import { inject, injectable } from "inversify";
1717
import { ProjectsService } from "../projects/projects-service";
18+
import { ApplicationError } from "@gitpod/gitpod-protocol/lib/messaging/error";
1819

1920
export interface ResolvedEnvVars {
2021
// all project env vars, censored included always
@@ -43,8 +44,11 @@ export class EnvVarService {
4344
};
4445

4546
const projectEnvVars = workspace.projectId
46-
? await this.projectsService.getProjectEnvironmentVariables(workspace.ownerId, workspace.projectId)
47+
? (await ApplicationError.notFoundToUndefined(
48+
this.projectsService.getProjectEnvironmentVariables(workspace.ownerId, workspace.projectId),
49+
)) || []
4750
: [];
51+
4852
if (workspace.type === "prebuild") {
4953
// prebuild does not have access to user env vars and cannot be started via prewfix URL
5054
const withValues = await this.projectDB.getProjectEnvironmentVariableValues(projectEnvVars);

components/server/src/workspace/gitpod-server-impl.ts

Lines changed: 29 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -844,17 +844,6 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
844844
await this.userDeletionService.deleteUser(user.id);
845845
}
846846

847-
private async getTeamMembersByProject(projectId: string | undefined): Promise<TeamMemberInfo[]> {
848-
const user = await this.checkUser("getTeamMembersByProject");
849-
if (projectId) {
850-
const project = await this.projectsService.getProject(user.id, projectId);
851-
if (project && project.teamId) {
852-
return await this.organizationService.listMembers(user.id, project.teamId);
853-
}
854-
}
855-
return [];
856-
}
857-
858847
public async getWorkspace(ctx: TraceContext, workspaceId: string): Promise<WorkspaceInfo> {
859848
traceAPIParams(ctx, { workspaceId });
860849
traceWI(ctx, { workspaceId });
@@ -863,8 +852,8 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
863852

864853
const workspace = await this.internalGetWorkspace(user, workspaceId, this.workspaceDb.trace(ctx));
865854
const latestInstancePromise = this.workspaceDb.trace(ctx).findCurrentInstance(workspaceId);
866-
const teamMembers = await this.getTeamMembersByProject(workspace.projectId);
867-
await this.guardAccess({ kind: "workspace", subject: workspace, teamMembers }, "get");
855+
const teamMembers = await this.organizationService.listMembers(user.id, workspace.organizationId);
856+
await this.guardAccess({ kind: "workspace", subject: workspace, teamMembers: teamMembers }, "get");
868857
const latestInstance = await latestInstancePromise;
869858
if (!!latestInstance) {
870859
await this.guardAccess(
@@ -978,7 +967,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
978967
}
979968
const envVarsPromise = this.envVarService.resolve(workspace);
980969
const projectPromise = workspace.projectId
981-
? this.projectsService.getProject(user.id, workspace.projectId)
970+
? ApplicationError.notFoundToUndefined(this.projectsService.getProject(user.id, workspace.projectId))
982971
: Promise.resolve(undefined);
983972

984973
await mayStartPromise;
@@ -1008,15 +997,15 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
1008997
const workspace = await this.internalGetWorkspace(user, workspaceId, this.workspaceDb.trace(ctx));
1009998
if (workspace.type === "prebuild") {
1010999
// If this is a team prebuild, any team member can stop it.
1011-
const teamMembers = await this.getTeamMembersByProject(workspace.projectId);
1000+
const teamMembers = await this.organizationService.listMembers(user.id, workspace.organizationId);
10121001
await this.guardAccess({ kind: "workspace", subject: workspace, teamMembers }, "get");
10131002
} else {
10141003
// If this is not a prebuild, or it's a personal prebuild, only the workspace owner can stop it.
10151004
await this.guardAccess({ kind: "workspace", subject: workspace }, "get");
10161005
}
10171006

10181007
try {
1019-
await this.internalStopWorkspace(ctx, workspace, "stopped via API");
1008+
await this.internalStopWorkspace(ctx, user.id, workspace, "stopped via API");
10201009
} catch (err) {
10211010
log.error(logCtx, "stopWorkspace error: ", err);
10221011
if (isClusterMaintenanceError(err)) {
@@ -1031,6 +1020,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
10311020

10321021
private async internalStopWorkspace(
10331022
ctx: TraceContext,
1023+
requestorId: string,
10341024
workspace: Workspace,
10351025
reason: string,
10361026
policy?: StopWorkspacePolicy,
@@ -1049,7 +1039,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
10491039
if (!admin) {
10501040
if (workspace.type === "prebuild") {
10511041
// If this is a team prebuild, any team member can stop it.
1052-
const teamMembers = await this.getTeamMembersByProject(workspace.projectId);
1042+
const teamMembers = await this.organizationService.listMembers(requestorId, workspace.organizationId);
10531043
await this.guardAccess(
10541044
{ kind: "workspaceInstance", subject: instance, workspace, teamMembers },
10551045
"update",
@@ -1113,7 +1103,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
11131103
await this.guardAccess({ kind: "workspace", subject: ws }, "delete");
11141104

11151105
// for good measure, try and stop running instances
1116-
await this.internalStopWorkspace(ctx, ws, "deleted via API");
1106+
await this.internalStopWorkspace(ctx, user.id, ws, "deleted via API");
11171107

11181108
// actually delete the workspace
11191109
await this.workspaceDeletionService.softDeleteWorkspace(ctx, ws, "user");
@@ -1593,9 +1583,6 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
15931583
const user = await this.checkAndBlockUser("getPrebuildEvents");
15941584

15951585
const project = await this.projectsService.getProject(user.id, projectId);
1596-
if (!project) {
1597-
throw new ApplicationError(ErrorCodes.NOT_FOUND, "Project not found");
1598-
}
15991586
await this.guardProjectOperation(user, projectId, "get");
16001587

16011588
const events = await this.projectsService.getPrebuildEvents(user.id, project.cloneUrl);
@@ -1612,9 +1599,6 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
16121599
const user = await this.checkAndBlockUser("triggerPrebuild");
16131600

16141601
const project = await this.projectsService.getProject(user.id, projectId);
1615-
if (!project) {
1616-
throw new ApplicationError(ErrorCodes.NOT_FOUND, "Project not found");
1617-
}
16181602
await this.guardProjectOperation(user, projectId, "update");
16191603

16201604
const branchDetails = !!branchName
@@ -2120,7 +2104,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
21202104
return;
21212105
}
21222106
traceWI(ctx, { instanceId: instance.id });
2123-
const teamMembers = await this.getTeamMembersByProject(workspace.projectId);
2107+
const teamMembers = await this.organizationService.listMembers(user.id, workspace.organizationId);
21242108
await this.guardAccess({ kind: "workspaceLog", subject: workspace, teamMembers }, "get");
21252109

21262110
// wait for up to 20s for imageBuildLogInfo to appear due to:
@@ -2197,7 +2181,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
21972181
async getHeadlessLog(ctx: TraceContext, instanceId: string): Promise<HeadlessLogUrls> {
21982182
traceAPIParams(ctx, { instanceId });
21992183

2200-
await this.checkAndBlockUser("getHeadlessLog", { instanceId });
2184+
const user = await this.checkAndBlockUser("getHeadlessLog", { instanceId });
22012185
const logCtx: LogContext = { instanceId };
22022186

22032187
const ws = await this.workspaceDb.trace(ctx).findByInstanceId(instanceId);
@@ -2206,7 +2190,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
22062190
}
22072191

22082192
const wsiPromise = this.workspaceDb.trace(ctx).findInstanceById(instanceId);
2209-
const teamMembers = await this.getTeamMembersByProject(ws.projectId);
2193+
const teamMembers = await this.organizationService.listMembers(user.id, ws.organizationId);
22102194

22112195
await this.guardAccess({ kind: "workspaceLog", subject: ws, teamMembers }, "get");
22122196

@@ -2810,9 +2794,6 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
28102794

28112795
private async guardProjectOperation(user: User, projectId: string, op: ResourceAccessOp): Promise<void> {
28122796
const project = await this.projectsService.getProject(user.id, projectId);
2813-
if (!project) {
2814-
throw new ApplicationError(ErrorCodes.NOT_FOUND, "Project not found");
2815-
}
28162797
// Anyone who can read a team's information (i.e. any team member) can manage team projects
28172798
await this.guardTeamOperation(project.teamId, "get", "not_implemented");
28182799
}
@@ -2870,7 +2851,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
28702851

28712852
public async getPrebuild(ctx: TraceContext, prebuildId: string): Promise<PrebuildWithStatus | undefined> {
28722853
traceAPIParams(ctx, { prebuildId });
2873-
await this.checkAndBlockUser("getPrebuild");
2854+
const user = await this.checkAndBlockUser("getPrebuild");
28742855

28752856
const pbws = await this.workspaceDb.trace(ctx).findPrebuiltWorkspaceById(prebuildId);
28762857
if (!pbws) {
@@ -2887,9 +2868,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
28872868
return undefined;
28882869
}
28892870

2890-
// TODO(gpl) Ideally, we should not need to query the project-team hierarchy here, but decide on a per-prebuild basis.
2891-
// For that we need to fix Prebuild-access semantics, which is out-of-scope for now.
2892-
const teamMembers = await this.getTeamMembersByProject(workspace.projectId);
2871+
const teamMembers = await this.organizationService.listMembers(user.id, workspace.organizationId);
28932872
await this.guardAccess({ kind: "prebuild", subject: pbws, workspace, teamMembers }, "get");
28942873
const result: PrebuildWithStatus = { info, status: pbws.state };
28952874
if (pbws.error) {
@@ -2903,7 +2882,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
29032882
workspaceId: string,
29042883
): Promise<PrebuiltWorkspace | undefined> {
29052884
traceAPIParams(ctx, { workspaceId });
2906-
await this.checkAndBlockUser("findPrebuildByWorkspaceID");
2885+
const user = await this.checkAndBlockUser("findPrebuildByWorkspaceID");
29072886

29082887
const [pbws, workspace] = await Promise.all([
29092888
this.workspaceDb.trace(ctx).findPrebuildByWorkspaceID(workspaceId),
@@ -2913,9 +2892,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
29132892
return undefined;
29142893
}
29152894

2916-
// TODO(gpl) Ideally, we should not need to query the project-team hierarchy here, but decide on a per-prebuild basis.
2917-
// For that we need to fix Prebuild-access semantics, which is out-of-scope for now.
2918-
const teamMembers = await this.getTeamMembersByProject(workspace.projectId);
2895+
const teamMembers = await this.organizationService.listMembers(user.id, workspace.organizationId);
29192896
await this.guardAccess({ kind: "prebuild", subject: pbws, workspace, teamMembers }, "get");
29202897
return pbws;
29212898
}
@@ -2954,10 +2931,7 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
29542931

29552932
const user = await this.checkAndBlockUser("cancelPrebuild");
29562933

2957-
const project = await this.projectsService.getProject(user.id, projectId);
2958-
if (!project) {
2959-
throw new ApplicationError(ErrorCodes.NOT_FOUND, "Project not found");
2960-
}
2934+
await this.projectsService.getProject(user.id, projectId);
29612935
await this.guardProjectOperation(user, projectId, "update");
29622936

29632937
const prebuild = await this.workspaceDb.trace(ctx).findPrebuildByID(prebuildId);
@@ -3299,11 +3273,22 @@ export class GitpodServerImpl implements GitpodServerWithTracing, Disposable {
32993273
async adminForceStopWorkspace(ctx: TraceContext, workspaceId: string): Promise<void> {
33003274
traceAPIParams(ctx, { workspaceId });
33013275

3302-
await this.guardAdminAccess("adminForceStopWorkspace", { id: workspaceId }, Permission.ADMIN_WORKSPACES);
3276+
const admin = await this.guardAdminAccess(
3277+
"adminForceStopWorkspace",
3278+
{ id: workspaceId },
3279+
Permission.ADMIN_WORKSPACES,
3280+
);
33033281

33043282
const workspace = await this.workspaceDb.trace(ctx).findById(workspaceId);
33053283
if (workspace) {
3306-
await this.internalStopWorkspace(ctx, workspace, "stopped by admin", StopWorkspacePolicy.IMMEDIATELY, true);
3284+
await this.internalStopWorkspace(
3285+
ctx,
3286+
admin.id,
3287+
workspace,
3288+
"stopped by admin",
3289+
StopWorkspacePolicy.IMMEDIATELY,
3290+
true,
3291+
);
33073292
}
33083293
}
33093294

components/server/src/workspace/headless-log-controller.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import { BearerAuth } from "../auth/bearer-authenticator";
3434
import { ProjectsService } from "../projects/projects-service";
3535
import { HostContextProvider } from "../auth/host-context-provider";
3636
import { TraceContext } from "@gitpod/gitpod-protocol/lib/util/tracing";
37+
import { ApplicationError } from "@gitpod/gitpod-protocol/lib/messaging/error";
3738

3839
export const HEADLESS_LOGS_PATH_PREFIX = "/headless-logs";
3940
export const HEADLESS_LOG_DOWNLOAD_PATH_PREFIX = "/headless-log-download";
@@ -214,7 +215,9 @@ export class HeadlessLogController {
214215

215216
let teamMembers: TeamMemberInfo[] = [];
216217
if (workspace?.projectId) {
217-
const p = await this.projectService.getProject(user.id, workspace.projectId);
218+
const p = await ApplicationError.notFoundToUndefined(
219+
this.projectService.getProject(user.id, workspace.projectId),
220+
);
218221
if (p?.teamId) {
219222
teamMembers = await this.teamDb.findMembersByTeam(p.teamId);
220223
}

components/server/src/workspace/workspace-starter.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -696,10 +696,7 @@ export class WorkspaceStarter {
696696
metadata.setMetaId(workspace.id);
697697
if (workspace.projectId) {
698698
metadata.setProject(workspace.projectId);
699-
const project = await this.projectDB.findProjectById(workspace.projectId);
700-
if (project && project.teamId) {
701-
metadata.setTeam(project.teamId);
702-
}
699+
metadata.setTeam(workspace.organizationId);
703700
}
704701

705702
return metadata;

0 commit comments

Comments
 (0)