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 ) ;
209
+ if ( reason . code === ErrorCodes . USER_BLOCKED ) {
210
+ return new ConnectError (
211
+ reason . message ,
212
+ Code . PermissionDenied ,
213
+ undefined ,
214
+ [
215
+ new PermissionDeniedDetails ( {
216
+ reason : {
217
+ case : "userBlocked" ,
218
+ value : new UserBlockedError ( ) ,
219
+ } ,
220
+ } ) ,
221
+ ] ,
222
+ reason ,
223
+ ) ;
224
+ }
225
+ if ( reason . code === ErrorCodes . NEEDS_VERIFICATION ) {
226
+ return new ConnectError (
227
+ reason . message ,
228
+ Code . PermissionDenied ,
229
+ undefined ,
230
+ [
231
+ new PermissionDeniedDetails ( {
232
+ reason : {
233
+ case : "needsVerification" ,
234
+ value : new NeedsVerificationError ( ) ,
235
+ } ,
236
+ } ) ,
237
+ ] ,
238
+ reason ,
239
+ ) ;
240
+ }
241
+ if ( reason instanceof InvalidGitpodYMLError ) {
242
+ return new ConnectError (
243
+ reason . message ,
244
+ Code . FailedPrecondition ,
245
+ undefined ,
246
+ [
247
+ new FailedPreconditionDetails ( {
248
+ reason : {
249
+ case : "invalidGitpodYml" ,
250
+ value : new InvalidGitpodYMLErrorData ( reason . info ) ,
251
+ } ,
252
+ } ) ,
253
+ ] ,
254
+ reason ,
255
+ ) ;
256
+ }
257
+ if ( reason instanceof RepositoryNotFoundError ) {
258
+ return new ConnectError (
259
+ reason . message ,
260
+ Code . FailedPrecondition ,
261
+ undefined ,
262
+ [
263
+ new FailedPreconditionDetails ( {
264
+ reason : {
265
+ case : "repositoryNotFound" ,
266
+ value : new RepositoryNotFoundErrorData ( reason . info ) ,
267
+ } ,
268
+ } ) ,
269
+ ] ,
270
+ reason ,
271
+ ) ;
272
+ }
273
+ if ( reason instanceof UnauthorizedRepositoryAccessError ) {
274
+ return new ConnectError (
275
+ reason . message ,
276
+ Code . FailedPrecondition ,
277
+ undefined ,
278
+ [
279
+ new FailedPreconditionDetails ( {
280
+ reason : {
281
+ case : "repositoryUnauthorized" ,
282
+ value : new RepositoryUnauthorizedErrorData ( reason . info ) ,
283
+ } ,
284
+ } ) ,
285
+ ] ,
286
+ reason ,
287
+ ) ;
288
+ }
289
+ if ( reason . code === ErrorCodes . PAYMENT_SPENDING_LIMIT_REACHED ) {
290
+ return new ConnectError (
291
+ reason . message ,
292
+ Code . FailedPrecondition ,
293
+ undefined ,
294
+ [
295
+ new FailedPreconditionDetails ( {
296
+ reason : {
297
+ case : "paymentSpendingLimitReached" ,
298
+ value : new PaymentSpendingLimitReachedError ( ) ,
299
+ } ,
300
+ } ) ,
301
+ ] ,
302
+ reason ,
303
+ ) ;
304
+ }
305
+ if ( reason . code === ErrorCodes . INVALID_COST_CENTER ) {
306
+ return new ConnectError (
307
+ reason . message ,
308
+ Code . FailedPrecondition ,
309
+ undefined ,
310
+ [
311
+ new FailedPreconditionDetails ( {
312
+ reason : {
313
+ case : "invalidCostCenter" ,
314
+ value : new InvalidCostCenterErrorData ( {
315
+ attributionId : reason . data . attributionId ,
316
+ } ) ,
317
+ } ,
318
+ } ) ,
319
+ ] ,
320
+ reason ,
321
+ ) ;
322
+ }
323
+ if ( reason . code === ErrorCodes . HEADLESS_LOG_NOT_YET_AVAILABLE ) {
324
+ return new ConnectError (
325
+ reason . message ,
326
+ Code . FailedPrecondition ,
327
+ undefined ,
328
+ [
329
+ new FailedPreconditionDetails ( {
330
+ reason : {
331
+ case : "imageBuildLogsNotYetAvailable" ,
332
+ value : new ImageBuildLogsNotYetAvailableError ( ) ,
333
+ } ,
334
+ } ) ,
335
+ ] ,
336
+ reason ,
337
+ ) ;
338
+ }
339
+ if ( reason . code === ErrorCodes . TOO_MANY_RUNNING_WORKSPACES ) {
340
+ return new ConnectError (
341
+ reason . message ,
342
+ Code . FailedPrecondition ,
343
+ undefined ,
344
+ [
345
+ new FailedPreconditionDetails ( {
346
+ reason : {
347
+ case : "tooManyRunningWorkspaces" ,
348
+ value : new TooManyRunningWorkspacesError ( ) ,
349
+ } ,
350
+ } ) ,
351
+ ] ,
352
+ reason ,
353
+ ) ;
198
354
}
199
355
if ( reason . code === ErrorCodes . NOT_FOUND ) {
200
- return new ConnectError ( reason . message , Code . NotFound , metadata , undefined , reason ) ;
356
+ return new ConnectError ( reason . message , Code . NotFound , undefined , undefined , reason ) ;
201
357
}
202
358
if ( reason . code === ErrorCodes . NOT_AUTHENTICATED ) {
203
- return new ConnectError ( reason . message , Code . Unauthenticated , metadata , undefined , reason ) ;
359
+ return new ConnectError ( reason . message , Code . Unauthenticated , undefined , undefined , reason ) ;
204
360
}
205
- if ( reason . code === ErrorCodes . PERMISSION_DENIED || reason . code === ErrorCodes . USER_BLOCKED ) {
206
- return new ConnectError ( reason . message , Code . PermissionDenied , metadata , undefined , reason ) ;
361
+ if ( reason . code === ErrorCodes . PERMISSION_DENIED ) {
362
+ return new ConnectError ( reason . message , Code . PermissionDenied , undefined , undefined , reason ) ;
207
363
}
208
364
if ( reason . code === ErrorCodes . CONFLICT ) {
209
- return new ConnectError ( reason . message , Code . AlreadyExists , metadata , undefined , reason ) ;
365
+ return new ConnectError ( reason . message , Code . AlreadyExists , undefined , undefined , reason ) ;
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
- fromError ( reason : ConnectError ) : Error {
229
- const codeMetadata = reason . metadata ?. get ( applicationErrorCode ) ;
230
- if ( ! codeMetadata ) {
231
- return reason ;
384
+ fromError ( reason : ConnectError ) : ApplicationError {
385
+ if ( reason . code === Code . NotFound ) {
386
+ return new ApplicationError ( ErrorCodes . NOT_FOUND , reason . rawMessage ) ;
232
387
}
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 ) ;
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