4
4
* See License.AGPL.txt in the project root for license information.
5
5
*/
6
6
7
- import { Timestamp } from "@bufbuild/protobuf" ;
7
+ import { Timestamp , toPlainMessage } from "@bufbuild/protobuf" ;
8
8
import { Code , ConnectError } from "@connectrpc/connect" ;
9
+ import {
10
+ FailedPreconditionDetails ,
11
+ ImageBuildLogsNotYetAvailableError ,
12
+ InvalidCostCenterError as InvalidCostCenterErrorData ,
13
+ InvalidGitpodYMLError as InvalidGitpodYMLErrorData ,
14
+ NeedsVerificationError ,
15
+ PaymentSpendingLimitReachedError ,
16
+ PermissionDeniedDetails ,
17
+ RepositoryNotFoundError as RepositoryNotFoundErrorData ,
18
+ RepositoryUnauthorizedError as RepositoryUnauthorizedErrorData ,
19
+ TooManyRunningWorkspacesError ,
20
+ UserBlockedError ,
21
+ } from "@gitpod/public-api/lib/gitpod/v1/error_pb" ;
9
22
import {
10
23
AuthProvider ,
11
24
AuthProviderDescription ,
@@ -50,7 +63,13 @@ import {
50
63
PrebuildPhase ,
51
64
PrebuildPhase_Phase ,
52
65
} from "@gitpod/public-api/lib/gitpod/v1/prebuild_pb" ;
53
- import { ApplicationError , ErrorCode , ErrorCodes } from "./messaging/error" ;
66
+ import {
67
+ ApplicationError ,
68
+ ErrorCodes ,
69
+ InvalidGitpodYMLError ,
70
+ RepositoryNotFoundError ,
71
+ UnauthorizedRepositoryAccessError ,
72
+ } from "./messaging/error" ;
54
73
import {
55
74
AuthProviderEntry as AuthProviderProtocol ,
56
75
AuthProviderInfo ,
@@ -74,7 +93,6 @@ import {
74
93
Project ,
75
94
Organization as ProtocolOrganization ,
76
95
} from "./teams-projects-protocol" ;
77
- import { TrustedValue } from "./util/scrubbing" ;
78
96
import {
79
97
ConfigurationIdeConfig ,
80
98
PortProtocol ,
@@ -84,9 +102,6 @@ import {
84
102
} from "./workspace-instance" ;
85
103
import { Author , Commit } from "@gitpod/public-api/lib/gitpod/v1/scm_pb" ;
86
104
87
- const applicationErrorCode = "application-error-code" ;
88
- const applicationErrorData = "application-error-data" ;
89
-
90
105
/**
91
106
* Converter between gRPC and JSON-RPC types.
92
107
*
@@ -191,57 +206,240 @@ export class PublicAPIConverter {
191
206
return reason ;
192
207
}
193
208
if ( reason instanceof ApplicationError ) {
194
- const metadata : HeadersInit = { } ;
195
- metadata [ applicationErrorCode ] = String ( reason . code ) ;
196
- if ( reason . data ) {
197
- metadata [ applicationErrorData ] = JSON . stringify ( reason . data ) ;
198
- }
199
209
if ( reason . code === ErrorCodes . NOT_FOUND ) {
200
- return new ConnectError ( reason . message , Code . NotFound , metadata , undefined , reason ) ;
210
+ return new ConnectError ( reason . message , Code . NotFound , undefined , undefined , reason ) ;
201
211
}
202
212
if ( reason . code === ErrorCodes . NOT_AUTHENTICATED ) {
203
- return new ConnectError ( reason . message , Code . Unauthenticated , metadata , undefined , reason ) ;
213
+ return new ConnectError ( reason . message , Code . Unauthenticated , undefined , undefined , reason ) ;
214
+ }
215
+ if ( reason . code === ErrorCodes . USER_BLOCKED ) {
216
+ return new ConnectError (
217
+ reason . message ,
218
+ Code . PermissionDenied ,
219
+ undefined ,
220
+ [
221
+ new PermissionDeniedDetails ( {
222
+ reason : {
223
+ case : "userBlocked" ,
224
+ value : new UserBlockedError ( ) ,
225
+ } ,
226
+ } ) ,
227
+ ] ,
228
+ reason ,
229
+ ) ;
230
+ }
231
+ if ( reason . code === ErrorCodes . NEEDS_VERIFICATION ) {
232
+ return new ConnectError (
233
+ reason . message ,
234
+ Code . PermissionDenied ,
235
+ undefined ,
236
+ [
237
+ new PermissionDeniedDetails ( {
238
+ reason : {
239
+ case : "needsVerification" ,
240
+ value : new NeedsVerificationError ( ) ,
241
+ } ,
242
+ } ) ,
243
+ ] ,
244
+ reason ,
245
+ ) ;
204
246
}
205
- if ( reason . code === ErrorCodes . PERMISSION_DENIED || reason . code === ErrorCodes . USER_BLOCKED ) {
206
- return new ConnectError ( reason . message , Code . PermissionDenied , metadata , undefined , reason ) ;
247
+ if ( reason . code === ErrorCodes . PERMISSION_DENIED ) {
248
+ return new ConnectError ( reason . message , Code . PermissionDenied , undefined , undefined , reason ) ;
207
249
}
208
250
if ( reason . code === ErrorCodes . CONFLICT ) {
209
- return new ConnectError ( reason . message , Code . AlreadyExists , metadata , undefined , reason ) ;
251
+ return new ConnectError ( reason . message , Code . AlreadyExists , undefined , undefined , reason ) ;
252
+ }
253
+ if ( reason instanceof InvalidGitpodYMLError ) {
254
+ return new ConnectError (
255
+ reason . message ,
256
+ Code . FailedPrecondition ,
257
+ undefined ,
258
+ [
259
+ new FailedPreconditionDetails ( {
260
+ reason : {
261
+ case : "invalidGitpodYml" ,
262
+ value : new InvalidGitpodYMLErrorData ( reason . info ) ,
263
+ } ,
264
+ } ) ,
265
+ ] ,
266
+ reason ,
267
+ ) ;
268
+ }
269
+ if ( reason instanceof RepositoryNotFoundError ) {
270
+ return new ConnectError (
271
+ reason . message ,
272
+ Code . FailedPrecondition ,
273
+ undefined ,
274
+ [
275
+ new FailedPreconditionDetails ( {
276
+ reason : {
277
+ case : "repositoryNotFound" ,
278
+ value : new RepositoryNotFoundErrorData ( reason . info ) ,
279
+ } ,
280
+ } ) ,
281
+ ] ,
282
+ reason ,
283
+ ) ;
284
+ }
285
+ if ( reason instanceof UnauthorizedRepositoryAccessError ) {
286
+ return new ConnectError (
287
+ reason . message ,
288
+ Code . FailedPrecondition ,
289
+ undefined ,
290
+ [
291
+ new FailedPreconditionDetails ( {
292
+ reason : {
293
+ case : "repositoryUnauthorized" ,
294
+ value : new RepositoryUnauthorizedErrorData ( reason . info ) ,
295
+ } ,
296
+ } ) ,
297
+ ] ,
298
+ reason ,
299
+ ) ;
300
+ }
301
+ if ( reason . code === ErrorCodes . PAYMENT_SPENDING_LIMIT_REACHED ) {
302
+ return new ConnectError (
303
+ reason . message ,
304
+ Code . FailedPrecondition ,
305
+ undefined ,
306
+ [
307
+ new FailedPreconditionDetails ( {
308
+ reason : {
309
+ case : "paymentSpendingLimitReached" ,
310
+ value : new PaymentSpendingLimitReachedError ( ) ,
311
+ } ,
312
+ } ) ,
313
+ ] ,
314
+ reason ,
315
+ ) ;
316
+ }
317
+ if ( reason . code === ErrorCodes . INVALID_COST_CENTER ) {
318
+ return new ConnectError (
319
+ reason . message ,
320
+ Code . FailedPrecondition ,
321
+ undefined ,
322
+ [
323
+ new FailedPreconditionDetails ( {
324
+ reason : {
325
+ case : "invalidCostCenter" ,
326
+ value : new InvalidCostCenterErrorData ( {
327
+ attributionId : reason . data . attributionId ,
328
+ } ) ,
329
+ } ,
330
+ } ) ,
331
+ ] ,
332
+ reason ,
333
+ ) ;
334
+ }
335
+ if ( reason . code === ErrorCodes . HEADLESS_LOG_NOT_YET_AVAILABLE ) {
336
+ return new ConnectError (
337
+ reason . message ,
338
+ Code . FailedPrecondition ,
339
+ undefined ,
340
+ [
341
+ new FailedPreconditionDetails ( {
342
+ reason : {
343
+ case : "imageBuildLogsNotYetAvailable" ,
344
+ value : new ImageBuildLogsNotYetAvailableError ( ) ,
345
+ } ,
346
+ } ) ,
347
+ ] ,
348
+ reason ,
349
+ ) ;
350
+ }
351
+ if ( reason . code === ErrorCodes . TOO_MANY_RUNNING_WORKSPACES ) {
352
+ return new ConnectError (
353
+ reason . message ,
354
+ Code . FailedPrecondition ,
355
+ undefined ,
356
+ [
357
+ new FailedPreconditionDetails ( {
358
+ reason : {
359
+ case : "tooManyRunningWorkspaces" ,
360
+ value : new TooManyRunningWorkspacesError ( ) ,
361
+ } ,
362
+ } ) ,
363
+ ] ,
364
+ reason ,
365
+ ) ;
210
366
}
211
367
if ( reason . code === ErrorCodes . PRECONDITION_FAILED ) {
212
- return new ConnectError ( reason . message , Code . FailedPrecondition , metadata , undefined , reason ) ;
368
+ return new ConnectError ( reason . message , Code . FailedPrecondition , undefined , undefined , reason ) ;
213
369
}
214
370
if ( reason . code === ErrorCodes . TOO_MANY_REQUESTS ) {
215
- return new ConnectError ( reason . message , Code . ResourceExhausted , metadata , undefined , reason ) ;
216
- }
217
- if ( reason . code === ErrorCodes . INTERNAL_SERVER_ERROR ) {
218
- return new ConnectError ( reason . message , Code . Internal , metadata , undefined , reason ) ;
371
+ return new ConnectError ( reason . message , Code . ResourceExhausted , undefined , undefined , reason ) ;
219
372
}
220
373
if ( reason . code === ErrorCodes . CANCELLED ) {
221
- return new ConnectError ( reason . message , Code . DeadlineExceeded , metadata , undefined , reason ) ;
374
+ return new ConnectError ( reason . message , Code . Canceled , undefined , undefined , reason ) ;
222
375
}
223
- return new ConnectError ( reason . message , Code . InvalidArgument , metadata , undefined , reason ) ;
376
+ if ( reason . code === ErrorCodes . INTERNAL_SERVER_ERROR ) {
377
+ return new ConnectError ( reason . message , Code . Internal , undefined , undefined , reason ) ;
378
+ }
379
+ return new ConnectError ( reason . message , Code . Unknown , undefined , undefined , reason ) ;
224
380
}
225
381
return ConnectError . from ( reason , Code . Internal ) ;
226
382
}
227
383
228
384
fromError ( reason : ConnectError ) : Error {
229
- const codeMetadata = reason . metadata ?. get ( applicationErrorCode ) ;
230
- if ( ! codeMetadata ) {
231
- return reason ;
232
- }
233
- const code = Number ( codeMetadata ) as ErrorCode ;
234
- const dataMetadata = reason . metadata ?. get ( applicationErrorData ) ;
235
- let data = undefined ;
236
- if ( dataMetadata ) {
237
- try {
238
- data = JSON . parse ( dataMetadata ) ;
239
- } catch ( e ) {
240
- console . error ( "failed to parse application error data" , e ) ;
385
+ if ( reason . code === Code . NotFound ) {
386
+ return new ApplicationError ( ErrorCodes . NOT_FOUND , reason . rawMessage ) ;
387
+ }
388
+ if ( reason . code === Code . Unauthenticated ) {
389
+ return new ApplicationError ( ErrorCodes . NOT_AUTHENTICATED , reason . rawMessage ) ;
390
+ }
391
+ if ( reason . code === Code . PermissionDenied ) {
392
+ const details = reason . findDetails ( PermissionDeniedDetails ) [ 0 ] ;
393
+ switch ( details ?. reason ?. case ) {
394
+ case "userBlocked" :
395
+ return new ApplicationError ( ErrorCodes . USER_BLOCKED , reason . rawMessage ) ;
396
+ case "needsVerification" :
397
+ return new ApplicationError ( ErrorCodes . NEEDS_VERIFICATION , reason . rawMessage ) ;
398
+ }
399
+ return new ApplicationError ( ErrorCodes . PERMISSION_DENIED , reason . rawMessage ) ;
400
+ }
401
+ if ( reason . code === Code . AlreadyExists ) {
402
+ return new ApplicationError ( ErrorCodes . CONFLICT , reason . rawMessage ) ;
403
+ }
404
+ if ( reason . code === Code . FailedPrecondition ) {
405
+ const details = reason . findDetails ( FailedPreconditionDetails ) [ 0 ] ;
406
+ switch ( details ?. reason ?. case ) {
407
+ case "invalidGitpodYml" :
408
+ const invalidGitpodYmlInfo = toPlainMessage ( details . reason . value ) ;
409
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
410
+ return new InvalidGitpodYMLError ( invalidGitpodYmlInfo ) ;
411
+ case "repositoryNotFound" :
412
+ const repositoryNotFoundInfo = toPlainMessage ( details . reason . value ) ;
413
+ return new RepositoryNotFoundError ( repositoryNotFoundInfo ) ;
414
+ case "repositoryUnauthorized" :
415
+ const repositoryUnauthorizedInfo = toPlainMessage ( details . reason . value ) ;
416
+ return new UnauthorizedRepositoryAccessError ( repositoryUnauthorizedInfo ) ;
417
+ case "paymentSpendingLimitReached" :
418
+ return new ApplicationError ( ErrorCodes . PAYMENT_SPENDING_LIMIT_REACHED , reason . rawMessage ) ;
419
+ case "invalidCostCenter" :
420
+ const invalidCostCenterInfo = toPlainMessage ( details . reason . value ) ;
421
+ return new ApplicationError (
422
+ ErrorCodes . INVALID_COST_CENTER ,
423
+ reason . rawMessage ,
424
+ invalidCostCenterInfo ,
425
+ ) ;
426
+ case "imageBuildLogsNotYetAvailable" :
427
+ return new ApplicationError ( ErrorCodes . HEADLESS_LOG_NOT_YET_AVAILABLE , reason . rawMessage ) ;
428
+ case "tooManyRunningWorkspaces" :
429
+ return new ApplicationError ( ErrorCodes . TOO_MANY_RUNNING_WORKSPACES , reason . rawMessage ) ;
241
430
}
431
+ return new ApplicationError ( ErrorCodes . PRECONDITION_FAILED , reason . rawMessage ) ;
432
+ }
433
+ if ( reason . code === Code . ResourceExhausted ) {
434
+ return new ApplicationError ( ErrorCodes . TOO_MANY_REQUESTS , reason . rawMessage ) ;
435
+ }
436
+ if ( reason . code === Code . Canceled ) {
437
+ return new ApplicationError ( ErrorCodes . CANCELLED , reason . rawMessage ) ;
438
+ }
439
+ if ( reason . code === Code . Internal ) {
440
+ return new ApplicationError ( ErrorCodes . INTERNAL_SERVER_ERROR , reason . rawMessage ) ;
242
441
}
243
- // data is trusted here, since it was scrubbed before on the server
244
- return new ApplicationError ( code , reason . message , new TrustedValue ( data ) ) ;
442
+ return new ApplicationError ( ErrorCodes . INTERNAL_SERVER_ERROR , reason . rawMessage ) ;
245
443
}
246
444
247
445
toWorkspaceEnvironmentVariables ( context : WorkspaceContext ) : WorkspaceEnvironmentVariable [ ] {
0 commit comments