Skip to content

Commit 22044b9

Browse files
committed
[prebuild] Support opening a specfic prebuild
1 parent 42a62d2 commit 22044b9

File tree

5 files changed

+67
-5
lines changed

5 files changed

+67
-5
lines changed

components/dashboard/src/projects/Prebuild.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,9 @@ export default function () {
181181
) : prebuild?.status === "available" ? (
182182
<a
183183
className="my-auto"
184-
href={gitpodHostUrl.withContext(`${prebuild?.info.changeUrl}`).toString()}
184+
href={gitpodHostUrl
185+
.withContext(`open-prebuild/${prebuild?.info.id}/${prebuild?.info.changeUrl}`)
186+
.toString()}
185187
>
186188
<button>New Workspace ({prebuild?.info.branch})</button>
187189
</a>

components/gitpod-protocol/src/protocol.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1200,6 +1200,16 @@ export namespace AdditionalContentContext {
12001200
}
12011201
}
12021202

1203+
export interface OpenPrebuildContext extends WorkspaceContext {
1204+
openPrebuilID: string;
1205+
}
1206+
1207+
export namespace OpenPrebuildContext {
1208+
export function is(ctx: any): ctx is OpenPrebuildContext {
1209+
return "openPrebuildID" in ctx;
1210+
}
1211+
}
1212+
12031213
export interface CommitContext extends WorkspaceContext, GitCheckoutInfo {
12041214
/** @deprecated Moved to .repository.cloneUrl, left here for backwards-compatibility for old workspace contextes in the DB */
12051215
cloneUrl?: string;

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

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ import { EntitlementService, MayStartWorkspaceResult } from "../../../src/billin
115115
import { BillingMode } from "@gitpod/gitpod-protocol/lib/billing-mode";
116116
import { BillingModes } from "../billing/billing-mode";
117117
import { UsageServiceDefinition } from "@gitpod/usage-api/lib/usage/v1/usage.pb";
118+
import { OpenPrebuildContext } from "@gitpod/gitpod-protocol/src/protocol";
118119

119120
@injectable()
120121
export class GitpodServerEEImpl extends GitpodServerImpl {
@@ -963,9 +964,19 @@ export class GitpodServerEEImpl extends GitpodServerImpl {
963964

964965
const logCtx: LogContext = { userId: user.id };
965966
const cloneUrl = context.repository.cloneUrl;
966-
const prebuiltWorkspace = await this.workspaceDb
967-
.trace(ctx)
968-
.findPrebuiltWorkspaceByCommit(cloneUrl, commitSHAs);
967+
let prebuiltWorkspace: PrebuiltWorkspace | undefined;
968+
if (OpenPrebuildContext.is(context)) {
969+
prebuiltWorkspace = await this.workspaceDb.trace(ctx).findPrebuildByID(context.openPrebuilID);
970+
if (prebuiltWorkspace?.cloneURL !== cloneUrl) {
971+
// prevent users from opening arbitrary prebuilds this way - they must match the clone URL so that the resource guards are correct.
972+
return;
973+
}
974+
} else {
975+
prebuiltWorkspace = await this.workspaceDb
976+
.trace(ctx)
977+
.findPrebuiltWorkspaceByCommit(cloneUrl, commitSHAs);
978+
}
979+
969980
const logPayload = { mode, cloneUrl, commit: commitSHAs, prebuiltWorkspace };
970981
log.debug(logCtx, "Looking for prebuilt workspace: ", logPayload);
971982
if (!prebuiltWorkspace) {
@@ -994,7 +1005,7 @@ export class GitpodServerEEImpl extends GitpodServerImpl {
9941005
const makeResult = (instanceID: string): WorkspaceCreationResult => {
9951006
return <WorkspaceCreationResult>{
9961007
runningWorkspacePrebuild: {
997-
prebuildID: prebuiltWorkspace.id,
1008+
prebuildID: prebuiltWorkspace!.id,
9981009
workspaceID,
9991010
instanceID,
10001011
starting: "queued",

components/server/src/container-module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ import { LivenessController } from "./liveness/liveness-controller";
113113
import { IDEServiceClient, IDEServiceDefinition } from "@gitpod/ide-service-api/lib/ide.pb";
114114
import { prometheusClientMiddleware } from "@gitpod/gitpod-protocol/lib/util/nice-grpc";
115115
import { UsageService } from "./user/usage-service";
116+
import { OpenPrebuildPrefixContextParser } from "./workspace/open-prebuild-prefix-context-parser";
116117

117118
export const productionContainerModule = new ContainerModule((bind, unbind, isBound, rebind) => {
118119
bind(Config).toConstantValue(ConfigFile.fromFile());
@@ -189,6 +190,7 @@ export const productionContainerModule = new ContainerModule((bind, unbind, isBo
189190
bind(IPrefixContextParser).to(EnvvarPrefixParser).inSingletonScope();
190191
bind(IPrefixContextParser).to(ImageBuildPrefixContextParser).inSingletonScope();
191192
bind(IPrefixContextParser).to(AdditionalContentPrefixContextParser).inSingletonScope();
193+
bind(IPrefixContextParser).to(OpenPrebuildPrefixContextParser).inSingletonScope();
192194

193195
bind(GitTokenScopeGuesser).toSelf().inSingletonScope();
194196
bind(GitTokenValidator).toSelf().inSingletonScope();
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/**
2+
* Copyright (c) 2021 Gitpod GmbH. All rights reserved.
3+
* Licensed under the GNU Affero General Public License (AGPL).
4+
* See License-AGPL.txt in the project root for license information.
5+
*/
6+
7+
import { User, WorkspaceContext } from "@gitpod/gitpod-protocol";
8+
import { log } from "@gitpod/gitpod-protocol/lib/util/logging";
9+
import { OpenPrebuildContext } from "@gitpod/gitpod-protocol/src/protocol";
10+
import { inject, injectable } from "inversify";
11+
import { Config } from "../config";
12+
import { IPrefixContextParser } from "./context-parser";
13+
14+
@injectable()
15+
export class OpenPrebuildPrefixContextParser implements IPrefixContextParser {
16+
@inject(Config) protected readonly config: Config;
17+
static PREFIX = /^\/?open-prebuild\/([^\/]*)\//;
18+
19+
findPrefix(user: User, context: string): string | undefined {
20+
const result = OpenPrebuildPrefixContextParser.PREFIX.exec(context);
21+
if (!result) {
22+
return undefined;
23+
}
24+
return result[0];
25+
}
26+
27+
public async handle(user: User, prefix: string, context: WorkspaceContext): Promise<WorkspaceContext> {
28+
const match = OpenPrebuildPrefixContextParser.PREFIX.exec(prefix);
29+
if (!match) {
30+
log.error("Could not parse prefix " + prefix);
31+
return context;
32+
}
33+
34+
(context as OpenPrebuildContext).openPrebuilID = match[1];
35+
return context;
36+
}
37+
}

0 commit comments

Comments
 (0)