generated from amazon-archives/__template_Apache-2.0
-
Notifications
You must be signed in to change notification settings - Fork 89
chore: migrate pg model dynamic auth e2e test in gen2 cdk #2920
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
35 commits
Select commit
Hold shift + click to select a range
5ade104
chore: initial commit
Siqi-Shan 90019a0
chore: debugging
Siqi-Shan ae910c3
chore: debugging cleaning
Siqi-Shan 123a480
chore: debugging
Siqi-Shan 7f5730f
fix: revising cdk and auth
Siqi-Shan 5fd253a
fix: tests except subscription
Siqi-Shan 153cfaa
chore: userpool test except subscription
Siqi-Shan 73b25d6
chore: debugging
Siqi-Shan 1f18fd7
chore: debugging
Siqi-Shan 1a03e65
fix: ttl duration unit conversion + e2e test
Siqi-Shan 8536347
chore: revert back construct changes to another PR
Siqi-Shan 3f72891
chore: initial cdk refactor
Siqi-Shan b5a22de
chore: cleanup
Siqi-Shan 69ac8d2
refactor: major refactor to sql confogurable stack and config write
Siqi-Shan 6e68ea0
refactor: configurable stack for prev tests
Siqi-Shan 691f1f5
chore: naming + trimming
Siqi-Shan 04c21ef
refactor: test setup + stack config
Siqi-Shan a409c75
chore: cleanup
Siqi-Shan 17c7e60
fix: async cleanup fix
Siqi-Shan 61e2404
Merge branch 'main' into gen2-migrate-pg-userpool-auth-e2e-test
Siqi-Shan d6645da
refactor: appsync client refactor
Siqi-Shan be1759e
refactor: appsync client helper
Siqi-Shan 65ecb07
refactor: cognito helper + initial test
Siqi-Shan 9d377ed
refactor: tester + test pattern extract
Siqi-Shan fab3911
refactor: auth tester generic function + crudl helper
Siqi-Shan d30adf8
refactor: add pg auto increment test from main
Siqi-Shan 268467c
Merge branch 'main' into gen2-migrate-pg-userpool-auth-e2e-test
Siqi-Shan 311a0a3
refactor: test conflict resolved + merge main
Siqi-Shan e98c99c
Merge branch 'main' into gen2-migrate-pg-userpool-auth-e2e-test
Siqi-Shan f4d541c
Merge branch 'main' into gen2-migrate-pg-userpool-auth-e2e-test
Siqi-Shan 2bbcd68
chore: naming + schema change
Siqi-Shan 51e2f97
Merge branch 'main' into gen2-migrate-pg-userpool-auth-e2e-test
Siqi-Shan 5f16873
refactor: sql provider helper to support my directives and mysql
Siqi-Shan c9cbece
fix: postgres schema formatting
Siqi-Shan de91277
fix: correct escape when converting sql create statements
Siqi-Shan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
299 changes: 299 additions & 0 deletions
299
.../amplify-graphql-api-construct-tests/src/__tests__/backends/sql-configurable-stack/app.ts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,299 @@ | ||
| #!/usr/bin/env node | ||
| import 'source-map-support/register'; | ||
| import { App, Stack, CfnOutput, Duration, RemovalPolicy } from 'aws-cdk-lib'; | ||
| // @ts-ignore | ||
| import { | ||
| AmplifyGraphqlApi, | ||
| AmplifyGraphqlDefinition, | ||
| AuthorizationModes, | ||
| IAmplifyGraphqlDefinition, | ||
| SqlModelDataSourceDbConnectionConfig, | ||
| ModelDataSourceStrategySqlDbType, | ||
| PartialTranslationBehavior, | ||
| } from '@aws-amplify/graphql-api-construct'; | ||
| import { AccountPrincipal, Effect, PolicyDocument, PolicyStatement, Role } from 'aws-cdk-lib/aws-iam'; | ||
| import { CfnUserPoolGroup, UserPool, UserPoolClient, UserPoolTriggers } from 'aws-cdk-lib/aws-cognito'; | ||
| import { Function, Runtime, Code } from 'aws-cdk-lib/aws-lambda'; | ||
|
|
||
| // #region Utilities | ||
|
|
||
| enum AUTH_MODE { | ||
| API_KEY = 'API_KEY', | ||
| AWS_IAM = 'AWS_IAM', | ||
| AMAZON_COGNITO_USER_POOLS = 'AMAZON_COGNITO_USER_POOLS', | ||
| OPENID_CONNECT = 'OPENID_CONNECT', | ||
| AWS_LAMBDA = 'AWS_LAMBDA', | ||
| } | ||
|
|
||
| interface DBDetails { | ||
| dbConfig: { | ||
| endpoint: string; | ||
| port: number; | ||
| dbName: string; | ||
| dbType: ModelDataSourceStrategySqlDbType; | ||
| strategyName: string; | ||
| vpcConfig: { | ||
| vpcId: string; | ||
| securityGroupIds: string[]; | ||
| subnetAvailabilityZones: [ | ||
| { | ||
| subnetId: string; | ||
| availabilityZone: string; | ||
| }, | ||
| ]; | ||
| }; | ||
| }; | ||
| dbConnectionConfig: SqlModelDataSourceDbConnectionConfig; | ||
| } | ||
|
|
||
| interface StackConfig { | ||
| /** | ||
| * The AppSync GraphQL schema, provided as string for AmplifyGraphqlApi Construct definition. | ||
| */ | ||
| schema: string; | ||
|
|
||
| /** | ||
| * The AuthorizationMode type for AmplifyGraphqlApi Construct. | ||
| */ | ||
| authMode?: AUTH_MODE; | ||
|
|
||
| /** | ||
| * If true, disable Cognito User Pool/Auth resources creation and only use API Key auth in sandbox mode. | ||
| */ | ||
| useSandbox?: boolean; | ||
|
|
||
| /** | ||
| * Cognito User Pool groups to create when provisioning the User Pool. | ||
| * | ||
| * **NOTE** | ||
| * Provide at least two group names for setup and testing purposes. | ||
| */ | ||
| userGroups?: string[]; | ||
|
|
||
| /** | ||
| * The OIDC options/config when using OIDC AuthorizationMode for AmplifyGraphqlApi Construct. | ||
| * | ||
| * @property {Record<string, string>} [triggers] - UserPoolTriggers for Cognito User Pool when provisioning the User Pool as OIDC provider. | ||
| * - key: trigger name e.g. 'preTokenGeneration' | ||
| * - value: the lambda function code inlined as a string | ||
| * | ||
| * **NOTE** | ||
| * - Only applicable when AuthorizationMode is set to OIDC. | ||
| * - Currently only supports Cognito User Pools as the simulated OIDC provider for E2E test. | ||
| * - Currently only supports JavaScript as the lambda function code, with Node.js runtime version 18.x. | ||
| * - Inline code needs to export the handler function as `handler` as `index.handler` would be used as the handler path. | ||
| */ | ||
| oidcOptions?: { | ||
| triggers: Record<string, string>; | ||
| }; | ||
| } | ||
|
|
||
| const createApiDefinition = (): IAmplifyGraphqlDefinition => { | ||
| return AmplifyGraphqlDefinition.fromString(stackConfig.schema, { | ||
| name: dbDetails.dbConfig.strategyName, | ||
| dbType: dbDetails.dbConfig.dbType, | ||
| vpcConfiguration: { | ||
| vpcId: dbDetails.dbConfig.vpcConfig.vpcId, | ||
| securityGroupIds: dbDetails.dbConfig.vpcConfig.securityGroupIds, | ||
| subnetAvailabilityZoneConfig: dbDetails.dbConfig.vpcConfig.subnetAvailabilityZones, | ||
| }, | ||
| dbConnectionConfig: { | ||
| ...dbDetails.dbConnectionConfig, | ||
| }, | ||
| sqlLambdaProvisionedConcurrencyConfig: { | ||
| provisionedConcurrentExecutions: 2, | ||
| }, | ||
| }); | ||
| }; | ||
|
|
||
| const createAuthorizationModes = (): AuthorizationModes => { | ||
| const auth = stackConfig.authMode ?? AUTH_MODE.API_KEY; | ||
| let authorizationModes: AuthorizationModes; | ||
|
|
||
| switch (auth) { | ||
| case AUTH_MODE.API_KEY: { | ||
| authorizationModes = { | ||
| defaultAuthorizationMode: 'API_KEY', | ||
| apiKeyConfig: { expires: Duration.days(7) }, | ||
| }; | ||
|
|
||
| break; | ||
| } | ||
| case AUTH_MODE.AMAZON_COGNITO_USER_POOLS: { | ||
| const { userPool, userPoolClient } = createUserPool(dbDetails.dbConfig.dbName); | ||
|
|
||
| authorizationModes = { | ||
| defaultAuthorizationMode: 'AMAZON_COGNITO_USER_POOLS', | ||
| userPoolConfig: { | ||
| userPool, | ||
| }, | ||
| apiKeyConfig: { expires: Duration.days(2) }, | ||
| }; | ||
|
|
||
| break; | ||
| } | ||
| case AUTH_MODE.OPENID_CONNECT: { | ||
| const { userPool, userPoolClient } = createUserPool(dbDetails.dbConfig.dbName, stackConfig.oidcOptions?.triggers); | ||
|
|
||
| authorizationModes = { | ||
| defaultAuthorizationMode: 'OPENID_CONNECT', | ||
| oidcConfig: { | ||
| oidcProviderName: 'awscognitouserpool', | ||
| oidcIssuerUrl: `https://cognito-idp.${stack.region}.amazonaws.com/${userPool.userPoolId}`, | ||
| clientId: userPoolClient.userPoolClientId, | ||
| tokenExpiryFromAuth: Duration.hours(1), | ||
| tokenExpiryFromIssue: Duration.hours(1), | ||
| }, | ||
| }; | ||
|
|
||
| break; | ||
| } | ||
| default: { | ||
| throw new Error(`Unsupported auth mode: ${stackConfig.authMode}`); | ||
| } | ||
| } | ||
|
|
||
| return authorizationModes; | ||
| }; | ||
|
|
||
| const createTranslationBehavior = (): PartialTranslationBehavior => { | ||
| const translationBehavior: PartialTranslationBehavior = { | ||
| sandboxModeEnabled: stackConfig.useSandbox ?? false, | ||
| }; | ||
| return translationBehavior; | ||
| }; | ||
|
|
||
| const createUserPool = (prefix: string, triggers?: Record<string, string>): { userPool: UserPool; userPoolClient: UserPoolClient } => { | ||
| const userPool = new UserPool(stack, `${prefix}UserPool`, { | ||
| signInAliases: { | ||
| username: true, | ||
| email: false, | ||
| }, | ||
| selfSignUpEnabled: true, | ||
| autoVerify: { email: true }, | ||
| standardAttributes: { | ||
| email: { | ||
| required: true, | ||
| mutable: false, | ||
| }, | ||
| }, | ||
| lambdaTriggers: triggers ? createUserPoolTriggers(triggers) : {}, | ||
| }); | ||
| userPool.applyRemovalPolicy(RemovalPolicy.DESTROY); | ||
|
|
||
| stackConfig.userGroups?.forEach((group) => { | ||
| new CfnUserPoolGroup(userPool, `Group${group}`, { | ||
| userPoolId: userPool.userPoolId, | ||
| groupName: group, | ||
| }); | ||
| }); | ||
|
|
||
| const userPoolClient = userPool.addClient(`${prefix}UserPoolClient`, { | ||
| authFlows: { | ||
| userPassword: true, | ||
| userSrp: true, | ||
| }, | ||
| }); | ||
|
|
||
| new CfnOutput(stack, 'userPoolId', { value: userPool.userPoolId }); | ||
| new CfnOutput(stack, 'webClientId', { value: userPoolClient.userPoolClientId }); | ||
|
|
||
| return { userPool, userPoolClient }; | ||
| }; | ||
|
|
||
| const createUserPoolTriggers = (triggers: Record<string, string>): UserPoolTriggers => { | ||
| const userPoolTriggers: UserPoolTriggers = {}; | ||
|
|
||
| Object.keys(triggers).forEach((triggerName) => { | ||
| userPoolTriggers[triggerName] = createLambdaFunction(triggerName, triggers[triggerName]); | ||
| }); | ||
|
|
||
| return userPoolTriggers; | ||
| }; | ||
|
|
||
| const createLambdaFunction = (name: string, code: string): Function => { | ||
| return new Function(stack, `${name}Lambda`, { | ||
| runtime: Runtime.NODEJS_18_X, | ||
| handler: 'index.handler', | ||
| code: Code.fromInline(code), | ||
| }); | ||
| }; | ||
|
|
||
| const createBasicRole = () => { | ||
| const basicRole = new Role(stack, 'BasicRole', { | ||
| assumedBy: new AccountPrincipal(stack.account), | ||
| path: '/', | ||
| inlinePolicies: { | ||
| root: new PolicyDocument({ | ||
| statements: [ | ||
| new PolicyStatement({ | ||
| actions: ['logs:CreateLogGroup', 'logs:CreateLogStream', 'logs:PutLogEvents'], | ||
| resources: ['arn:aws:logs:*:*:*'], | ||
| effect: Effect.ALLOW, | ||
| }), | ||
| ], | ||
| }), | ||
| }, | ||
| }); | ||
| basicRole.applyRemovalPolicy(RemovalPolicy.DESTROY); | ||
|
|
||
| basicRole.addToPolicy( | ||
| new PolicyStatement({ | ||
| actions: ['appsync:GraphQL'], | ||
| resources: [`${api.resources.graphqlApi.arn}/*`], | ||
| effect: Effect.ALLOW, | ||
| }), | ||
| ); | ||
|
|
||
| new CfnOutput(stack, 'BasicRoleArn', { value: basicRole.roleArn }); | ||
| }; | ||
|
|
||
| const createAdditionalCfnOutputs = () => { | ||
| switch (stackConfig.authMode) { | ||
| case AUTH_MODE.API_KEY: { | ||
| const { | ||
| resources: { functions }, | ||
| } = api; | ||
| const sqlLambda = functions[`SQLFunction${dbDetails.dbConfig.strategyName}`]; | ||
|
|
||
| new CfnOutput(stack, 'SQLFunctionName', { value: sqlLambda.functionName }); | ||
| } | ||
| default: { | ||
| new CfnOutput(stack, 'GraphQLApiId', { value: api.resources.graphqlApi.apiId }); | ||
| new CfnOutput(stack, 'GraphQLApiArn', { value: api.resources.graphqlApi.arn }); | ||
| new CfnOutput(stack, 'region', { value: stack.region }); | ||
| } | ||
| } | ||
| }; | ||
|
|
||
| // #endregion Utilities | ||
|
|
||
| // #region CDK App | ||
|
|
||
| // eslint-disable-next-line @typescript-eslint/no-var-requires | ||
| const dbDetails: DBDetails = require('../db-details.json'); | ||
| const stackConfig: StackConfig = require('../stack-config.json'); | ||
|
|
||
| // eslint-disable-next-line @typescript-eslint/no-var-requires | ||
| const packageJson = require('../package.json'); | ||
|
|
||
| const app = new App(); | ||
| const stack = new Stack(app, packageJson.name.replace(/_/g, '-'), { | ||
| env: { region: process.env.CLI_REGION || 'us-west-2' }, | ||
| }); | ||
|
|
||
| const definition = createApiDefinition(); | ||
| const authorizationModes = createAuthorizationModes(); | ||
| const translationBehavior = createTranslationBehavior(); | ||
|
|
||
| const api = new AmplifyGraphqlApi(stack, `SqlBoundApi`, { | ||
| apiName: `${dbDetails.dbConfig.dbType}${Date.now()}`, | ||
| definition, | ||
| authorizationModes, | ||
| translationBehavior, | ||
| }); | ||
|
|
||
| createBasicRole(); | ||
| createAdditionalCfnOutputs(); | ||
|
|
||
| // #endregion CDK App | ||
84 changes: 0 additions & 84 deletions
84
packages/amplify-graphql-api-construct-tests/src/__tests__/backends/sql-models/app.ts
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need the API key to be valid for 2 days? Especially since we teardown these apps post test run, I would recommend setting it to 1 hr to begin with.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line 75 of file
authorization-modes.tsinamplify-graphql-api-constructenforces theDurationwould be converted to days with following definition:apiKeyExpirationDays: authMode.expires.toDays()Setting expiration to hours would cause CDK deployment to fail with error message:
We could adjust the construct time conversion if needed to give test a more tight time boundary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That might be the right way to go forward here.