@gitpod/gitpod-protocol 0.1.5-wth-test.41 → 0.1.5-wth-test.80

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/data/gitpod-schema.json +18 -3
  2. package/lib/admin-protocol.d.ts +12 -1
  3. package/lib/admin-protocol.d.ts.map +1 -1
  4. package/lib/admin-protocol.js.map +1 -1
  5. package/lib/analytics.d.ts +4 -5
  6. package/lib/analytics.d.ts.map +1 -1
  7. package/lib/context-url.d.ts +18 -5
  8. package/lib/context-url.d.ts.map +1 -1
  9. package/lib/context-url.js +58 -5
  10. package/lib/context-url.js.map +1 -1
  11. package/lib/context-url.spec.d.ts +2 -0
  12. package/lib/context-url.spec.d.ts.map +1 -1
  13. package/lib/context-url.spec.js +25 -4
  14. package/lib/context-url.spec.js.map +1 -1
  15. package/lib/gitpod-service.d.ts +33 -6
  16. package/lib/gitpod-service.d.ts.map +1 -1
  17. package/lib/gitpod-service.js +4 -2
  18. package/lib/gitpod-service.js.map +1 -1
  19. package/lib/ide-protocol.d.ts +105 -0
  20. package/lib/ide-protocol.d.ts.map +1 -0
  21. package/lib/ide-protocol.js +8 -0
  22. package/lib/ide-protocol.js.map +1 -0
  23. package/lib/index.d.ts +2 -0
  24. package/lib/index.d.ts.map +1 -1
  25. package/lib/index.js +2 -0
  26. package/lib/index.js.map +1 -1
  27. package/lib/installation-admin-protocol.d.ts +27 -0
  28. package/lib/installation-admin-protocol.d.ts.map +1 -0
  29. package/lib/installation-admin-protocol.js +30 -0
  30. package/lib/installation-admin-protocol.js.map +1 -0
  31. package/lib/messaging/error.d.ts +1 -0
  32. package/lib/messaging/error.d.ts.map +1 -1
  33. package/lib/messaging/error.js +2 -0
  34. package/lib/messaging/error.js.map +1 -1
  35. package/lib/messaging/node/connection.d.ts +1 -17
  36. package/lib/messaging/node/connection.d.ts.map +1 -1
  37. package/lib/messaging/node/connection.js +21 -57
  38. package/lib/messaging/node/connection.js.map +1 -1
  39. package/lib/oss-allowlist.d.ts +14 -0
  40. package/lib/oss-allowlist.d.ts.map +1 -0
  41. package/lib/oss-allowlist.js +8 -0
  42. package/lib/oss-allowlist.js.map +1 -0
  43. package/lib/permission.d.ts +7 -1
  44. package/lib/permission.d.ts.map +1 -1
  45. package/lib/permission.js +24 -4
  46. package/lib/permission.js.map +1 -1
  47. package/lib/protocol.d.ts +28 -40
  48. package/lib/protocol.d.ts.map +1 -1
  49. package/lib/protocol.js +16 -4
  50. package/lib/protocol.js.map +1 -1
  51. package/lib/teams-projects-protocol.d.ts +10 -0
  52. package/lib/teams-projects-protocol.d.ts.map +1 -1
  53. package/lib/teams-projects-protocol.js +7 -0
  54. package/lib/teams-projects-protocol.js.map +1 -1
  55. package/lib/util/analytics.js +12 -3
  56. package/lib/util/analytics.js.map +1 -1
  57. package/lib/util/garbage-collected-cache.d.ts +1 -0
  58. package/lib/util/garbage-collected-cache.d.ts.map +1 -1
  59. package/lib/util/garbage-collected-cache.js +5 -1
  60. package/lib/util/garbage-collected-cache.js.map +1 -1
  61. package/lib/util/generate-workspace-id.d.ts +1 -1
  62. package/lib/util/generate-workspace-id.d.ts.map +1 -1
  63. package/lib/util/generate-workspace-id.js +19 -2
  64. package/lib/util/generate-workspace-id.js.map +1 -1
  65. package/lib/util/generate-workspace-id.spec.js +24 -0
  66. package/lib/util/generate-workspace-id.spec.js.map +1 -1
  67. package/lib/util/gitpod-host-url.d.ts +0 -1
  68. package/lib/util/gitpod-host-url.d.ts.map +1 -1
  69. package/lib/util/gitpod-host-url.js +3 -6
  70. package/lib/util/gitpod-host-url.js.map +1 -1
  71. package/lib/util/jaeger-client-types.d.ts +68 -0
  72. package/lib/util/jaeger-client-types.d.ts.map +1 -0
  73. package/lib/util/jaeger-client-types.js +8 -0
  74. package/lib/util/jaeger-client-types.js.map +1 -0
  75. package/lib/util/parse-workspace-id.js +1 -1
  76. package/lib/util/parse-workspace-id.js.map +1 -1
  77. package/lib/util/repeat.d.ts +15 -0
  78. package/lib/util/repeat.d.ts.map +1 -0
  79. package/lib/util/repeat.js +55 -0
  80. package/lib/util/repeat.js.map +1 -0
  81. package/lib/util/tracing.d.ts +51 -5
  82. package/lib/util/tracing.d.ts.map +1 -1
  83. package/lib/util/tracing.js +156 -17
  84. package/lib/util/tracing.js.map +1 -1
  85. package/lib/util/tracing.spec.d.ts +7 -0
  86. package/lib/util/tracing.spec.d.ts.map +1 -0
  87. package/lib/util/tracing.spec.js +121 -0
  88. package/lib/util/tracing.spec.js.map +1 -0
  89. package/lib/workspace-cluster.d.ts +9 -7
  90. package/lib/workspace-cluster.d.ts.map +1 -1
  91. package/lib/workspace-cluster.js +18 -1
  92. package/lib/workspace-cluster.js.map +1 -1
  93. package/lib/workspace-instance.d.ts +19 -0
  94. package/lib/workspace-instance.d.ts.map +1 -1
  95. package/package.json +5 -3
  96. package/pkg-yarn.lock +2 -2
  97. package/provenance-bundle.jsonl +2 -0
  98. package/src/admin-protocol.ts +19 -5
  99. package/src/analytics.ts +4 -6
  100. package/src/context-url.spec.ts +18 -4
  101. package/src/context-url.ts +62 -6
  102. package/src/gitpod-service.ts +41 -10
  103. package/src/ide-frontend-service.ts +1 -1
  104. package/src/ide-protocol.ts +119 -0
  105. package/src/index.ts +2 -0
  106. package/src/installation-admin-protocol.ts +42 -0
  107. package/src/messaging/error.ts +3 -0
  108. package/src/messaging/node/connection.ts +21 -68
  109. package/src/oss-allowlist.ts +15 -0
  110. package/src/permission.ts +22 -3
  111. package/src/protocol.ts +45 -44
  112. package/src/teams-projects-protocol.ts +16 -1
  113. package/src/util/analytics.ts +21 -3
  114. package/src/util/garbage-collected-cache.ts +7 -1
  115. package/src/util/generate-workspace-id.spec.ts +17 -0
  116. package/src/util/generate-workspace-id.ts +20 -2
  117. package/src/util/gitpod-host-url.ts +4 -8
  118. package/src/util/jaeger-client-types.ts +102 -0
  119. package/src/util/parse-workspace-id.ts +1 -1
  120. package/src/util/repeat.ts +45 -0
  121. package/src/util/tracing.spec.ts +83 -0
  122. package/src/util/tracing.ts +183 -17
  123. package/src/workspace-cluster.ts +17 -9
  124. package/src/workspace-instance.ts +20 -0
  125. package/lib/messaging/connection-error-handler.d.ts +0 -27
  126. package/lib/messaging/connection-error-handler.d.ts.map +0 -1
  127. package/lib/messaging/connection-error-handler.js +0 -34
  128. package/lib/messaging/connection-error-handler.js.map +0 -1
  129. package/lib/util/repeater.d.ts +0 -22
  130. package/lib/util/repeater.d.ts.map +0 -1
  131. package/lib/util/repeater.js +0 -65
  132. package/lib/util/repeater.js.map +0 -1
  133. package/lib/util/safe-promise.d.ts +0 -11
  134. package/lib/util/safe-promise.d.ts.map +0 -1
  135. package/lib/util/safe-promise.js +0 -31
  136. package/lib/util/safe-promise.js.map +0 -1
  137. package/src/messaging/connection-error-handler.ts +0 -62
  138. package/src/util/jaeger-client.d.ts +0 -105
  139. package/src/util/repeater.ts +0 -49
  140. package/src/util/safe-promise.ts +0 -26
@@ -4,10 +4,62 @@
4
4
  * See License-AGPL.txt in the project root for license information.
5
5
  */
6
6
 
7
+ import { Workspace } from ".";
8
+
9
+ /**
10
+ * The whole point of these methods is to overcome inconsistencies in our data model.
11
+ * Ideally we remove it at some point once we fixed our model, as it:
12
+ * - duplicates logic
13
+ * - but additional burden on clients (using this, copying this to other languages!)
14
+ *
15
+ * TODO(gpl) See if we can get this into `server` code to remove the burden from clients
16
+ */
7
17
  export namespace ContextURL {
8
18
  export const INCREMENTAL_PREBUILD_PREFIX = "incremental-prebuild";
9
19
  export const PREBUILD_PREFIX = "prebuild";
10
20
  export const IMAGEBUILD_PREFIX = "imagebuild";
21
+ export const SNAPSHOT_PREFIX = "snapshot";
22
+ export const REFERRER_PREFIX = 'referrer:';
23
+
24
+ /**
25
+ * This function will (try to) return the HTTP(S) URL of the context the user originally created this workspace on.
26
+ * Especially it will not contain any modifiers or be of different scheme than HTTP(S).
27
+ *
28
+ * Use this function if you need to provided a _working_ URL to the original context.
29
+ * @param ws
30
+ * @returns
31
+ */
32
+ export function getNormalizedURL(ws: Pick<Workspace, "context" | "contextURL"> | undefined): URL | undefined {
33
+ const normalized = normalize(ws);
34
+ if (!normalized) {
35
+ return undefined;
36
+ }
37
+
38
+ try {
39
+ return new URL(normalized);
40
+ } catch (err) {
41
+ console.error(`unable to parse URL from normalized contextURL: '${normalized}'`, err);
42
+ }
43
+ return undefined;
44
+ }
45
+
46
+ function normalize(ws: Pick<Workspace, "context" | "contextURL"> | undefined): string | undefined {
47
+ if (!ws) {
48
+ return undefined;
49
+ }
50
+ if (ws.context.normalizedContextURL) {
51
+ return ws.context.normalizedContextURL;
52
+ }
53
+
54
+ // fallback: we do not yet set normalizedContextURL on all workspaces, yet, let alone older existing workspaces
55
+ let fallback: string | undefined = undefined;
56
+ try {
57
+ fallback = removePrefixes(ws.contextURL);
58
+ } catch (err) {
59
+ console.error(`unable to remove prefixes from contextURL: '${ws.contextURL}'`, err);
60
+ }
61
+ return fallback;
62
+ }
11
63
 
12
64
  /**
13
65
  * The field "contextUrl" might contain prefixes like:
@@ -15,29 +67,33 @@ export namespace ContextURL {
15
67
  * - prebuild/...
16
68
  * This is the analogon to the (Prefix)ContextParser structure in "server".
17
69
  */
18
- export function parseToURL(contextUrl: string | undefined): URL | undefined {
70
+ function removePrefixes(contextUrl: string | undefined): string | undefined {
19
71
  if (contextUrl === undefined) {
20
72
  return undefined;
21
73
  }
22
74
 
23
75
  const segments = contextUrl.split("/");
24
76
  if (segments.length === 1) {
25
- return new URL(segments[0]); // this might be something, we just try
77
+ return segments[0]; // this might be something, we just try
26
78
  }
27
79
 
28
- const segmentsToURL = (offset: number): URL => {
80
+ const segmentsToURL = (offset: number): string => {
29
81
  let rest = segments.slice(offset).join("/");
82
+ if (/^git@[^:\/]+:/.test(rest)) {
83
+ rest = rest.replace(/^git@([^:\/]+):/, 'https://$1/');
84
+ }
30
85
  if (!rest.startsWith("http")) {
31
86
  rest = 'https://' + rest;
32
87
  }
33
- return new URL(rest);
88
+ return rest;
34
89
  };
35
90
 
36
-
37
91
  const firstSegment = segments[0];
38
92
  if (firstSegment === PREBUILD_PREFIX ||
39
93
  firstSegment === INCREMENTAL_PREBUILD_PREFIX ||
40
- firstSegment === IMAGEBUILD_PREFIX) {
94
+ firstSegment === IMAGEBUILD_PREFIX ||
95
+ firstSegment === SNAPSHOT_PREFIX ||
96
+ firstSegment.startsWith(REFERRER_PREFIX)) {
41
97
  return segmentsToURL(1);
42
98
  }
43
99
 
@@ -6,14 +6,14 @@
6
6
 
7
7
  import {
8
8
  User, WorkspaceInfo, WorkspaceCreationResult, WorkspaceInstanceUser,
9
- WhitelistedRepository, WorkspaceImageBuild, AuthProviderInfo, Branding, CreateWorkspaceMode,
9
+ WhitelistedRepository, WorkspaceImageBuild, AuthProviderInfo, CreateWorkspaceMode,
10
10
  Token, UserEnvVarValue, ResolvePluginsParams, PreparePluginUploadParams, Terms,
11
11
  ResolvedPlugins, Configuration, InstallPluginsParams, UninstallPluginParams, UserInfo, GitpodTokenType,
12
- GitpodToken, AuthProviderEntry, GuessGitTokenScopesParams, GuessedGitTokenScopes
12
+ GitpodToken, AuthProviderEntry, GuessGitTokenScopesParams, GuessedGitTokenScopes, ProjectEnvVar
13
13
  } from './protocol';
14
14
  import {
15
15
  Team, TeamMemberInfo,
16
- TeamMembershipInvite, Project, TeamMemberRole, PrebuildWithStatus, StartPrebuildResult
16
+ TeamMembershipInvite, Project, TeamMemberRole, PrebuildWithStatus, StartPrebuildResult, PartialProject
17
17
  } from './teams-projects-protocol';
18
18
  import { JsonRpcProxy, JsonRpcServer } from './messaging/proxy-factory';
19
19
  import { Disposable, CancellationTokenSource } from 'vscode-jsonrpc';
@@ -29,6 +29,8 @@ import { AccountStatement, CreditAlert } from './accounting-protocol';
29
29
  import { GithubUpgradeURL, PlanCoupon } from './payment-protocol';
30
30
  import { TeamSubscription, TeamSubscriptionSlot, TeamSubscriptionSlotResolved } from './team-subscription-protocol';
31
31
  import { RemotePageMessage, RemoteTrackMessage, RemoteIdentifyMessage } from './analytics';
32
+ import { IDEServer } from './ide-protocol';
33
+ import { InstallationAdminSettings, TelemetryData } from './installation-admin-protocol';
32
34
 
33
35
  export interface GitpodClient {
34
36
  onInstanceUpdate(instance: WorkspaceInstance): void;
@@ -45,7 +47,7 @@ export interface GitpodClient {
45
47
  }
46
48
 
47
49
  export const GitpodServer = Symbol('GitpodServer');
48
- export interface GitpodServer extends JsonRpcServer<GitpodClient>, AdminServer, LicenseService {
50
+ export interface GitpodServer extends JsonRpcServer<GitpodClient>, AdminServer, LicenseService, IDEServer {
49
51
  // User related API
50
52
  getLoggedInUser(): Promise<User>;
51
53
  getTerms(): Promise<Terms>;
@@ -54,7 +56,6 @@ export interface GitpodServer extends JsonRpcServer<GitpodClient>, AdminServer,
54
56
  getOwnAuthProviders(): Promise<AuthProviderEntry[]>;
55
57
  updateOwnAuthProvider(params: GitpodServer.UpdateOwnAuthProviderParams): Promise<AuthProviderEntry>;
56
58
  deleteOwnAuthProvider(params: GitpodServer.DeleteOwnAuthProviderParams): Promise<void>;
57
- getBranding(): Promise<Branding>;
58
59
  getConfiguration(): Promise<Configuration>;
59
60
  getToken(query: GitpodServer.GetTokenSearchOptions): Promise<Token | undefined>;
60
61
  getGitpodTokenScopes(tokenHash: string): Promise<string[]>;
@@ -71,8 +72,15 @@ export interface GitpodServer extends JsonRpcServer<GitpodClient>, AdminServer,
71
72
  getWorkspaceOwner(workspaceId: string): Promise<UserInfo | undefined>;
72
73
  getWorkspaceUsers(workspaceId: string): Promise<WorkspaceInstanceUser[]>;
73
74
  getFeaturedRepositories(): Promise<WhitelistedRepository[]>;
75
+ getSuggestedContextURLs(): Promise<string[]>;
76
+ /**
77
+ * **Security:**
78
+ * Sensitive information like an owner token is erased, since it allows access for all team members.
79
+ * If you need to access an owner token use `getOwnerToken` instead.
80
+ */
74
81
  getWorkspace(id: string): Promise<WorkspaceInfo>;
75
82
  isWorkspaceOwner(workspaceId: string): Promise<boolean>;
83
+ getOwnerToken(workspaceId: string): Promise<string>;
76
84
 
77
85
  /**
78
86
  * Creates and starts a workspace for the given context URL.
@@ -125,6 +133,11 @@ export interface GitpodServer extends JsonRpcServer<GitpodClient>, AdminServer,
125
133
  resetGenericInvite(inviteId: string): Promise<TeamMembershipInvite>;
126
134
  deleteTeam(teamId: string, userId: string): Promise<void>;
127
135
 
136
+ // Admin Settings
137
+ adminGetSettings(): Promise<InstallationAdminSettings>;
138
+ adminUpdateSettings(settings: InstallationAdminSettings): Promise<void>;
139
+ adminGetTelemetryData(): Promise<TelemetryData>;
140
+
128
141
  // Projects
129
142
  getProviderRepositoriesForUser(params: GetProviderRepositoriesParams): Promise<ProviderRepository[]>;
130
143
  createProject(params: CreateProjectParams): Promise<Project>;
@@ -135,9 +148,15 @@ export interface GitpodServer extends JsonRpcServer<GitpodClient>, AdminServer,
135
148
  findPrebuilds(params: FindPrebuildsParams): Promise<PrebuildWithStatus[]>;
136
149
  triggerPrebuild(projectId: string, branchName: string | null): Promise<StartPrebuildResult>;
137
150
  cancelPrebuild(projectId: string, prebuildId: string): Promise<void>;
138
- setProjectConfiguration(projectId: string, configString: string): Promise<void>;
139
151
  fetchProjectRepositoryConfiguration(projectId: string): Promise<string | undefined>;
140
152
  guessProjectConfiguration(projectId: string): Promise<string | undefined>;
153
+ fetchRepositoryConfiguration(cloneUrl: string): Promise<string | undefined>;
154
+ guessRepositoryConfiguration(cloneUrl: string): Promise<string | undefined>;
155
+ setProjectConfiguration(projectId: string, configString: string): Promise<void>;
156
+ updateProjectPartial(partialProject: PartialProject): Promise<void>;
157
+ setProjectEnvironmentVariable(projectId: string, name: string, value: string, censored: boolean): Promise<void>;
158
+ getProjectEnvironmentVariables(projectId: string): Promise<ProjectEnvVar[]>;
159
+ deleteProjectEnvironmentVariable(variableId: string): Promise<void>;
141
160
 
142
161
  // content service
143
162
  getContentBlobUploadUrl(name: string): Promise<string>
@@ -235,6 +254,16 @@ export interface GitpodServer extends JsonRpcServer<GitpodClient>, AdminServer,
235
254
  identifyUser(event: RemoteIdentifyMessage): Promise<void>;
236
255
  }
237
256
 
257
+ export interface RateLimiterError {
258
+ method?: string,
259
+
260
+ /**
261
+ * Retry after this many seconds, earliest.
262
+ * cmp.: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After
263
+ */
264
+ retryAfter: number,
265
+ }
266
+
238
267
  export interface CreateProjectParams {
239
268
  name: string;
240
269
  slug?: string;
@@ -267,7 +296,7 @@ export interface ProviderRepository {
267
296
  installationId?: number;
268
297
  installationUpdatedAt?: string;
269
298
 
270
- inUse?: boolean;
299
+ inUse?: { userName: string };
271
300
  }
272
301
 
273
302
  export interface ClientHeaderFields {
@@ -380,10 +409,12 @@ export class GitpodCompositeClient<Client extends GitpodClient> implements Gitpo
380
409
 
381
410
  public registerClient(client: Partial<Client>): Disposable {
382
411
  this.clients.push(client);
383
- const index = this.clients.length;
384
412
  return {
385
413
  dispose: () => {
386
- this.clients.slice(index, 1);
414
+ const index = this.clients.indexOf(client);
415
+ if (index > -1) {
416
+ this.clients.splice(index, 1);
417
+ }
387
418
  }
388
419
  }
389
420
  }
@@ -573,7 +604,7 @@ export class WorkspaceInstanceUpdateListener {
573
604
  }
574
605
 
575
606
  export interface GitpodServiceOptions {
576
- onReconnect?: () => (void | Promise<void>)
607
+ onReconnect?: () => (void | Promise<void>)
577
608
  }
578
609
 
579
610
  export class GitpodServiceImpl<Client extends GitpodClient, Server extends GitpodServer> {
@@ -7,7 +7,7 @@
7
7
  import { Event } from "./util/event";
8
8
  import { Disposable } from "./util/disposable";
9
9
 
10
- export type IDEFrontendState = 'init' | 'ready' | 'terminated';
10
+ export type IDEFrontendState = 'init' | 'ready' | 'terminated';
11
11
 
12
12
  export interface IDEFrontendService {
13
13
  readonly state: IDEFrontendState;
@@ -0,0 +1,119 @@
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
+ /**
8
+ * `IDEServer` provides a list of available IDEs.
9
+ */
10
+ export interface IDEServer {
11
+ /**
12
+ * Returns the IDE preferences.
13
+ */
14
+ getIDEOptions(): Promise<IDEOptions>;
15
+ }
16
+
17
+ export interface IDEOptions {
18
+ /**
19
+ * A list of available IDEs.
20
+ */
21
+ options: { [key: string]: IDEOption };
22
+
23
+ /**
24
+ * The default (browser) IDE when the user has not specified one.
25
+ */
26
+ defaultIde: string;
27
+
28
+ /**
29
+ * The default desktop IDE when the user has not specified one.
30
+ */
31
+ defaultDesktopIde: string;
32
+
33
+ /**
34
+ * Client specific IDE options.
35
+ */
36
+ clients?: { [id: string]: IDEClient };
37
+ }
38
+
39
+ export interface IDEClient {
40
+ /**
41
+ * The default desktop IDE when the user has not specified one.
42
+ */
43
+ defaultDesktopIDE?: string;
44
+
45
+ /**
46
+ * Desktop IDEs supported by the client.
47
+ */
48
+ desktopIDEs?: string[]
49
+
50
+ /**
51
+ * Steps to install the client on user machine.
52
+ */
53
+ installationSteps?: string[]
54
+ }
55
+
56
+ export interface IDEOption {
57
+ /**
58
+ * To ensure a stable order one can set an `orderKey`.
59
+ */
60
+ orderKey?: string;
61
+
62
+ /**
63
+ * Human readable title text of the IDE (plain text only).
64
+ */
65
+ title: string;
66
+
67
+ /**
68
+ * The type of the IDE, currently 'browser' or 'desktop'.
69
+ */
70
+ type: 'browser' | 'desktop';
71
+
72
+ /**
73
+ * The logo for the IDE. That could be a key in (see
74
+ * components/dashboard/src/images/ideLogos.ts) or a URL.
75
+ */
76
+ logo: string;
77
+
78
+ /**
79
+ * Text of an optional tooltip (plain text only).
80
+ */
81
+ tooltip?: string;
82
+
83
+ /**
84
+ * Text of an optional label next to the IDE option like “Insiders” (plain
85
+ * text only).
86
+ */
87
+ label?: string;
88
+
89
+ /**
90
+ * Notes to the IDE option that are renderd in the preferences when a user
91
+ * chooses this IDE.
92
+ */
93
+ notes?: string[];
94
+
95
+ /**
96
+ * If `true` this IDE option is not visible in the IDE preferences.
97
+ */
98
+ hidden?: boolean;
99
+
100
+ /**
101
+ * The image ref to the IDE image.
102
+ */
103
+ image: string;
104
+
105
+ /**
106
+ * The latest image ref to the IDE image, this image ref always resolve to digest.
107
+ */
108
+ latestImage?: string;
109
+
110
+ /**
111
+ * When this is `true`, the tag of this image is resolved to the latest
112
+ * image digest regularly.
113
+ *
114
+ * This is useful if this image points to a tag like `nightly` that will be
115
+ * updated regularly. When `resolveImageDigest` is `true`, we make sure that
116
+ * we resolve the tag regularly to the most recent image version.
117
+ */
118
+ resolveImageDigest?: boolean;
119
+ }
package/src/index.ts CHANGED
@@ -18,3 +18,5 @@ export * from './headless-workspace-log';
18
18
  export * from './context-url';
19
19
  export * from './teams-projects-protocol';
20
20
  export * from './snapshot-url';
21
+ export * from './oss-allowlist';
22
+ export * from './installation-admin-protocol';
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Copyright (c) 2022 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 { v4 as uuidv4 } from 'uuid';
8
+
9
+ const InstallationAdminSettingsPrototype = {
10
+ sendTelemetry: true
11
+ }
12
+
13
+ export type InstallationAdminSettings = typeof InstallationAdminSettingsPrototype;
14
+
15
+ export namespace InstallationAdminSettings {
16
+ export function fields(): (keyof InstallationAdminSettings)[] {
17
+ return Object.keys(InstallationAdminSettingsPrototype) as (keyof InstallationAdminSettings)[];
18
+ }
19
+ }
20
+
21
+ export interface InstallationAdmin {
22
+ id: string;
23
+ settings: InstallationAdminSettings;
24
+ }
25
+
26
+ export interface TelemetryData {
27
+ installationAdmin: InstallationAdmin
28
+ totalUsers: number
29
+ totalWorkspaces: number
30
+ totalInstances: number
31
+ }
32
+
33
+ export namespace InstallationAdmin {
34
+ export function createDefault(): InstallationAdmin {
35
+ return {
36
+ id: uuidv4(),
37
+ settings: {
38
+ ...InstallationAdminSettingsPrototype,
39
+ }
40
+ };
41
+ }
42
+ }
@@ -78,4 +78,7 @@ export namespace ErrorCodes {
78
78
 
79
79
  // 630 Snapshot Error
80
80
  export const SNAPSHOT_ERROR = 630;
81
+
82
+ // 640 Headless logs are not available (yet)
83
+ export const HEADLESS_LOG_NOT_YET_AVAILABLE = 640;
81
84
  }
@@ -6,81 +6,34 @@
6
6
  */
7
7
 
8
8
  import * as ws from "ws";
9
- import * as http from "http";
10
- import * as https from "https";
11
- import * as url from "url";
12
- import * as net from "net";
13
- import { MessageConnection } from "vscode-jsonrpc";
14
- import { createWebSocketConnection, IWebSocket } from "vscode-ws-jsonrpc";
15
- import { log } from '../../util/logging';
9
+ import { IWebSocket } from "vscode-ws-jsonrpc";
16
10
 
17
- export interface IServerOptions {
18
- readonly server: http.Server | https.Server;
19
- readonly path?: string;
20
- matches?(request: http.IncomingMessage): boolean;
21
- }
22
-
23
- export function createServerWebSocketConnection(options: IServerOptions, onConnect: (connection: MessageConnection) => void): void {
24
- openJsonRpcSocket(options, socket => {
25
- onConnect(createWebSocketConnection(socket, console));
26
- });
27
- }
28
-
29
- export function openJsonRpcSocket(options: IServerOptions, onOpen: (socket: IWebSocket) => void): void {
30
- openSocket(options, socket => {
31
- const webSocket = toIWebSocket(socket);
32
- onOpen(webSocket);
33
- });
34
- }
35
-
36
- export interface OnOpen {
37
- (webSocket: ws, request: http.IncomingMessage, socket: net.Socket, head: Buffer): void;
38
- }
39
-
40
- export function openSocket(options: IServerOptions, onOpen: OnOpen): void {
41
- const wss = new ws.Server({
42
- noServer: true,
43
- perMessageDeflate: {
44
- // don't compress if a message is less than 256kb
45
- threshold: 256 * 1024
46
- }
47
- });
48
- options.server.on('upgrade', (request: http.IncomingMessage, socket: net.Socket, head: Buffer) => {
49
- const pathname = request.url ? url.parse(request.url).pathname : undefined;
50
- if (options.path && pathname === options.path || options.matches && options.matches(request)) {
51
- wss.handleUpgrade(request, socket, head, webSocket => {
52
- if (webSocket.readyState === webSocket.OPEN) {
53
- onOpen(webSocket, request, socket, head);
54
- } else {
55
- webSocket.on('open', () => onOpen(webSocket, request, socket, head));
56
- }
57
- });
58
- }
59
- });
60
- }
61
-
62
- export function toIWebSocket(webSocket: ws) {
63
- let sendsAfterOpen = 0;
11
+ export function toIWebSocket(ws: ws) {
64
12
  return <IWebSocket>{
65
13
  send: content => {
66
- if (webSocket.readyState !== ws.OPEN) {
67
- if (sendsAfterOpen++ > 3) {
68
- //log.debug(`Repeated try to send on closed web socket (readyState was ${webSocket.readyState})`, { ws });
69
- }
14
+ if (ws.readyState >= ws.CLOSING) {
15
+ // ws is already CLOSING/CLOSED, send() would just return an error.
70
16
  return;
71
17
  }
72
- webSocket.send(content, err => {
73
- if (err) {
74
- log.error('error in ws.send()', err, { ws });
75
- }
76
- })
18
+
19
+ // in general send-errors should trigger an 'error' event already, we just make sure it actually happens.
20
+ try {
21
+ ws.send(content, err => {
22
+ if (!err) {
23
+ return;
24
+ }
25
+ ws.emit('error', err);
26
+ });
27
+ } catch (err) {
28
+ ws.emit('error', err);
29
+ }
77
30
  },
78
- onMessage: cb => webSocket.on('message', cb),
79
- onError: cb => webSocket.on('error', cb),
80
- onClose: cb => webSocket.on('close', cb),
31
+ onMessage: cb => ws.on('message', cb),
32
+ onError: cb => ws.on('error', cb),
33
+ onClose: cb => ws.on('close', cb),
81
34
  dispose: () => {
82
- if (webSocket.readyState < ws.CLOSING) {
83
- webSocket.close();
35
+ if (ws.readyState < ws.CLOSING) {
36
+ ws.close();
84
37
  }
85
38
  }
86
39
  };
@@ -0,0 +1,15 @@
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
+ export interface OssAllowList {
8
+ /**
9
+ * A string that identifies a GitHub/GitLab/Bitbucket identity of the form "<host>/<profilename>"
10
+ * E.g., "github.com/geropl"
11
+ */
12
+ identity: string,
13
+
14
+ deleted?: boolean,
15
+ }
package/src/permission.ts CHANGED
@@ -13,6 +13,7 @@ export const Permissions = {
13
13
  "registry-access": undefined,
14
14
  "admin-users": undefined,
15
15
  "admin-workspaces": undefined,
16
+ "admin-projects": undefined,
16
17
  "admin-api": undefined,
17
18
  "ide-settings": undefined,
18
19
  "new-workspace-cluster": undefined,
@@ -34,6 +35,22 @@ export interface Role {
34
35
  permissions: PermissionName[],
35
36
  }
36
37
 
38
+ export namespace RolesOrPermissions {
39
+ export function toPermissionSet(rolesOrPermissions: RoleOrPermission[] | undefined): Set<PermissionName> {
40
+ rolesOrPermissions = rolesOrPermissions || [];
41
+
42
+ const permissions = new Set<PermissionName>();
43
+ for (const rop of rolesOrPermissions) {
44
+ if (Permission.is(rop)) {
45
+ permissions.add(rop);
46
+ } else if (RoleName.is(rop)) {
47
+ Role.getByName(rop).permissions.forEach(p => permissions.add(p));
48
+ }
49
+ }
50
+ return permissions;
51
+ };
52
+ }
53
+
37
54
  export namespace Permission {
38
55
  /** The permission to monitor the (live) state of a Gitpod installation */
39
56
  export const MONITOR: PermissionName = "monitor";
@@ -50,6 +67,9 @@ export namespace Permission {
50
67
  /** The permission for accessing all workspace data */
51
68
  export const ADMIN_WORKSPACES: PermissionName = "admin-workspaces";
52
69
 
70
+ /** The permission for accessing all projects data */
71
+ export const ADMIN_PROJECTS: PermissionName = "admin-projects";
72
+
53
73
  /** The permission to access the admin API */
54
74
  export const ADMIN_API: PermissionName = "admin-api";
55
75
 
@@ -62,9 +82,7 @@ export namespace Permission {
62
82
  }
63
83
 
64
84
  export const all = (): PermissionName[] => {
65
- return Object.keys(Permission)
66
- .map(k => (Permission as any)[k])
67
- .filter(k => typeof(k) === 'string');
85
+ return Object.keys(Permissions) as PermissionName[];
68
86
  };
69
87
  }
70
88
 
@@ -94,6 +112,7 @@ export namespace Role {
94
112
  permissions: [
95
113
  Permission.ADMIN_USERS,
96
114
  Permission.ADMIN_WORKSPACES,
115
+ Permission.ADMIN_PROJECTS,
97
116
  Permission.ADMIN_API,
98
117
  Permission.ENFORCEMENT,
99
118
  ]