From 4c33c44a218d6f3b2920f04d0563f4b03d561916 Mon Sep 17 00:00:00 2001 From: Spencer Stolworthy Date: Thu, 1 Dec 2022 12:42:13 -0800 Subject: [PATCH 1/4] chore: remove lgtm config file --- .lgtm.yml | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 .lgtm.yml diff --git a/.lgtm.yml b/.lgtm.yml deleted file mode 100644 index efc97b118ec..00000000000 --- a/.lgtm.yml +++ /dev/null @@ -1,21 +0,0 @@ -######################################################################################### -# Use the extraction block to define changes to the default code extraction process # -# for one or more languages. The settings for each language are defined in a child # -# block, with one or more steps. # -######################################################################################### - -extraction: - # Define settings for JavaScript analysis - ########################################## - javascript: - # The `index` step extracts information from the files in the codebase. - index: - # Specify a list of glob patterns to include/exclude files from extraction; this - # is applied on top of the include/exclude paths from above; patterns are - # processed in the same way as for path classifiers above. - # Default: include all files with known extensions (such as .js, .ts and .html), - # but exclude files ending in `-min.js` or `.min.js` and folders named `node_modules` - # or `bower_components` - filters: - # exclude any *.ts files anywhere. - - exclude: "packages/amplify-category-api/resources/awscloudformation/container-templates/**/*.js" \ No newline at end of file From 68505f10c5a247aea416d587569e3045a4580c48 Mon Sep 17 00:00:00 2001 From: Danielle Adams <6271256+danielleadams@users.noreply.github.com> Date: Fri, 2 Dec 2022 15:56:22 -0500 Subject: [PATCH 2/4] fix: add fallpack for undefined env var (#11505) --- packages/amplify-e2e-core/src/utils/index.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/amplify-e2e-core/src/utils/index.ts b/packages/amplify-e2e-core/src/utils/index.ts index 901a687422f..e1981e96793 100644 --- a/packages/amplify-e2e-core/src/utils/index.ts +++ b/packages/amplify-e2e-core/src/utils/index.ts @@ -30,7 +30,8 @@ export * from './git-operations'; /** * Whether the current environment is CircleCI or not */ -export const isCI = (): boolean => process.env.CI && process.env.CIRCLECI && JSON.parse(process.env.CI) && JSON.parse(process.env.CIRCLECI); + +export const isCI = (): boolean => JSON.parse(process.env.CI || 'false') && JSON.parse(process.env.CIRCLECI || 'false'); // eslint-disable-next-line spellcheck/spell-checker export const TEST_PROFILE_NAME = isCI() ? 'amplify-integ-test-user' : 'default'; From 1ee69a4dba4adb1264ddec513ba9888c1296d7b4 Mon Sep 17 00:00:00 2001 From: Danielle Adams <6271256+danielleadams@users.noreply.github.com> Date: Fri, 2 Dec 2022 16:00:47 -0500 Subject: [PATCH 3/4] fix: add a dependsOn to custom resource for auth trigger (#11504) * fix: add a dependsOn to custom resource for auth trigger * test: add snapshot tests to show cfn changes for dependencies * fix: mock uuid lib in test --- ...enerate-auth-trigger-template.test.ts.snap | 257 ++++++++++++++++++ .../generate-auth-trigger-template.test.ts | 34 +++ .../utils/generate-auth-trigger-template.ts | 6 +- 3 files changed, 295 insertions(+), 2 deletions(-) create mode 100644 packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/generate-auth-trigger-template.test.ts.snap create mode 100644 packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/generate-auth-trigger-template.test.ts diff --git a/packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/generate-auth-trigger-template.test.ts.snap b/packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/generate-auth-trigger-template.test.ts.snap new file mode 100644 index 00000000000..1f9ae7895d7 --- /dev/null +++ b/packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/__snapshots__/generate-auth-trigger-template.test.ts.snap @@ -0,0 +1,257 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`generateNestedAuthTriggerTemplate adds "authTriggerFn" as a dependency on "CustomAuthTriggerResource" 1`] = ` +Object { + "AWSTemplateFormatVersion": "2010-09-09", + "Conditions": Object { + "ShouldNotCreateEnvResources": Object { + "Fn::Equals": Array [ + Object { + "Ref": "env", + }, + "NONE", + ], + }, + }, + "Description": "Custom Resource stack for Auth Trigger created using Amplify CLI", + "Parameters": Object { + "env": Object { + "Type": "String", + }, + "functionauthtestCustomMessageArn": Object { + "Type": "String", + }, + "functionauthtestCustomMessageName": Object { + "Type": "String", + }, + "functionauthtestostConfirmationArn": Object { + "Type": "String", + }, + "functionauthtestostConfirmationName": Object { + "Type": "String", + }, + "userpoolArn": Object { + "Type": "String", + }, + "userpoolId": Object { + "Type": "String", + }, + }, + "Resources": Object { + "CustomAuthTriggerResource": Object { + "DeletionPolicy": "Delete", + "DependsOn": Array [ + "authTriggerFn7FCFA449", + "authTriggerFnServiceRoleDefaultPolicyEC9285A8", + "authTriggerFnServiceRole08093B67", + ], + "Properties": Object { + "ServiceToken": Object { + "Fn::GetAtt": Array [ + "authTriggerFn7FCFA449", + "Arn", + ], + }, + "lambdaConfig": Array [ + Object { + "lambdaFunctionArn": Object { + "Ref": "functionauthtestCustomMessageArn", + }, + "lambdaFunctionName": "authtestCustomMessage", + "triggerType": "CustomMessage", + }, + Object { + "lambdaFunctionArn": Object { + "Ref": "functionauthtestostConfirmationArn", + }, + "lambdaFunctionName": "authtestostConfirmation", + "triggerType": "PostConfirmation", + }, + ], + "nonce": "4fd798a7-86d3-46c2-81e1-40eed9df38ec", + "userpoolId": Object { + "Ref": "userpoolId", + }, + }, + "Type": "Custom::CustomAuthTriggerResourceOutputs", + "UpdateReplacePolicy": "Delete", + }, + "UserPoolCustomMessageLambdaInvokePermission": Object { + "Properties": Object { + "Action": "lambda:InvokeFunction", + "FunctionName": Object { + "Ref": "functionauthtestCustomMessageName", + }, + "Principal": "cognito-idp.amazonaws.com", + "SourceArn": Object { + "Ref": "userpoolArn", + }, + }, + "Type": "AWS::Lambda::Permission", + }, + "UserPoolPostConfirmationLambdaInvokePermission": Object { + "Properties": Object { + "Action": "lambda:InvokeFunction", + "FunctionName": Object { + "Ref": "functionauthtestostConfirmationName", + }, + "Principal": "cognito-idp.amazonaws.com", + "SourceArn": Object { + "Ref": "userpoolArn", + }, + }, + "Type": "AWS::Lambda::Permission", + }, + "authTriggerFn7FCFA449": Object { + "DependsOn": Array [ + "authTriggerFnServiceRoleDefaultPolicyEC9285A8", + "authTriggerFnServiceRole08093B67", + ], + "Properties": Object { + "Code": Object { + "ZipFile": "const response = require('cfn-response'); +const aws = require('aws-sdk'); + +exports.handler = async function (event, context) { + const physicalResourceId = \`\${event.LogicalResourceId}-\${event.ResourceProperties.userpoolId}\`; + + try { + const userPoolId = event.ResourceProperties.userpoolId; + const lambdaConfig = event.ResourceProperties.lambdaConfig; + const config = {}; + const cognitoClient = new aws.CognitoIdentityServiceProvider(); + const userPoolConfig = await cognitoClient.describeUserPool({ UserPoolId: userPoolId }).promise(); + const userPoolParams = userPoolConfig.UserPool; + // update userPool params + + const updateUserPoolConfig = { + UserPoolId: userPoolParams.Id, + Policies: userPoolParams.Policies, + SmsVerificationMessage: userPoolParams.SmsVerificationMessage, + AccountRecoverySetting: userPoolParams.AccountRecoverySetting, + AdminCreateUserConfig: userPoolParams.AdminCreateUserConfig, + AutoVerifiedAttributes: userPoolParams.AutoVerifiedAttributes, + EmailConfiguration: userPoolParams.EmailConfiguration, + EmailVerificationMessage: userPoolParams.EmailVerificationMessage, + EmailVerificationSubject: userPoolParams.EmailVerificationSubject, + VerificationMessageTemplate: userPoolParams.VerificationMessageTemplate, + SmsAuthenticationMessage: userPoolParams.SmsAuthenticationMessage, + MfaConfiguration: userPoolParams.MfaConfiguration, + DeviceConfiguration: userPoolParams.DeviceConfiguration, + SmsConfiguration: userPoolParams.SmsConfiguration, + UserPoolTags: userPoolParams.UserPoolTags, + UserPoolAddOns: userPoolParams.UserPoolAddOns, + }; + + // removing undefined keys + Object.keys(updateUserPoolConfig).forEach(key => updateUserPoolConfig[key] === undefined && delete updateUserPoolConfig[key]); + + /*removing UnusedAccountValidityDays as deprecated + InvalidParameterException: Please use TemporaryPasswordValidityDays in PasswordPolicy instead of UnusedAccountValidityDays + */ + if (updateUserPoolConfig.AdminCreateUserConfig && updateUserPoolConfig.AdminCreateUserConfig.UnusedAccountValidityDays) { + delete updateUserPoolConfig.AdminCreateUserConfig.UnusedAccountValidityDays; + } + + lambdaConfig.forEach(lambda => (config[\`\${lambda.triggerType}\`] = lambda.lambdaFunctionArn)); + if (event.RequestType === 'Delete') { + try { + updateUserPoolConfig.LambdaConfig = {}; + const result = await cognitoClient.updateUserPool(updateUserPoolConfig).promise(); + console.log('delete response data ' + JSON.stringify(result)); + await response.send(event, context, response.SUCCESS, {}, physicalResourceId); + } catch (err) { + console.log(err.stack); + await response.send(event, context, response.FAILED, { err }, physicalResourceId); + } + } + if (event.RequestType === 'Update' || event.RequestType === 'Create') { + updateUserPoolConfig.LambdaConfig = config; + console.log(\`\${event.RequestType}: \${updateUserPoolConfig}\`); + try { + const result = await cognitoClient.updateUserPool(updateUserPoolConfig).promise(); + console.log('createOrUpdate response data ' + JSON.stringify(result)); + await response.send(event, context, response.SUCCESS, {}, physicalResourceId); + } catch (err) { + console.log(err.stack); + await response.send(event, context, response.FAILED, { err }, physicalResourceId); + } + } + } catch (err) { + console.log(err.stack); + await response.send(event, context, response.FAILED, { err }, physicalResourceId); + } +}; +", + }, + "Handler": "index.handler", + "Role": Object { + "Fn::GetAtt": Array [ + "authTriggerFnServiceRole08093B67", + "Arn", + ], + }, + "Runtime": "nodejs14.x", + }, + "Type": "AWS::Lambda::Function", + }, + "authTriggerFnServiceRole08093B67": Object { + "Properties": Object { + "AssumeRolePolicyDocument": Object { + "Statement": Array [ + Object { + "Action": "sts:AssumeRole", + "Effect": "Allow", + "Principal": Object { + "Service": "lambda.amazonaws.com", + }, + }, + ], + "Version": "2012-10-17", + }, + "ManagedPolicyArns": Array [ + Object { + "Fn::Join": Array [ + "", + Array [ + "arn:", + Object { + "Ref": "AWS::Partition", + }, + ":iam::aws:policy/service-role/AWSLambdaBasicExecutionRole", + ], + ], + }, + ], + }, + "Type": "AWS::IAM::Role", + }, + "authTriggerFnServiceRoleDefaultPolicyEC9285A8": Object { + "Properties": Object { + "PolicyDocument": Object { + "Statement": Array [ + Object { + "Action": Array [ + "cognito-idp:DescribeUserPool", + "cognito-idp:DescribeUserPoolClient", + "cognito-idp:UpdateUserPool", + "iam:PassRole", + ], + "Effect": "Allow", + "Resource": "*", + }, + ], + "Version": "2012-10-17", + }, + "PolicyName": "authTriggerFnServiceRoleDefaultPolicyEC9285A8", + "Roles": Array [ + Object { + "Ref": "authTriggerFnServiceRole08093B67", + }, + ], + }, + "Type": "AWS::IAM::Policy", + }, + }, +} +`; diff --git a/packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/generate-auth-trigger-template.test.ts b/packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/generate-auth-trigger-template.test.ts new file mode 100644 index 00000000000..9f63350e384 --- /dev/null +++ b/packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/generate-auth-trigger-template.test.ts @@ -0,0 +1,34 @@ +import { Construct } from '@aws-cdk/core'; +import { generateNestedAuthTriggerTemplate, createCustomResourceForAuthTrigger, CustomResourceAuthStack } from '../../../../provider-utils/awscloudformation/utils/generate-auth-trigger-template'; + +jest.mock('uuid', () => { + return { + v4: () => { + return '4fd798a7-86d3-46c2-81e1-40eed9df38ec'; + } + }; +}); + +describe('generateNestedAuthTriggerTemplate', () => { + it('adds "authTriggerFn" as a dependency on "CustomAuthTriggerResource"', () => { + const authTriggerConnections = [ + { + triggerType: 'CustomMessage', + lambdaFunctionName: 'authtestCustomMessage' + }, + { + triggerType: 'PostConfirmation', + lambdaFunctionName: 'authtestostConfirmation' + } + ]; + + const cfnTemplate: any = createCustomResourceForAuthTrigger(authTriggerConnections); + + expect(cfnTemplate).toMatchSnapshot(); + expect(cfnTemplate["Resources"]["CustomAuthTriggerResource"]["DependsOn"]).toEqual(expect.arrayContaining([ + "authTriggerFn7FCFA449", + "authTriggerFnServiceRoleDefaultPolicyEC9285A8", + "authTriggerFnServiceRole08093B67", + ])); + }); +}); diff --git a/packages/amplify-category-auth/src/provider-utils/awscloudformation/utils/generate-auth-trigger-template.ts b/packages/amplify-category-auth/src/provider-utils/awscloudformation/utils/generate-auth-trigger-template.ts index 709c6d98b10..a7c7dda5f9b 100644 --- a/packages/amplify-category-auth/src/provider-utils/awscloudformation/utils/generate-auth-trigger-template.ts +++ b/packages/amplify-category-auth/src/provider-utils/awscloudformation/utils/generate-auth-trigger-template.ts @@ -91,7 +91,7 @@ export const generateNestedAuthTriggerTemplate = async ( } }; -const createCustomResourceForAuthTrigger = (authTriggerConnections: AuthTriggerConnection[]): Record => { +export const createCustomResourceForAuthTrigger = (authTriggerConnections: AuthTriggerConnection[]): Record => { const stack = new CustomResourceAuthStack(undefined as unknown as Construct, 'Amplify', { description: 'Custom Resource stack for Auth Trigger created using Amplify CLI', authTriggerConnections, @@ -122,11 +122,13 @@ const createCustomResource = (stack: cdk.Stack, authTriggerConnections: AuthTrig // The custom resource that uses the provider to supply value // Passing in a nonce parameter to ensure that the custom resource is triggered on every deployment // eslint-disable-next-line no-new - new CustomResource(stack, 'CustomAuthTriggerResource', { + const customResource = new CustomResource(stack, 'CustomAuthTriggerResource', { serviceToken: authTriggerFn.functionArn, properties: { userpoolId: userpoolId.valueAsString, lambdaConfig: authTriggerConnections, nonce: uuid() }, resourceType: 'Custom::CustomAuthTriggerResourceOutputs', }); + + customResource.node.addDependency(authTriggerFn); }; const createPermissionToInvokeLambda = ( From 74d98a09550de1e0c343c6684d37bc1f02a17c9d Mon Sep 17 00:00:00 2001 From: Zachary Goldberg <117126550+goldbez@users.noreply.github.com> Date: Mon, 5 Dec 2022 10:07:40 -0800 Subject: [PATCH 4/4] fix(category-auth): prevent overwriting local changes to admin queries function (#11520) --- .../utils/synthesize-resources.test.ts | 33 ++++++++ .../utils/synthesize-resources.ts | 80 +++++++++---------- 2 files changed, 73 insertions(+), 40 deletions(-) diff --git a/packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/synthesize-resources.test.ts b/packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/synthesize-resources.test.ts index 3f01617299f..3c2ac63aef7 100644 --- a/packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/synthesize-resources.test.ts +++ b/packages/amplify-category-auth/src/__tests__/provider-utils/awscloudformation/utils/synthesize-resources.test.ts @@ -3,6 +3,8 @@ import { } from 'amplify-cli-core'; import { UserPoolGroupMetadata } from '../../../../provider-utils/awscloudformation/auth-stack-builder'; import { updateUserPoolGroups } from '../../../../provider-utils/awscloudformation/utils/synthesize-resources'; +import { createAdminAuthFunction } from '../../../../provider-utils/awscloudformation/utils/synthesize-resources'; +import * as path from 'path'; jest.mock('amplify-cli-core'); jest.mock('fs-extra'); @@ -149,3 +151,34 @@ describe('correctly updates userPool group list', () => { expectAmplifyMetaFileUpdate(); }); }); + +describe('correctly handles local overwrites', () => { + let mockContext: $TSAny; + const resourceName = 'mockResource'; + const functionName = 'mockFunctionName'; + const adminGroup = 'mockAdminGroup'; + const pathManagerMock = pathManager as jest.Mocked; + beforeEach(() => { + mockContext = { + amplify: { + copyBatch: jest.fn().mockReturnValue({}), + pathManager, + updateamplifyMetaAfterResourceAdd: jest.fn(), + }, + }; + pathManagerMock.getBackendDirPath = jest.fn().mockReturnValue('backend'); + }); + afterEach(() => jest.resetAllMocks()); + + it('ensure local backend chanes are not overwritten on amplify update auth', async () => { + const operation = 'update'; + await createAdminAuthFunction((mockContext as unknown) as $TSContext, resourceName, functionName, adminGroup, operation); + expect(mockContext.amplify.copyBatch).not.toBeCalled(); + }); + + it('ensure local backend chanes are not overwritten on amplify update auth', async () => { + const operation = 'add'; + await createAdminAuthFunction((mockContext as unknown) as $TSContext, resourceName, functionName, adminGroup, operation); + expect(mockContext.amplify.copyBatch).toBeCalled(); + }); +}); diff --git a/packages/amplify-category-auth/src/provider-utils/awscloudformation/utils/synthesize-resources.ts b/packages/amplify-category-auth/src/provider-utils/awscloudformation/utils/synthesize-resources.ts index fe4a623b7bd..09b631f5fe3 100644 --- a/packages/amplify-category-auth/src/provider-utils/awscloudformation/utils/synthesize-resources.ts +++ b/packages/amplify-category-auth/src/provider-utils/awscloudformation/utils/synthesize-resources.ts @@ -323,7 +323,7 @@ const addAdminAuth = async ( } }; -const createAdminAuthFunction = async ( +export const createAdminAuthFunction = async ( context: $TSContext, authResourceName: string, functionName: string, @@ -345,46 +345,46 @@ const createAdminAuthFunction = async ( lambdaGroupVar = 'NONE'; } - const functionProps = { - functionName: `${functionName}`, - roleName: `${functionName}LambdaRole`, - dependsOn, - authResourceName, - lambdaGroupVar, - }; - - const copyJobs = [ - { - dir: adminAuthAssetRoot, - template: 'admin-auth-app.js', - target: path.join(targetDir, 'src/app.js'), - }, - { - dir: adminAuthAssetRoot, - template: 'admin-auth-cognitoActions.js', - target: path.join(targetDir, 'src/cognitoActions.js'), - }, - { - dir: adminAuthAssetRoot, - template: 'admin-auth-index.js', - target: path.join(targetDir, 'src/index.js'), - }, - { - dir: adminAuthAssetRoot, - template: 'admin-auth-package.json', - target: path.join(targetDir, 'src/package.json'), - }, - { - dir: adminAuthAssetRoot, - template: 'admin-queries-function-template.json.ejs', - target: path.join(targetDir, `${functionName}-cloudformation-template.json`), - }, - ]; - - // copy over the files - await context.amplify.copyBatch(context, copyJobs, functionProps, true); - if (operation === 'add') { + const functionProps = { + functionName: `${functionName}`, + roleName: `${functionName}LambdaRole`, + dependsOn, + authResourceName, + lambdaGroupVar, + }; + + const copyJobs = [ + { + dir: adminAuthAssetRoot, + template: 'admin-auth-app.js', + target: path.join(targetDir, 'src/app.js'), + }, + { + dir: adminAuthAssetRoot, + template: 'admin-auth-cognitoActions.js', + target: path.join(targetDir, 'src/cognitoActions.js'), + }, + { + dir: adminAuthAssetRoot, + template: 'admin-auth-index.js', + target: path.join(targetDir, 'src/index.js'), + }, + { + dir: adminAuthAssetRoot, + template: 'admin-auth-package.json', + target: path.join(targetDir, 'src/package.json'), + }, + { + dir: adminAuthAssetRoot, + template: 'admin-queries-function-template.json.ejs', + target: path.join(targetDir, `${functionName}-cloudformation-template.json`), + }, + ]; + + // copy over the files + await context.amplify.copyBatch(context, copyJobs, functionProps, true); + // add amplify-meta and backend-config const backendConfigs = { service: AmplifySupportedService.LAMBDA,