Skip to content

Commit 03a5477

Browse files
committed
Proper invalid contextUrl workaround
1 parent 52d3997 commit 03a5477

File tree

4 files changed

+73
-29
lines changed

4 files changed

+73
-29
lines changed

src/commands/workspaces.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,8 +324,19 @@ export class OpenWorkspaceContextCommand implements Command {
324324
return;
325325
}
326326

327+
const rawWsData = await this.sessionService.getAPI().getWorkspace(treeItem.id)
327328
const wsData = rawWorkspaceToWorkspaceData(await this.sessionService.getAPI().getWorkspace(treeItem.id));
328329

330+
// Report if we couldn't parse contextUrl
331+
if (!wsData.contextUrl) {
332+
this.telemetryService.sendTelemetryException(new Error('Unable to parse workspace contextUrl'), {
333+
gitpodHost: this.hostService.gitpodHost,
334+
workspaceId: wsData.id,
335+
contextUrl: rawWsData.context?.contextUrl,
336+
});
337+
return;
338+
}
339+
329340
this.telemetryService.sendTelemetryEvent('vscode_desktop_view_command', {
330341
name: this.id,
331342
gitpodHost: this.hostService.gitpodHost,

src/local-ssh/ipc/extensionServiceServer.ts

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@ import { ParsedKey } from 'ssh2-streams';
2222
import { isPortUsed } from '../../common/ports';
2323
import { WrapError } from '../../common/utils';
2424
import { ConnectError, Code } from '@bufbuild/connect';
25-
import { WorkspaceInstanceStatus_Phase } from '@gitpod/public-api/lib/gitpod/experimental/v1';
26-
import { WorkspacePhase } from '../../publicApi';
25+
import { rawWorkspaceToWorkspaceData } from '../../publicApi';
2726

2827
function isServiceError(obj: any): obj is ServiceError {
2928
// eslint-disable-next-line eqeqeq
@@ -109,26 +108,34 @@ class ExtensionServiceImpl implements ExtensionServiceImplementation {
109108
// TODO(lssh): Get auth info according to `request.gitpodHost`
110109
const gitpodHost = this.hostService.gitpodHost;
111110

112-
const ws = await this.sessionService.getAPI().getWorkspace(actualWorkspaceId, _context.signal);
113-
114-
instanceId = ws.status!.instance!.instanceId;
115-
116-
let ownerToken = '';
117-
let sshkey = '';
118-
let workspaceHost = '';
119-
const phase = WorkspaceInstanceStatus_Phase[ws.status!.instance!.status!.phase ?? WorkspaceInstanceStatus_Phase.UNSPECIFIED].toLowerCase() as WorkspacePhase;
120-
// if workspace is not running, we may not compute its url yet
121-
if (phase === 'running') {
122-
ownerToken = await this.sessionService.getAPI().getOwnerToken(actualWorkspaceId, _context.signal);
123-
let workspaceUrl = ws.status!.instance!.status!.url;
124-
const url = new URL(workspaceUrl);
125-
workspaceHost = url.host.substring(url.host.indexOf('.') + 1);
126-
if (workspaceId !== actualWorkspaceId) {
127-
// Public api doesn't take into account "debug" workspaces, readd 'debug-' prefix
128-
workspaceUrl = workspaceUrl.replace(actualWorkspaceId, workspaceId);
129-
}
130-
sshkey = await this.getWorkspaceSSHKey(ownerToken, workspaceUrl, _context.signal);
111+
const rawWorkspace = await this.sessionService.getAPI().getWorkspace(actualWorkspaceId, _context.signal);
112+
const wsData = rawWorkspaceToWorkspaceData(rawWorkspace);
113+
114+
// Report if we couldn't parse contextUrl
115+
if (!wsData.contextUrl) {
116+
this.telemetryService.sendTelemetryException(new Error('Unable to parse workspace contextUrl'), {
117+
gitpodHost: request.gitpodHost,
118+
workspaceId: request.workspaceId,
119+
instanceId,
120+
userId,
121+
contextUrl: rawWorkspace.context?.contextUrl,
122+
});
123+
}
124+
125+
const ownerToken = await this.sessionService.getAPI().getOwnerToken(actualWorkspaceId, _context.signal);
126+
127+
instanceId = rawWorkspace.status!.instance!.instanceId;
128+
129+
const workspaceUrl = new URL(wsData.workspaceUrl);
130+
const workspaceHost = workspaceUrl.host.substring(workspaceUrl.host.indexOf('.') + 1);
131+
let actualWorkspaceUrl = wsData.workspaceUrl;
132+
if (workspaceId !== actualWorkspaceId) {
133+
// Public api doesn't take into account "debug" workspaces, readd 'debug-' prefix
134+
actualWorkspaceUrl = actualWorkspaceUrl.replace(actualWorkspaceId, workspaceId);
131135
}
136+
137+
const sshkey = wsData.phase === 'running' ? (await this.getWorkspaceSSHKey(ownerToken, actualWorkspaceUrl, _context.signal)) : '';
138+
132139
return {
133140
gitpodHost,
134141
userId,
@@ -137,7 +144,7 @@ class ExtensionServiceImpl implements ExtensionServiceImplementation {
137144
workspaceHost,
138145
ownerToken,
139146
sshkey,
140-
phase,
147+
phase: wsData.phase,
141148
};
142149
} catch (e) {
143150
let code = Status.INTERNAL;

src/publicApi.ts

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -295,29 +295,34 @@ export interface WorkspaceData {
295295
owner: string;
296296
repo: string;
297297
id: string;
298-
contextUrl: string;
298+
contextUrl: string | undefined;
299299
workspaceUrl: string;
300300
phase: WorkspacePhase;
301301
description: string;
302302
lastUsed: Date;
303-
recentFolders : string[];
303+
recentFolders: string[];
304304
}
305305

306306
export function rawWorkspaceToWorkspaceData(rawWorkspaces: Workspace): WorkspaceData;
307307
export function rawWorkspaceToWorkspaceData(rawWorkspaces: Workspace[]): WorkspaceData[];
308308
export function rawWorkspaceToWorkspaceData(rawWorkspaces: Workspace | Workspace[]) {
309309
const toWorkspaceData = (ws: Workspace) => {
310-
const url = new URL(ws.context!.contextUrl);
311-
const provider = url.host.replace(/\..+?$/, ''); // remove '.com', etc
312-
const matches = url.pathname.match(/[^/]+/g)!; // match /owner/repo
310+
const normalizedUrl = getNormalizedURL(ws.context!.contextUrl);
311+
let provider = 'undefined';
312+
let matches = ['undefined', 'undefined'];
313+
if (normalizedUrl) {
314+
const url = new URL(normalizedUrl);
315+
provider = url.host.replace(/\..+?$/, ''); // remove '.com', etc
316+
matches = url.pathname.match(/[^/]+/g)!; // match /owner/repo
317+
}
313318
const owner = matches[0];
314319
const repo = matches[1];
315320
return {
316321
provider,
317322
owner,
318323
repo,
319324
id: ws.workspaceId,
320-
contextUrl: ws.context!.contextUrl,
325+
contextUrl: normalizedUrl,
321326
workspaceUrl: ws.status!.instance!.status!.url,
322327
phase: WorkspaceInstanceStatus_Phase[ws.status!.instance!.status!.phase ?? WorkspaceInstanceStatus_Phase.UNSPECIFIED].toLowerCase() as WorkspacePhase,
323328
description: ws.description,
@@ -333,3 +338,24 @@ export function rawWorkspaceToWorkspaceData(rawWorkspaces: Workspace | Workspace
333338

334339
return toWorkspaceData(rawWorkspaces);
335340
}
341+
342+
// TODO: remove this once public api is fixed, ref https://github.com/gitpod-io/gitpod/pull/18292
343+
function getNormalizedURL(contextUrl: string | undefined): string | undefined {
344+
if (!contextUrl) {
345+
return
346+
}
347+
348+
const idx = contextUrl.search(/http[s]?:\/\//);
349+
let normalized = contextUrl;
350+
if (idx > 0) {
351+
normalized = contextUrl.substring(idx);
352+
}
353+
354+
try {
355+
new URL(normalized);
356+
return normalized;
357+
} catch {
358+
}
359+
360+
return undefined
361+
}

src/workspacesExplorerView.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ export class WorkspacesExplorerView extends Disposable implements vscode.TreeDat
121121
ws.owner,
122122
ws.repo,
123123
ws.id,
124-
ws.contextUrl,
124+
ws.contextUrl ?? 'undefined',
125125
ws.phase === 'running',
126126
ws.description,
127127
ws.lastUsed

0 commit comments

Comments
 (0)