diff --git a/packages/parser/package.json b/packages/parser/package.json index 5e2592d6bb..6a74b75836 100644 --- a/packages/parser/package.json +++ b/packages/parser/package.json @@ -60,6 +60,10 @@ "require": "./lib/cjs/schemas/apigwv2.js", "import": "./lib/esm/schemas/apigwv2.js" }, + "./schemas/appsync": { + "require": "./lib/cjs/schemas/appsync.js", + "import": "./lib/esm/schemas/appsync.js" + }, "./schemas/cloudformation-custom-resources": { "require": "./lib/cjs/schemas/cloudformation-custom-resources.js", "import": "./lib/esm/schemas/cloudformation-custom-resources.js" @@ -183,10 +187,7 @@ }, "typesVersions": { "*": { - "types": [ - "./lib/cjs/types/index.d.ts", - "./lib/esm/types/index.d.ts" - ], + "types": ["./lib/cjs/types/index.d.ts", "./lib/esm/types/index.d.ts"], "middleware": [ "./lib/cjs/middleware/parser.d.ts", "./lib/esm/middleware/parser.d.ts" @@ -207,6 +208,10 @@ "./lib/cjs/schemas/apigwv2.d.ts", "./lib/esm/schemas/apigwv2.d.ts" ], + "schemas/appsync": [ + "./lib/cjs/schemas/appsync.d.ts", + "./lib/esm/schemas/appsync.d.ts" + ], "schemas/cloudformation-custom-resources": [ "./lib/cjs/schemas/cloudformation-custom-resources.d.ts", "./lib/esm/schemas/cloudformation-custom-resources.d.ts" @@ -327,9 +332,7 @@ }, "main": "./lib/cjs/index.js", "types": "./lib/cjs/index.d.ts", - "files": [ - "lib" - ], + "files": ["lib"], "repository": { "type": "git", "url": "git+https://github.com/aws-powertools/powertools-lambda-typescript.git" diff --git a/packages/parser/src/schemas/appsync.ts b/packages/parser/src/schemas/appsync.ts new file mode 100644 index 0000000000..c3f5daece4 --- /dev/null +++ b/packages/parser/src/schemas/appsync.ts @@ -0,0 +1,254 @@ +import { z } from 'zod'; + +const AppSyncIamIdentity = z.object({ + accountId: z.string(), + cognitoIdentityPoolId: z.string().nullable(), + cognitoIdentityId: z.string().nullable(), + sourceIp: z.array(z.string()), + username: z.string(), + userArn: z.string(), + cognitoIdentityAuthType: z.string().nullable(), + cognitoIdentityAuthProvider: z.string().nullable(), +}); + +const AppSyncCognitoIdentity = z.object({ + sub: z.string(), + issuer: z.string(), + username: z.string(), + claims: z.any(), + sourceIp: z.array(z.string()), + defaultAuthStrategy: z.string(), + groups: z.array(z.string()).nullable(), +}); + +const AppSyncOidcIdentity = z.object({ + claims: z.any(), + issuer: z.string(), + sub: z.string(), +}); + +const AppSyncLambdaIdentity = z.object({ + resolverContext: z.any(), +}); + +const AppSyncIdentity = z.union([ + AppSyncCognitoIdentity, + AppSyncIamIdentity, + AppSyncOidcIdentity, + AppSyncLambdaIdentity, +]); + +/** + * A zod schema for an AppSync resolver event + * + * @example + * ```json + * { + * "arguments": { + * "id": "1973493" + * }, + * "source": null, + * "identity": { + * "accountId": "012345678901", + * "cognitoIdentityAuthProvider": null, + * "cognitoIdentityAuthType": null, + * "cognitoIdentityId": null, + * "cognitoIdentityPoolId": null, + * "sourceIp": ["10.10.10.10"], + * "userArn": "arn:aws:sts::012345678901:assumed-role/role", + * "username": "AROAXYKJUOW6FHGUSK5FA:username" + * }, + * "request": { + * "headers": { + * "x-forwarded-for": "1.1.1.1, 2.2.2.2", + * "cloudfront-viewer-country": "US", + * "cloudfront-is-tablet-viewer": "false", + * "via": "2.0 xxxxxxxxxxxxxxxx.cloudfront.net (CloudFront)", + * "cloudfront-forwarded-proto": "https", + * "origin": "https://us-west-1.console.aws.amazon.com", + * "content-length": "217", + * "accept-language": "en-US,en;q=0.9", + * "host": "xxxxxxxxxxxxxxxx.appsync-api.us-west-1.amazonaws.com", + * "x-forwarded-proto": "https", + * "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36", + * "accept": "*!/!*", + * "cloudfront-is-mobile-viewer": "false", + * "cloudfront-is-smarttv-viewer": "false", + * "accept-encoding": "gzip, deflate, br", + * "referer": "https://us-west-1.console.aws.amazon.com/appsync/home?region=us-west-1", + * "content-type": "application/json", + * "sec-fetch-mode": "cors", + * "x-amz-cf-id": "3aykhqlUwQeANU-HGY7E_guV5EkNeMMtwyOgiA==", + * "x-amzn-trace-id": "Root=1-5f512f51-fac632066c5e848ae714", + * "authorization": "eyJraWQiOiJScWFCSlJqYVJlM0hrSnBTUFpIcVRXazNOW...", + * "sec-fetch-dest": "empty", + * "x-amz-user-agent": "AWS-Console-AppSync/", + * "cloudfront-is-desktop-viewer": "true", + * "sec-fetch-site": "cross-site", + * "x-forwarded-port": "443" + * } + * }, + * "prev": { + * "result": {} + * }, + * "info": { + * "selectionSetList": ["id", "field1", "field2"], + * "selectionSetGraphQL": "{\n id\n field1\n field2\n}", + * "parentTypeName": "Mutation", + * "fieldName": "createSomething", + * "variables": {} + * }, + * "stash": {} + * } + * ``` + * + * @see {@link https://docs.aws.amazon.com/appsync/latest/devguide/resolver-context-reference-js.html} + */ + +const AppSyncResolverSchema = z.object({ + arguments: z.record(z.any()), + identity: z.optional(AppSyncIdentity), + source: z.record(z.any()).nullable(), + request: z.object({ + domainName: z.string().nullable(), + headers: z.record(z.string()), + }), + info: z.object({ + selectionSetList: z.array(z.string()), + selectionSetGraphQL: z.string(), + parentTypeName: z.string(), + fieldName: z.string(), + variables: z.record(z.any()), + }), + prev: z + .object({ + result: z.record(z.any()), + }) + .nullable(), + stash: z.record(z.any()), +}); + +/** + * A zod schema for a batch AppSync resolver event + * + * @example + * ```json + * [{ + * "arguments": { + * "id": "1973493" + * }, + * "source": null, + * "identity": { + * "accountId": "012345678901", + * "cognitoIdentityAuthProvider": "cognitoIdentityAuthProvider", + * "cognitoIdentityAuthType": "cognitoIdentityAuthType", + * "cognitoIdentityId": "cognitoIdentityId", + * "cognitoIdentityPoolId": "cognitoIdentityPoolId", + * "sourceIp": ["10.10.10.10"], + * "userArn": "arn:aws:sts::012345678901:assumed-role/role", + * "username": "AROAXYKJUOW6FHGUSK5FA:username" + * }, + * "request": { + * "headers": { + * "x-forwarded-for": "1.1.1.1, 2.2.2.2", + * "cloudfront-viewer-country": "US", + * "cloudfront-is-tablet-viewer": "false", + * "via": "2.0 xxxxxxxxxxxxxxxx.cloudfront.net (CloudFront)", + * "cloudfront-forwarded-proto": "https", + * "origin": "https://us-west-1.console.aws.amazon.com", + * "content-length": "217", + * "accept-language": "en-US,en;q=0.9", + * "host": "xxxxxxxxxxxxxxxx.appsync-api.us-west-1.amazonaws.com", + * "x-forwarded-proto": "https", + * "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36", + * "accept": "*!/!*", + * "cloudfront-is-mobile-viewer": "false", + * "cloudfront-is-smarttv-viewer": "false", + * "accept-encoding": "gzip, deflate, br", + * "referer": "https://us-west-1.console.aws.amazon.com/appsync/home?region=us-west-1", + * "content-type": "application/json", + * "sec-fetch-mode": "cors", + * "x-amz-cf-id": "3aykhqlUwQeANU-HGY7E_guV5EkNeMMtwyOgiA==", + * "x-amzn-trace-id": "Root=1-5f512f51-fac632066c5e848ae714", + * "authorization": "eyJraWQiOiJScWFCSlJqYVJlM0hrSnBTUFpIcVRXazNOW...", + * "sec-fetch-dest": "empty", + * "x-amz-user-agent": "AWS-Console-AppSync/", + * "cloudfront-is-desktop-viewer": "true", + * "sec-fetch-site": "cross-site", + * "x-forwarded-port": "443" + * } + * }, + * "prev": { + * "result": {} + * }, + * "info": { + * "selectionSetList": ["id", "field1", "field2"], + * "selectionSetGraphQL": "{\n id\n field1\n field2\n}", + * "parentTypeName": "Mutation", + * "fieldName": "createSomething", + * "variables": {} + * }, + * "stash": {} + * }, + * { + * "arguments": { + * "id": "1987311" + * }, + * "source": null, + * "identity": { + * "claims": { + * "sub": "sub" + * }, + * "issuer": "issuer", + * "sub": "sub + * }, + * "request": { + * "headers": { + * "x-forwarded-for": "1.1.1.1, 2.2.2.2", + * "cloudfront-viewer-country": "US", + * "cloudfront-is-tablet-viewer": "false", + * "via": "2.0 xxxxxxxxxxxxxxxx.cloudfront.net (CloudFront)", + * "cloudfront-forwarded-proto": "https", + * "origin": "https://us-west-1.console.aws.amazon.com", + * "content-length": "217", + * "accept-language": "en-US,en;q=0.9", + * "host": "xxxxxxxxxxxxxxxx.appsync-api.us-west-1.amazonaws.com", + * "x-forwarded-proto": "https", + * "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36", + * "accept": "*!/!*", + * "cloudfront-is-mobile-viewer": "false", + * "cloudfront-is-smarttv-viewer": "false", + * "accept-encoding": "gzip, deflate, br", + * "referer": "https://us-west-1.console.aws.amazon.com/appsync/home?region=us-west-1", + * "content-type": "application/json", + * "sec-fetch-mode": "cors", + * "x-amz-cf-id": "3aykhqlUwQeANU-HGY7E_guV5EkNeMMtwyOgiA==", + * "x-amzn-trace-id": "Root=1-5f512f51-fac632066c5e848ae714", + * "authorization": "eyJraWQiOiJScWFCSlJqYVJlM0hrSnBTUFpIcVRXazNOW...", + * "sec-fetch-dest": "empty", + * "x-amz-user-agent": "AWS-Console-AppSync/", + * "cloudfront-is-desktop-viewer": "true", + * "sec-fetch-site": "cross-site", + * "x-forwarded-port": "443" + * } + * }, + * "prev": { + * "result": {} + * }, + * "info": { + * "selectionSetList": ["id", "field1", "field2"], + * "selectionSetGraphQL": "{\n id\n field1\n field2\n}", + * "parentTypeName": "Mutation", + * "fieldName": "createSomething", + * "variables": {} + * }, + * "stash": {} + * }] + * ``` + * + * @see {@link https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-lambda-resolvers.html#advanced-use-case-batching} + */ + +const AppSyncBatchResolverSchema = z.array(AppSyncResolverSchema); + +export { AppSyncResolverSchema, AppSyncBatchResolverSchema }; diff --git a/packages/parser/src/schemas/index.ts b/packages/parser/src/schemas/index.ts index 95fa347237..7c92729ad2 100644 --- a/packages/parser/src/schemas/index.ts +++ b/packages/parser/src/schemas/index.ts @@ -4,6 +4,10 @@ export { APIGatewayRequestAuthorizerEventSchema, APIGatewayTokenAuthorizerEventSchema, } from './apigw.js'; +export { + AppSyncResolverSchema, + AppSyncBatchResolverSchema, +} from './appsync.js'; export { APIGatewayProxyEventV2Schema, APIGatewayRequestAuthorizerEventV2Schema, diff --git a/packages/parser/src/types/index.ts b/packages/parser/src/types/index.ts index a74259e7eb..1bc68a549a 100644 --- a/packages/parser/src/types/index.ts +++ b/packages/parser/src/types/index.ts @@ -13,6 +13,8 @@ export type { APIGatewayProxyEventV2, APIGatewayRequestContextV2, APIGatewayRequestAuthorizerV2, + AppSyncResolverEvent, + AppSyncBatchResolverEvent, S3Event, S3EventNotificationEventBridge, S3SqsEventNotification, diff --git a/packages/parser/src/types/schema.ts b/packages/parser/src/types/schema.ts index f9084d97ec..5f17f4b6bd 100644 --- a/packages/parser/src/types/schema.ts +++ b/packages/parser/src/types/schema.ts @@ -6,6 +6,8 @@ import type { APIGatewayRequestContextV2Schema, AlbMultiValueHeadersSchema, AlbSchema, + AppSyncBatchResolverSchema, + AppSyncResolverSchema, CloudFormationCustomResourceCreateSchema, CloudFormationCustomResourceDeleteSchema, CloudFormationCustomResourceUpdateSchema, @@ -55,6 +57,10 @@ type APIGatewayRequestContextV2 = z.infer< typeof APIGatewayRequestContextV2Schema >; +type AppSyncResolverEvent = z.infer; + +type AppSyncBatchResolverEvent = z.infer; + type CloudFormationCustomResourceCreateEvent = z.infer< typeof CloudFormationCustomResourceCreateSchema >; @@ -134,6 +140,8 @@ export type { APIGatewayProxyEventV2, APIGatewayRequestAuthorizerV2, APIGatewayRequestContextV2, + AppSyncResolverEvent, + AppSyncBatchResolverEvent, CloudFormationCustomResourceCreateEvent, CloudFormationCustomResourceDeleteEvent, CloudFormationCustomResourceUpdateEvent, diff --git a/packages/parser/tests/events/appsync/cognito-identity-group.json b/packages/parser/tests/events/appsync/cognito-identity-group.json new file mode 100644 index 0000000000..ec2b94d343 --- /dev/null +++ b/packages/parser/tests/events/appsync/cognito-identity-group.json @@ -0,0 +1,77 @@ +{ + "arguments": { + "id": "my identifier" + }, + "source": { + "name": "Value", + "nested": { + "name": "value", + "list": [] + } + }, + "identity": { + "claims": { + "sub": "192879fc-a240-4bf1-ab5a-d6a00f3063f9", + "email_verified": true, + "iss": "https://cognito-idp.us-west-2.amazonaws.com/us-west-xxxxxxxxxxx", + "phone_number_verified": false, + "cognito:username": "jdoe", + "aud": "7471s60os7h0uu77i1tk27sp9n", + "event_id": "bc334ed8-a938-4474-b644-9547e304e606", + "token_use": "id", + "auth_time": 1599154213, + "phone_number": "+19999999999", + "exp": 1599157813, + "iat": 1599154213, + "email": "jdoe@email.com" + }, + "defaultAuthStrategy": "ALLOW", + "groups": ["group1", "group2"], + "issuer": "https://cognito-idp.us-west-2.amazonaws.com/us-west-xxxxxxxxxxx", + "sourceIp": ["1.1.1.1"], + "sub": "192879fc-a240-4bf1-ab5a-d6a00f3063f9", + "username": "jdoe" + }, + "request": { + "domainName": null, + "headers": { + "x-forwarded-for": "1.1.1.1, 2.2.2.2", + "cloudfront-viewer-country": "US", + "cloudfront-is-tablet-viewer": "false", + "via": "2.0 xxxxxxxxxxxxxxxx.cloudfront.net (CloudFront)", + "cloudfront-forwarded-proto": "https", + "origin": "https://us-west-1.console.aws.amazon.com", + "content-length": "217", + "accept-language": "en-US,en;q=0.9", + "host": "xxxxxxxxxxxxxxxx.appsync-api.us-west-1.amazonaws.com", + "x-forwarded-proto": "https", + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36", + "accept": "*/*", + "cloudfront-is-mobile-viewer": "false", + "cloudfront-is-smarttv-viewer": "false", + "accept-encoding": "gzip, deflate, br", + "referer": "https://us-west-1.console.aws.amazon.com/appsync/home?region=us-west-1", + "content-type": "application/json", + "sec-fetch-mode": "cors", + "x-amz-cf-id": "3aykhqlUwQeANU-HGY7E_guV5EkNeMMtwyOgiA==", + "x-amzn-trace-id": "Root=1-5f512f51-fac632066c5e848ae714", + "authorization": "eyJraWQiOiJScWFCSlJqYVJlM0hrSnBTUFpIcVRXazNOW...", + "sec-fetch-dest": "empty", + "x-amz-user-agent": "AWS-Console-AppSync/", + "cloudfront-is-desktop-viewer": "true", + "sec-fetch-site": "cross-site", + "x-forwarded-port": "443" + } + }, + "prev": { + "result": {} + }, + "info": { + "selectionSetList": ["id", "field1", "field2"], + "selectionSetGraphQL": "{\n id\n field1\n field2\n}", + "parentTypeName": "Mutation", + "fieldName": "createSomething", + "variables": {} + }, + "stash": {} +} diff --git a/packages/parser/tests/events/appsync/cognito-identity-null-group.json b/packages/parser/tests/events/appsync/cognito-identity-null-group.json new file mode 100644 index 0000000000..b6e68142d0 --- /dev/null +++ b/packages/parser/tests/events/appsync/cognito-identity-null-group.json @@ -0,0 +1,77 @@ +{ + "arguments": { + "id": "my identifier" + }, + "source": { + "name": "Value", + "nested": { + "name": "value", + "list": [] + } + }, + "identity": { + "claims": { + "sub": "192879fc-a240-4bf1-ab5a-d6a00f3063f9", + "email_verified": true, + "iss": "https://cognito-idp.us-west-2.amazonaws.com/us-west-xxxxxxxxxxx", + "phone_number_verified": false, + "cognito:username": "jdoe", + "aud": "7471s60os7h0uu77i1tk27sp9n", + "event_id": "bc334ed8-a938-4474-b644-9547e304e606", + "token_use": "id", + "auth_time": 1599154213, + "phone_number": "+19999999999", + "exp": 1599157813, + "iat": 1599154213, + "email": "jdoe@email.com" + }, + "defaultAuthStrategy": "ALLOW", + "groups": null, + "issuer": "https://cognito-idp.us-west-2.amazonaws.com/us-west-xxxxxxxxxxx", + "sourceIp": ["1.1.1.1"], + "sub": "192879fc-a240-4bf1-ab5a-d6a00f3063f9", + "username": "jdoe" + }, + "request": { + "domainName": null, + "headers": { + "x-forwarded-for": "1.1.1.1, 2.2.2.2", + "cloudfront-viewer-country": "US", + "cloudfront-is-tablet-viewer": "false", + "via": "2.0 xxxxxxxxxxxxxxxx.cloudfront.net (CloudFront)", + "cloudfront-forwarded-proto": "https", + "origin": "https://us-west-1.console.aws.amazon.com", + "content-length": "217", + "accept-language": "en-US,en;q=0.9", + "host": "xxxxxxxxxxxxxxxx.appsync-api.us-west-1.amazonaws.com", + "x-forwarded-proto": "https", + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36", + "accept": "*/*", + "cloudfront-is-mobile-viewer": "false", + "cloudfront-is-smarttv-viewer": "false", + "accept-encoding": "gzip, deflate, br", + "referer": "https://us-west-1.console.aws.amazon.com/appsync/home?region=us-west-1", + "content-type": "application/json", + "sec-fetch-mode": "cors", + "x-amz-cf-id": "3aykhqlUwQeANU-HGY7E_guV5EkNeMMtwyOgiA==", + "x-amzn-trace-id": "Root=1-5f512f51-fac632066c5e848ae714", + "authorization": "eyJraWQiOiJScWFCSlJqYVJlM0hrSnBTUFpIcVRXazNOW...", + "sec-fetch-dest": "empty", + "x-amz-user-agent": "AWS-Console-AppSync/", + "cloudfront-is-desktop-viewer": "true", + "sec-fetch-site": "cross-site", + "x-forwarded-port": "443" + } + }, + "prev": { + "result": {} + }, + "info": { + "selectionSetList": ["id", "field1", "field2"], + "selectionSetGraphQL": "{\n id\n field1\n field2\n}", + "parentTypeName": "Mutation", + "fieldName": "createSomething", + "variables": {} + }, + "stash": {} +} diff --git a/packages/parser/tests/events/appsync/custom-domain-name.json b/packages/parser/tests/events/appsync/custom-domain-name.json new file mode 100644 index 0000000000..3b020994c5 --- /dev/null +++ b/packages/parser/tests/events/appsync/custom-domain-name.json @@ -0,0 +1,56 @@ +{ + "arguments": { + "id": "my identifier" + }, + "source": { + "name": "Value", + "nested": { + "name": "value", + "list": [] + } + }, + "request": { + "domainName": "mycustomdomain.example.com", + "headers": { + "x-forwarded-for": "1.1.1.1, 2.2.2.2", + "cloudfront-viewer-country": "US", + "cloudfront-is-tablet-viewer": "false", + "via": "2.0 xxxxxxxxxxxxxxxx.cloudfront.net (CloudFront)", + "cloudfront-forwarded-proto": "https", + "origin": "https://us-west-1.console.aws.amazon.com", + "content-length": "217", + "accept-language": "en-US,en;q=0.9", + "host": "xxxxxxxxxxxxxxxx.appsync-api.us-west-1.amazonaws.com", + "x-forwarded-proto": "https", + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36", + "accept": "*/*", + "cloudfront-is-mobile-viewer": "false", + "cloudfront-is-smarttv-viewer": "false", + "accept-encoding": "gzip, deflate, br", + "referer": "https://us-west-1.console.aws.amazon.com/appsync/home?region=us-west-1", + "content-type": "application/json", + "sec-fetch-mode": "cors", + "x-amz-cf-id": "3aykhqlUwQeANU-HGY7E_guV5EkNeMMtwyOgiA==", + "x-amzn-trace-id": "Root=1-5f512f51-fac632066c5e848ae714", + "authorization": "eyJraWQiOiJScWFCSlJqYVJlM0hrSnBTUFpIcVRXazNOW...", + "sec-fetch-dest": "empty", + "x-amz-user-agent": "AWS-Console-AppSync/", + "cloudfront-is-desktop-viewer": "true", + "sec-fetch-site": "cross-site", + "x-forwarded-port": "443" + } + }, + "prev": { + "result": { + "field1": "value1" + } + }, + "info": { + "selectionSetList": ["id", "field1", "field2"], + "selectionSetGraphQL": "{\n id\n field1\n field2\n}", + "parentTypeName": "Mutation", + "fieldName": "createSomething", + "variables": {} + }, + "stash": {} +} diff --git a/packages/parser/tests/events/appsync/iam-identity-cognito.json b/packages/parser/tests/events/appsync/iam-identity-cognito.json new file mode 100644 index 0000000000..1f37cc38da --- /dev/null +++ b/packages/parser/tests/events/appsync/iam-identity-cognito.json @@ -0,0 +1,64 @@ +{ + "arguments": { + "id": "my identifier" + }, + "source": { + "name": "Value", + "nested": { + "name": "value", + "list": [] + } + }, + "identity": { + "accountId": "012345678901", + "cognitoIdentityAuthProvider": "cognitoIdentityAuthProvider", + "cognitoIdentityAuthType": "cognitoIdentityAuthType", + "cognitoIdentityId": "cognitoIdentityId", + "cognitoIdentityPoolId": "cognitoIdentityPoolId", + "sourceIp": ["10.10.10.10"], + "userArn": "arn:aws:sts::012345678901:assumed-role/role", + "username": "AROAXYKJUOW6FHGUSK5FA:username" + }, + "request": { + "domainName": null, + "headers": { + "x-forwarded-for": "1.1.1.1, 2.2.2.2", + "cloudfront-viewer-country": "US", + "cloudfront-is-tablet-viewer": "false", + "via": "2.0 xxxxxxxxxxxxxxxx.cloudfront.net (CloudFront)", + "cloudfront-forwarded-proto": "https", + "origin": "https://us-west-1.console.aws.amazon.com", + "content-length": "217", + "accept-language": "en-US,en;q=0.9", + "host": "xxxxxxxxxxxxxxxx.appsync-api.us-west-1.amazonaws.com", + "x-forwarded-proto": "https", + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36", + "accept": "*/*", + "cloudfront-is-mobile-viewer": "false", + "cloudfront-is-smarttv-viewer": "false", + "accept-encoding": "gzip, deflate, br", + "referer": "https://us-west-1.console.aws.amazon.com/appsync/home?region=us-west-1", + "content-type": "application/json", + "sec-fetch-mode": "cors", + "x-amz-cf-id": "3aykhqlUwQeANU-HGY7E_guV5EkNeMMtwyOgiA==", + "x-amzn-trace-id": "Root=1-5f512f51-fac632066c5e848ae714", + "authorization": "eyJraWQiOiJScWFCSlJqYVJlM0hrSnBTUFpIcVRXazNOW...", + "sec-fetch-dest": "empty", + "x-amz-user-agent": "AWS-Console-AppSync/", + "cloudfront-is-desktop-viewer": "true", + "sec-fetch-site": "cross-site", + "x-forwarded-port": "443" + } + }, + "prev": { + "result": {} + }, + "info": { + "selectionSetList": ["id", "field1", "field2"], + "selectionSetGraphQL": "{\n id\n field1\n field2\n}", + "parentTypeName": "Mutation", + "fieldName": "createSomething", + "variables": {} + }, + "stash": {} +} diff --git a/packages/parser/tests/events/appsync/iam-identity-no-cognito.json b/packages/parser/tests/events/appsync/iam-identity-no-cognito.json new file mode 100644 index 0000000000..5d141b0509 --- /dev/null +++ b/packages/parser/tests/events/appsync/iam-identity-no-cognito.json @@ -0,0 +1,64 @@ +{ + "arguments": { + "id": "my identifier" + }, + "source": { + "name": "Value", + "nested": { + "name": "value", + "list": [] + } + }, + "identity": { + "accountId": "012345678901", + "cognitoIdentityAuthProvider": null, + "cognitoIdentityAuthType": null, + "cognitoIdentityId": null, + "cognitoIdentityPoolId": null, + "sourceIp": ["10.10.10.10"], + "userArn": "arn:aws:sts::012345678901:assumed-role/role", + "username": "AROAXYKJUOW6FHGUSK5FA:username" + }, + "request": { + "domainName": null, + "headers": { + "x-forwarded-for": "1.1.1.1, 2.2.2.2", + "cloudfront-viewer-country": "US", + "cloudfront-is-tablet-viewer": "false", + "via": "2.0 xxxxxxxxxxxxxxxx.cloudfront.net (CloudFront)", + "cloudfront-forwarded-proto": "https", + "origin": "https://us-west-1.console.aws.amazon.com", + "content-length": "217", + "accept-language": "en-US,en;q=0.9", + "host": "xxxxxxxxxxxxxxxx.appsync-api.us-west-1.amazonaws.com", + "x-forwarded-proto": "https", + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36", + "accept": "*/*", + "cloudfront-is-mobile-viewer": "false", + "cloudfront-is-smarttv-viewer": "false", + "accept-encoding": "gzip, deflate, br", + "referer": "https://us-west-1.console.aws.amazon.com/appsync/home?region=us-west-1", + "content-type": "application/json", + "sec-fetch-mode": "cors", + "x-amz-cf-id": "3aykhqlUwQeANU-HGY7E_guV5EkNeMMtwyOgiA==", + "x-amzn-trace-id": "Root=1-5f512f51-fac632066c5e848ae714", + "authorization": "eyJraWQiOiJScWFCSlJqYVJlM0hrSnBTUFpIcVRXazNOW...", + "sec-fetch-dest": "empty", + "x-amz-user-agent": "AWS-Console-AppSync/", + "cloudfront-is-desktop-viewer": "true", + "sec-fetch-site": "cross-site", + "x-forwarded-port": "443" + } + }, + "prev": { + "result": {} + }, + "info": { + "selectionSetList": ["id", "field1", "field2"], + "selectionSetGraphQL": "{\n id\n field1\n field2\n}", + "parentTypeName": "Mutation", + "fieldName": "createSomething", + "variables": {} + }, + "stash": {} +} diff --git a/packages/parser/tests/events/appsync/invalid.json b/packages/parser/tests/events/appsync/invalid.json new file mode 100644 index 0000000000..b0992f4ae1 --- /dev/null +++ b/packages/parser/tests/events/appsync/invalid.json @@ -0,0 +1,18 @@ +{ + "arguments": { + "id": "my identifier" + }, + "source": { + "name": "Value", + "nested": { + "name": "value", + "list": [] + } + }, + "prev": { + "result": { + "field1": "value1" + } + }, + "stash": {} +} diff --git a/packages/parser/tests/events/appsync/lambda-identity.json b/packages/parser/tests/events/appsync/lambda-identity.json new file mode 100644 index 0000000000..0e7c928417 --- /dev/null +++ b/packages/parser/tests/events/appsync/lambda-identity.json @@ -0,0 +1,59 @@ +{ + "arguments": { + "id": "my identifier" + }, + "source": { + "name": "Value", + "nested": { + "name": "value", + "list": [] + } + }, + "identity": { + "resolverContext": { + "field1": "value" + } + }, + "request": { + "domainName": null, + "headers": { + "x-forwarded-for": "1.1.1.1, 2.2.2.2", + "cloudfront-viewer-country": "US", + "cloudfront-is-tablet-viewer": "false", + "via": "2.0 xxxxxxxxxxxxxxxx.cloudfront.net (CloudFront)", + "cloudfront-forwarded-proto": "https", + "origin": "https://us-west-1.console.aws.amazon.com", + "content-length": "217", + "accept-language": "en-US,en;q=0.9", + "host": "xxxxxxxxxxxxxxxx.appsync-api.us-west-1.amazonaws.com", + "x-forwarded-proto": "https", + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36", + "accept": "*/*", + "cloudfront-is-mobile-viewer": "false", + "cloudfront-is-smarttv-viewer": "false", + "accept-encoding": "gzip, deflate, br", + "referer": "https://us-west-1.console.aws.amazon.com/appsync/home?region=us-west-1", + "content-type": "application/json", + "sec-fetch-mode": "cors", + "x-amz-cf-id": "3aykhqlUwQeANU-HGY7E_guV5EkNeMMtwyOgiA==", + "x-amzn-trace-id": "Root=1-5f512f51-fac632066c5e848ae714", + "authorization": "eyJraWQiOiJScWFCSlJqYVJlM0hrSnBTUFpIcVRXazNOW...", + "sec-fetch-dest": "empty", + "x-amz-user-agent": "AWS-Console-AppSync/", + "cloudfront-is-desktop-viewer": "true", + "sec-fetch-site": "cross-site", + "x-forwarded-port": "443" + } + }, + "prev": { + "result": {} + }, + "info": { + "selectionSetList": ["id", "field1", "field2"], + "selectionSetGraphQL": "{\n id\n field1\n field2\n}", + "parentTypeName": "Mutation", + "fieldName": "createSomething", + "variables": {} + }, + "stash": {} +} diff --git a/packages/parser/tests/events/appsync/no-identity.json b/packages/parser/tests/events/appsync/no-identity.json new file mode 100644 index 0000000000..253128a218 --- /dev/null +++ b/packages/parser/tests/events/appsync/no-identity.json @@ -0,0 +1,56 @@ +{ + "arguments": { + "id": "my identifier" + }, + "source": { + "name": "Value", + "nested": { + "name": "value", + "list": [] + } + }, + "request": { + "domainName": null, + "headers": { + "x-forwarded-for": "1.1.1.1, 2.2.2.2", + "cloudfront-viewer-country": "US", + "cloudfront-is-tablet-viewer": "false", + "via": "2.0 xxxxxxxxxxxxxxxx.cloudfront.net (CloudFront)", + "cloudfront-forwarded-proto": "https", + "origin": "https://us-west-1.console.aws.amazon.com", + "content-length": "217", + "accept-language": "en-US,en;q=0.9", + "host": "xxxxxxxxxxxxxxxx.appsync-api.us-west-1.amazonaws.com", + "x-forwarded-proto": "https", + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36", + "accept": "*/*", + "cloudfront-is-mobile-viewer": "false", + "cloudfront-is-smarttv-viewer": "false", + "accept-encoding": "gzip, deflate, br", + "referer": "https://us-west-1.console.aws.amazon.com/appsync/home?region=us-west-1", + "content-type": "application/json", + "sec-fetch-mode": "cors", + "x-amz-cf-id": "3aykhqlUwQeANU-HGY7E_guV5EkNeMMtwyOgiA==", + "x-amzn-trace-id": "Root=1-5f512f51-fac632066c5e848ae714", + "authorization": "eyJraWQiOiJScWFCSlJqYVJlM0hrSnBTUFpIcVRXazNOW...", + "sec-fetch-dest": "empty", + "x-amz-user-agent": "AWS-Console-AppSync/", + "cloudfront-is-desktop-viewer": "true", + "sec-fetch-site": "cross-site", + "x-forwarded-port": "443" + } + }, + "prev": { + "result": { + "field1": "value1" + } + }, + "info": { + "selectionSetList": ["id", "field1", "field2"], + "selectionSetGraphQL": "{\n id\n field1\n field2\n}", + "parentTypeName": "Mutation", + "fieldName": "createSomething", + "variables": {} + }, + "stash": {} +} diff --git a/packages/parser/tests/events/appsync/null-prev.json b/packages/parser/tests/events/appsync/null-prev.json new file mode 100644 index 0000000000..ecaa3e6af0 --- /dev/null +++ b/packages/parser/tests/events/appsync/null-prev.json @@ -0,0 +1,52 @@ +{ + "arguments": { + "id": "my identifier" + }, + "source": { + "name": "Value", + "nested": { + "name": "value", + "list": [] + } + }, + "request": { + "domainName": null, + "headers": { + "x-forwarded-for": "1.1.1.1, 2.2.2.2", + "cloudfront-viewer-country": "US", + "cloudfront-is-tablet-viewer": "false", + "via": "2.0 xxxxxxxxxxxxxxxx.cloudfront.net (CloudFront)", + "cloudfront-forwarded-proto": "https", + "origin": "https://us-west-1.console.aws.amazon.com", + "content-length": "217", + "accept-language": "en-US,en;q=0.9", + "host": "xxxxxxxxxxxxxxxx.appsync-api.us-west-1.amazonaws.com", + "x-forwarded-proto": "https", + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36", + "accept": "*/*", + "cloudfront-is-mobile-viewer": "false", + "cloudfront-is-smarttv-viewer": "false", + "accept-encoding": "gzip, deflate, br", + "referer": "https://us-west-1.console.aws.amazon.com/appsync/home?region=us-west-1", + "content-type": "application/json", + "sec-fetch-mode": "cors", + "x-amz-cf-id": "3aykhqlUwQeANU-HGY7E_guV5EkNeMMtwyOgiA==", + "x-amzn-trace-id": "Root=1-5f512f51-fac632066c5e848ae714", + "authorization": "eyJraWQiOiJScWFCSlJqYVJlM0hrSnBTUFpIcVRXazNOW...", + "sec-fetch-dest": "empty", + "x-amz-user-agent": "AWS-Console-AppSync/", + "cloudfront-is-desktop-viewer": "true", + "sec-fetch-site": "cross-site", + "x-forwarded-port": "443" + } + }, + "prev": null, + "info": { + "selectionSetList": ["id", "field1", "field2"], + "selectionSetGraphQL": "{\n id\n field1\n field2\n}", + "parentTypeName": "Mutation", + "fieldName": "createSomething", + "variables": {} + }, + "stash": {} +} diff --git a/packages/parser/tests/events/appsync/null-source.json b/packages/parser/tests/events/appsync/null-source.json new file mode 100644 index 0000000000..eb8d06f046 --- /dev/null +++ b/packages/parser/tests/events/appsync/null-source.json @@ -0,0 +1,48 @@ +{ + "arguments": { + "id": "my identifier" + }, + "source": null, + "request": { + "domainName": null, + "headers": { + "x-forwarded-for": "1.1.1.1, 2.2.2.2", + "cloudfront-viewer-country": "US", + "cloudfront-is-tablet-viewer": "false", + "via": "2.0 xxxxxxxxxxxxxxxx.cloudfront.net (CloudFront)", + "cloudfront-forwarded-proto": "https", + "origin": "https://us-west-1.console.aws.amazon.com", + "content-length": "217", + "accept-language": "en-US,en;q=0.9", + "host": "xxxxxxxxxxxxxxxx.appsync-api.us-west-1.amazonaws.com", + "x-forwarded-proto": "https", + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36", + "accept": "*/*", + "cloudfront-is-mobile-viewer": "false", + "cloudfront-is-smarttv-viewer": "false", + "accept-encoding": "gzip, deflate, br", + "referer": "https://us-west-1.console.aws.amazon.com/appsync/home?region=us-west-1", + "content-type": "application/json", + "sec-fetch-mode": "cors", + "x-amz-cf-id": "3aykhqlUwQeANU-HGY7E_guV5EkNeMMtwyOgiA==", + "x-amzn-trace-id": "Root=1-5f512f51-fac632066c5e848ae714", + "authorization": "eyJraWQiOiJScWFCSlJqYVJlM0hrSnBTUFpIcVRXazNOW...", + "sec-fetch-dest": "empty", + "x-amz-user-agent": "AWS-Console-AppSync/", + "cloudfront-is-desktop-viewer": "true", + "sec-fetch-site": "cross-site", + "x-forwarded-port": "443" + } + }, + "prev": { + "result": {} + }, + "info": { + "selectionSetList": ["id", "field1", "field2"], + "selectionSetGraphQL": "{\n id\n field1\n field2\n}", + "parentTypeName": "Mutation", + "fieldName": "createSomething", + "variables": {} + }, + "stash": {} +} diff --git a/packages/parser/tests/events/appsync/oidc-identity.json b/packages/parser/tests/events/appsync/oidc-identity.json new file mode 100644 index 0000000000..74fc9b0269 --- /dev/null +++ b/packages/parser/tests/events/appsync/oidc-identity.json @@ -0,0 +1,61 @@ +{ + "arguments": { + "id": "my identifier" + }, + "source": { + "name": "Value", + "nested": { + "name": "value", + "list": [] + } + }, + "identity": { + "claims": { + "sub": "sub" + }, + "issuer": "issuer", + "sub": "sub" + }, + "request": { + "domainName": null, + "headers": { + "x-forwarded-for": "1.1.1.1, 2.2.2.2", + "cloudfront-viewer-country": "US", + "cloudfront-is-tablet-viewer": "false", + "via": "2.0 xxxxxxxxxxxxxxxx.cloudfront.net (CloudFront)", + "cloudfront-forwarded-proto": "https", + "origin": "https://us-west-1.console.aws.amazon.com", + "content-length": "217", + "accept-language": "en-US,en;q=0.9", + "host": "xxxxxxxxxxxxxxxx.appsync-api.us-west-1.amazonaws.com", + "x-forwarded-proto": "https", + "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.83 Safari/537.36", + "accept": "*/*", + "cloudfront-is-mobile-viewer": "false", + "cloudfront-is-smarttv-viewer": "false", + "accept-encoding": "gzip, deflate, br", + "referer": "https://us-west-1.console.aws.amazon.com/appsync/home?region=us-west-1", + "content-type": "application/json", + "sec-fetch-mode": "cors", + "x-amz-cf-id": "3aykhqlUwQeANU-HGY7E_guV5EkNeMMtwyOgiA==", + "x-amzn-trace-id": "Root=1-5f512f51-fac632066c5e848ae714", + "authorization": "eyJraWQiOiJScWFCSlJqYVJlM0hrSnBTUFpIcVRXazNOW...", + "sec-fetch-dest": "empty", + "x-amz-user-agent": "AWS-Console-AppSync/", + "cloudfront-is-desktop-viewer": "true", + "sec-fetch-site": "cross-site", + "x-forwarded-port": "443" + } + }, + "prev": { + "result": {} + }, + "info": { + "selectionSetList": ["id", "field1", "field2"], + "selectionSetGraphQL": "{\n id\n field1\n field2\n}", + "parentTypeName": "Mutation", + "fieldName": "createSomething", + "variables": {} + }, + "stash": {} +} diff --git a/packages/parser/tests/unit/schema/appsync.test.ts b/packages/parser/tests/unit/schema/appsync.test.ts new file mode 100644 index 0000000000..4330e42f12 --- /dev/null +++ b/packages/parser/tests/unit/schema/appsync.test.ts @@ -0,0 +1,141 @@ +/** + * Test built-in AppSync resolver schemas + * + * @group unit/parser/schema/appsync + */ + +import { describe, expect, it } from 'vitest'; +import { + AppSyncBatchResolverSchema, + AppSyncResolverSchema, +} from '../../../src/schemas/appsync'; +import type { AppSyncResolverEvent } from '../../../src/types'; +import { getTestEvent } from './utils'; + +type Table = { + name: string; + filename: string; +}; + +describe('AppSync Resolver Schemas', () => { + const eventsPath = 'appsync'; + + const table = [ + { + name: 'should parse resolver event without identity field', + filename: 'no-identity', + }, + { + name: 'should parse resolver event with null source', + filename: 'null-source', + }, + { + name: 'should parse resolver event with null prev', + filename: 'null-prev', + }, + { + name: 'should parse resolver event with custom domain name', + filename: 'custom-domain-name', + }, + { + name: 'should parse resolver event with cognito identity and rbac groups', + filename: 'cognito-identity-group', + }, + { + name: 'should parse resolver event with cognito identity and no rbac groups', + filename: 'cognito-identity-null-group', + }, + { + name: 'with iam identity with no cognito fields', + filename: 'iam-identity-no-cognito', + }, + { + name: 'should parse resolver event with iam identity with cognito fields', + filename: 'iam-identity-cognito', + }, + { + name: 'should parse resolver event with lambda identity', + filename: 'lambda-identity', + }, + { + name: 'should parse resolver event with oidc identity', + filename: 'oidc-identity', + }, + ]; + + describe('AppSync Resolver Schema', () => { + it('should return validation error when the event is invalid', () => { + const event = getTestEvent({ eventsPath, filename: 'invalid' }); + + const { error } = AppSyncResolverSchema.safeParse(event); + + expect(error?.issues).toEqual([ + { + code: 'invalid_type', + expected: 'object', + received: 'undefined', + path: ['request'], + message: 'Required', + }, + { + code: 'invalid_type', + expected: 'object', + received: 'undefined', + path: ['info'], + message: 'Required', + }, + ]); + }); + + it.each(table)('$name', ({ filename }) => { + const event = getTestEvent({ + eventsPath, + filename, + }); + + const parsedEvent = AppSyncResolverSchema.parse(event); + + expect(parsedEvent).toEqual(event); + }); + }); + + describe('Batch AppSync Resolver Schema', () => { + it('should return validation error when the event is invalid', () => { + const event = getTestEvent({ + eventsPath, + filename: 'invalid', + }); + + const { error } = AppSyncBatchResolverSchema.safeParse([event]); + + expect(error?.issues).toEqual([ + { + code: 'invalid_type', + expected: 'object', + received: 'undefined', + path: [0, 'request'], + message: 'Required', + }, + { + code: 'invalid_type', + expected: 'object', + received: 'undefined', + path: [0, 'info'], + message: 'Required', + }, + ]); + }); + + it('should parse batches of appsync resolver events', () => { + const filenames = table.map((table: Table) => table.filename); + + const events = filenames.map((filename) => + getTestEvent({ eventsPath, filename }) + ); + + const parsedEvent = AppSyncBatchResolverSchema.parse(events); + + expect(parsedEvent).toEqual(events); + }); + }); +});