diff --git a/packages/amplify-migration-tests/src/__tests__/migration_tests_v12/__snapshots__/auth-app-client-secret-migration.test.ts.snap b/packages/amplify-migration-tests/src/__tests__/migration_tests_v12/__snapshots__/auth-app-client-secret-migration.test.ts.snap new file mode 100644 index 00000000000..cd22409139c --- /dev/null +++ b/packages/amplify-migration-tests/src/__tests__/migration_tests_v12/__snapshots__/auth-app-client-secret-migration.test.ts.snap @@ -0,0 +1,69 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`amplify add auth... ...should init an Android project and add default auth 1`] = ` +"IAM Statement Changes +┌───┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬────────┬────────────────────────────────────┬───────────────────────────┬───────────┐ +│ │ Resource │ Effect │ Action │ Principal │ Condition │ +├───┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼────────┼────────────────────────────────────┼───────────────────────────┼───────────┤ +│ - │ \${UserPool.Arn} │ Allow │ cognito-idp:DescribeUserPoolClient │ AWS:\${UserPoolClientRole} │ │ +├───┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼────────┼────────────────────────────────────┼───────────────────────────┼───────────┤ +│ - │ {"Fn::Sub":["arn:aws:logs:\${region}:\${account}:log-group:/aws/lambda/\${lambda}:log-stream:*",{"region":"\${AWS::Region}","account":"\${AWS::AccountId}","lambda":"\${UserPoolClientLambda}"}]} │ Allow │ logs:CreateLogGroup │ AWS:\${UserPoolClientRole} │ │ +│ │ │ │ logs:CreateLogStream │ │ │ +│ │ │ │ logs:PutLogEvents │ │ │ +└───┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴────────┴────────────────────────────────────┴───────────────────────────┴───────────┘ +(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299) + +Conditions +[-] Condition ShouldOutputAppClientSecrets: {"Fn::Equals":[{"Ref":"userpoolClientGenerateSecret"},true]} + +Resources +[-] AWS::Lambda::Function UserPoolClientLambda destroy +[-] AWS::IAM::Policy UserPoolClientLambdaPolicy destroy +[-] AWS::IAM::Policy UserPoolClientLogPolicy destroy +[-] Custom::LambdaCallout UserPoolClientInputs destroy +[~] AWS::IAM::Role UserPoolClientRole + └─ [-] DependsOn + └─ ["UserPoolClient"] +[~] AWS::Cognito::IdentityPool IdentityPool + └─ [-] DependsOn + └─ ["UserPoolClientInputs"] + +Outputs +[-] Output AppClientSecret: {"Value":{"Fn::GetAtt":["UserPoolClientInputs","appSecret"]},"Condition":"ShouldOutputAppClientSecrets"} + +" +`; + +exports[`amplify add auth... ...should init an Android project and add default auth 2`] = ` +"IAM Statement Changes +┌───┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┬────────┬────────────────────────────────────┬───────────────────────────┬───────────┐ +│ │ Resource │ Effect │ Action │ Principal │ Condition │ +├───┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼────────┼────────────────────────────────────┼───────────────────────────┼───────────┤ +│ - │ \${UserPool.Arn} │ Allow │ cognito-idp:DescribeUserPoolClient │ AWS:\${UserPoolClientRole} │ │ +├───┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┼────────┼────────────────────────────────────┼───────────────────────────┼───────────┤ +│ - │ {"Fn::Sub":["arn:aws:logs:\${region}:\${account}:log-group:/aws/lambda/\${lambda}:log-stream:*",{"region":"\${AWS::Region}","account":"\${AWS::AccountId}","lambda":"\${UserPoolClientLambda}"}]} │ Allow │ logs:CreateLogGroup │ AWS:\${UserPoolClientRole} │ │ +│ │ │ │ logs:CreateLogStream │ │ │ +│ │ │ │ logs:PutLogEvents │ │ │ +└───┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┴────────┴────────────────────────────────────┴───────────────────────────┴───────────┘ +(NOTE: There may be security-related changes not in this list. See https://github.com/aws/aws-cdk/issues/1299) + +Conditions +[-] Condition ShouldOutputAppClientSecrets: {"Fn::Equals":[{"Ref":"userpoolClientGenerateSecret"},true]} + +Resources +[-] AWS::Lambda::Function UserPoolClientLambda destroy +[-] AWS::IAM::Policy UserPoolClientLambdaPolicy destroy +[-] AWS::IAM::Policy UserPoolClientLogPolicy destroy +[-] Custom::LambdaCallout UserPoolClientInputs destroy +[~] AWS::IAM::Role UserPoolClientRole + └─ [-] DependsOn + └─ ["UserPoolClient"] +[~] AWS::Cognito::IdentityPool IdentityPool + └─ [-] DependsOn + └─ ["UserPoolClientInputs"] + +Outputs +[-] Output AppClientSecret: {"Value":{"Fn::GetAtt":["UserPoolClientInputs","appSecret"]},"Condition":"ShouldOutputAppClientSecrets"} + +" +`; diff --git a/packages/amplify-migration-tests/src/__tests__/migration_tests_v12/auth-app-client-secret-migration.test.ts b/packages/amplify-migration-tests/src/__tests__/migration_tests_v12/auth-app-client-secret-migration.test.ts new file mode 100644 index 00000000000..841e88eeab7 --- /dev/null +++ b/packages/amplify-migration-tests/src/__tests__/migration_tests_v12/auth-app-client-secret-migration.test.ts @@ -0,0 +1,83 @@ +import { + addAuthWithDefault, + amplifyPullNonInteractive, + amplifyPushAuth, + amplifyPushForce, + createNewProjectDir, + deleteProject, + deleteProjectDir, + getAppId, + getCLIInputs, + getProjectMeta, + setCLIInputs, +} from '@aws-amplify/amplify-e2e-core'; +import { allowedVersionsToMigrateFrom, versionCheck } from '../../migration-helpers'; +import { initAndroidProjectWithProfileV12 } from '../../migration-helpers-v12/init'; +import { assertAppClientSecretInFiles, pullPushForceWithLatestCodebaseValidateParameterAndCfnDrift } from '../../migration-helpers/utils'; + +const defaultsSettings = { + name: 'authTest', + disableAmplifyAppCreation: false, +}; + +describe('amplify add auth...', () => { + let projRoot: string; + const projectName: string = 'authAppClientSecret'; + + beforeAll(async () => { + const migrateFromVersion = { v: 'uninitialized' }; + const migrateToVersion = { v: 'uninitialized' }; + await versionCheck(process.cwd(), false, migrateFromVersion); + await versionCheck(process.cwd(), true, migrateToVersion); + console.log(`Test migration from: ${migrateFromVersion.v} to ${migrateToVersion.v}`); + expect(allowedVersionsToMigrateFrom).toContain(migrateFromVersion.v); + }); + + beforeEach(async () => { + projRoot = await createNewProjectDir(projectName); + await initAndroidProjectWithProfileV12(projRoot, defaultsSettings); + await addAuthWithDefault(projRoot); + await amplifyPushAuth(projRoot); + let meta = getProjectMeta(projRoot); + let id = Object.keys(meta.auth)[0]; + // update parameter to generate client Secret + const parameters = getCLIInputs(projRoot, 'auth', id); + parameters.cognitoConfig.userpoolClientGenerateSecret = true; + setCLIInputs(projRoot, 'auth', id, parameters); + await amplifyPushAuth(projRoot); + }); + + afterEach(async () => { + await deleteProject(projRoot); + deleteProjectDir(projRoot); + }); + + it('...should init an Android project and add default auth', async () => { + // assert client secret in projRoot + await assertAppClientSecretInFiles(projRoot); + const projRoot2 = await createNewProjectDir(`${projectName}2`); + const projRoot3 = await createNewProjectDir(`${projectName}3`); + // using amplify push force here as changes are only related to build files + await pullPushForceWithLatestCodebaseValidateParameterAndCfnDrift(projRoot, projRoot2); + const appId = getAppId(projRoot); + expect(appId).toBeDefined(); + const frontendConfig = { + frontend: 'android', + config: { + ResDir: 'app/src/main/res', + }, + }; + const envName = 'integtest'; + try { + await amplifyPullNonInteractive(projRoot3, { + appId, + frontend: frontendConfig, + envName, + }); + await amplifyPushForce(projRoot3, true); + await assertAppClientSecretInFiles(projRoot3); + } finally { + deleteProjectDir(projRoot3); + } + }); +}); diff --git a/packages/amplify-migration-tests/src/migration-helpers-v12/init.ts b/packages/amplify-migration-tests/src/migration-helpers-v12/init.ts index 06470d4ac4e..a8104bb0eff 100644 --- a/packages/amplify-migration-tests/src/migration-helpers-v12/init.ts +++ b/packages/amplify-migration-tests/src/migration-helpers-v12/init.ts @@ -44,57 +44,49 @@ export function initJSProjectWithProfileV12(cwd: string, settings?: Partial 20) console.warn('Project names should not be longer than 20 characters. This may cause tests to break.'); - return new Promise((resolve, reject) => { - const chain = spawn(getCLIPath(), cliArgs, { - cwd, - stripColors: true, - env, - disableCIDetection: s.disableCIDetection, - }) - .wait('Enter a name for the project') - .sendLine(s.name) - .wait('Initialize the project with the above configuration?') - .sendConfirmNo() - .wait('Enter a name for the environment') - .sendLine(s.envName) - .wait('Choose your default editor:') - .sendLine(s.editor) - .wait("Choose the type of app that you're building") - .sendLine(s.appType) - .wait('What javascript framework are you using') - .sendLine(s.framework) - .wait('Source Directory Path:') - .sendLine(s.srcDir) - .wait('Distribution Directory Path:') - .sendLine(s.distDir) - .wait('Build Command:') - .sendLine(s.buildCmd) - .wait('Start Command:') - .sendCarriageReturn(); - - if (!providerConfigSpecified) { - chain - .wait('Using default provider awscloudformation') - .wait('Select the authentication method you want to use:') - .sendCarriageReturn() - .wait('Please choose the profile you want to use') - .sendLine(s.profileName); - } + const chain = spawn(getCLIPath(), cliArgs, { + cwd, + stripColors: true, + env, + disableCIDetection: s.disableCIDetection, + }) + .wait('Enter a name for the project') + .sendLine(s.name) + .wait('Initialize the project with the above configuration?') + .sendConfirmNo() + .wait('Enter a name for the environment') + .sendLine(s.envName) + .wait('Choose your default editor:') + .sendLine(s.editor) + .wait("Choose the type of app that you're building") + .sendLine(s.appType) + .wait('What javascript framework are you using') + .sendLine(s.framework) + .wait('Source Directory Path:') + .sendLine(s.srcDir) + .wait('Distribution Directory Path:') + .sendLine(s.distDir) + .wait('Build Command:') + .sendLine(s.buildCmd) + .wait('Start Command:') + .sendCarriageReturn(); + + if (!providerConfigSpecified) { chain - .wait('Help improve Amplify CLI by sharing non sensitive configurations on failures') - .sendYes() - .wait(/Try "amplify add api" to create a backend API and then "amplify (push|publish)" to deploy everything/) - .run((err: Error) => { - if (err) { - reject(err); - } else { - resolve(); - } - }); - }); + .wait('Using default provider awscloudformation') + .wait('Select the authentication method you want to use:') + .sendCarriageReturn() + .wait('Please choose the profile you want to use') + .sendLine(s.profileName); + } + return chain + .wait('Help improve Amplify CLI by sharing non sensitive configurations on failures') + .sendYes() + .wait(/Try "amplify add api" to create a backend API and then "amplify (push|publish)" to deploy everything/) + .runAsync(); } -export function initIosProjectWithProfile12(cwd: string, settings: Record): Promise { +export function initIosProjectWithProfileV12(cwd: string, settings: Record): Promise { const s = { ...defaultSettings, ...settings }; let env; @@ -105,36 +97,67 @@ export function initIosProjectWithProfile12(cwd: string, settings: Record { - spawn(getCLIPath(), ['init'], { - cwd, - stripColors: true, - env, - }) - .wait('Enter a name for the project') - .sendLine(s.name) - .wait('Initialize the project with the above configuration?') - .sendConfirmNo() - .wait('Enter a name for the environment') - .sendLine(s.envName) - .wait('Choose your default editor:') - .sendLine(s.editor) - .wait("Choose the type of app that you're building") - .sendKeyDown(3) - .sendCarriageReturn() - .wait('Select the authentication method you want to use:') - .sendCarriageReturn() - .wait('Please choose the profile you want to use') - .sendLine(s.profileName) - .wait('Help improve Amplify CLI by sharing non sensitive configurations on failures') - .sendYes() - .wait(/Try "amplify add api" to create a backend API and then "amplify (push|publish)" to deploy everything/) - .run((err: Error) => { - if (!err) { - resolve(); - } else { - reject(err); - } - }); - }); + return spawn(getCLIPath(), ['init'], { + cwd, + stripColors: true, + env, + }) + .wait('Enter a name for the project') + .sendLine(s.name) + .wait('Initialize the project with the above configuration?') + .sendConfirmNo() + .wait('Enter a name for the environment') + .sendLine(s.envName) + .wait('Choose your default editor:') + .sendLine(s.editor) + .wait("Choose the type of app that you're building") + .sendKeyDown(3) + .sendCarriageReturn() + .wait('Select the authentication method you want to use:') + .sendCarriageReturn() + .wait('Please choose the profile you want to use') + .sendLine(s.profileName) + .wait('Help improve Amplify CLI by sharing non sensitive configurations on failures') + .sendYes() + .wait(/Try "amplify add api" to create a backend API and then "amplify (push|publish)" to deploy everything/) + .runAsync(); +} + +export function initAndroidProjectWithProfileV12(cwd: string, settings: Partial): Promise { + const s = { ...defaultSettings, ...settings }; + + let env; + + if (s.disableAmplifyAppCreation) { + env = { + CLI_DEV_INTERNAL_DISABLE_AMPLIFY_APP_CREATION: '1', + }; + } + + return spawn(getCLIPath(), ['init'], { + cwd, + stripColors: true, + env, + }) + .wait('Enter a name for the project') + .sendLine(s.name) + .wait('Initialize the project with the above configuration?') + .sendConfirmNo() + .wait('Enter a name for the environment') + .sendLine(s.envName) + .wait('Choose your default editor:') + .sendLine(s.editor) + .wait("Choose the type of app that you're building") + .sendKeyDown(1) + .sendCarriageReturn() + .wait('Where is your Res directory') + .sendCarriageReturn() + .wait('Select the authentication method you want to use:') + .sendCarriageReturn() + .wait('Please choose the profile you want to use') + .sendLine(s.profileName) + .wait('Help improve Amplify CLI by sharing non sensitive configurations on failures') + .sendYes() + .wait(/Try "amplify add api" to create a backend API and then "amplify (push|publish)" to deploy everything/) + .runAsync(); } diff --git a/packages/amplify-migration-tests/src/migration-helpers/utils.ts b/packages/amplify-migration-tests/src/migration-helpers/utils.ts index cfd0af19027..6629022f708 100644 --- a/packages/amplify-migration-tests/src/migration-helpers/utils.ts +++ b/packages/amplify-migration-tests/src/migration-helpers/utils.ts @@ -6,7 +6,7 @@ import { createNewProjectDir, deleteProjectDir, getAppId, - getAwsIOSConfig, + getAwsAndroidConfig, getBackendConfig, getCLIInputs, getCloudFormationTemplate, @@ -197,7 +197,7 @@ export const pullPushForceWithLatestCodebaseValidateParameterAndCfnDrift = async * asserts app client secret in projects files and on cloud */ export const assertAppClientSecretInFiles = async (projRoot: string): Promise => { - const config = await getAwsIOSConfig(projRoot); + const config = await getAwsAndroidConfig(projRoot); const clientSecretInAwsIOSConfig = config.CognitoUserPool.Default.AppClientSecret; expect(clientSecretInAwsIOSConfig).toBeDefined(); const meta = getProjectMeta(projRoot); diff --git a/scripts/split-e2e-test-filters.ts b/scripts/split-e2e-test-filters.ts index f781370d8d8..3aa7c43936d 100644 --- a/scripts/split-e2e-test-filters.ts +++ b/scripts/split-e2e-test-filters.ts @@ -24,6 +24,7 @@ export const migrationFromV10Tests = [ ]; export const migrationFromV12Tests = [ 'src/__tests__/migration_tests_v12/auth.migration.test.ts', + 'src/__tests__/migration_tests_v12/auth-app-client-secret-migration.test', 'src/__tests__/migration_tests_v12/auth-lambda-callout-migration.test.ts', 'src/__tests__/migration_tests_v12/auth-lambda-callout-migration-rollback.test.ts', 'src/__tests__/migration_tests_v12/auth-oauth-lambda-migration.test.ts',