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