Skip to content

chore: use org child accounts with existing e2e test infra#14842

Merged
iliapolo merged 8 commits intodevfrom
iankhou-gen2-migration-child-accounts
May 7, 2026
Merged

chore: use org child accounts with existing e2e test infra#14842
iliapolo merged 8 commits intodevfrom
iankhou-gen2-migration-child-accounts

Conversation

@iankhou
Copy link
Copy Markdown
Contributor

@iankhou iankhou commented Apr 30, 2026

Description of changes

Previously, gen2-migration E2E tests were hardcoded as 8 individual jobs in e2e_workflow_base.yml using a custom buildspec. They deployed Amplify apps and ran the migration in a single account and region. They now run through the same split-and-execute pipeline as regular E2E tests — the split script auto-generates one CodeBuild job per migration app. The tests now run across multiple child accounts and regions. Adding a new migration app means adding a test file, not editing YAML.

Each migration app gets a Jest test file in amplify-e2e-tests/src/__tests__/gen2-migration/ that calls App.migrate() directly in-process.

E2E flow

sequenceDiagram
    participant CB as CodeBuild Job
    participant Shell as _runE2ETestsLinux
    participant Jest as Jest test
    participant App as App.migrate()
    participant CM as CredentialManager
    participant STS as AWS STS

    CB->>Shell: source shared-scripts.sh && _runE2ETestsLinux
    Shell->>Shell: setAwsAccountCredentials → useChildAccountCredentials
    Note over Shell: Picks random child account X<br/>Sets AWS_ACCESS_KEY_ID/SECRET/TOKEN in env
    Shell->>Jest: yarn e2e (runs migration test file)
    Jest->>Jest: resolveChildAccountId()<br/>STS GetCallerIdentity → account X
    Jest->>Jest: process.env.CHILD_ACCOUNT_ID = X
    Jest->>App: new App(appName, undefined)
    App->>CM: CredentialManager reads CHILD_ACCOUNT_ID = X
    App->>CM: refreshCredentials()
    CM->>STS: fromContainerMetadata() → TEST_ACCOUNT_ROLE (parent)
    STS-->>CM: Parent session
    CM->>STS: Parent → OrganizationAccountAccessRole (account X)
    STS-->>CM: Child session (account X)
    CM->>CM: Write to migration profile (account X)
    Note over App: getEnv() strips AWS credential env vars<br/>so subprocesses use only the profile
    App->>App: amplify init/push (uses migration profile → account X)
    App->>App: cdk bootstrap / ampx sandbox (uses migration profile → account X)
    App-->>Jest: migrate() resolves
    Jest->>App: app.getClientConfig()
    App-->>Jest: { credentials: fromIni({ profile }) }
    Jest->>Jest: new Teardown(name, clientConfig).clean()
Loading

Key design decisions

Single account for Gen1 and Gen2: resolveChildAccountId() reads the account from the shell-level env vars (via STS GetCallerIdentity). The CredentialManager then assumes into that same account. This ensures Gen1 commands and Gen2 commands target the same account — the DynamoDB tables created by amplify push are found by ampx sandbox.

getEnv() strips credential env vars: Without this, the AWS CLI and CDK prefer env var credentials over AWS_PROFILE, causing operations to run in the wrong account (the shell-level account instead of the profile account).

fromContainerMetadata() for hop 1: The CredentialManager explicitly uses container metadata credentials for the first hop, bypassing any env var credentials. This lets it refresh mid-run without depending on the shell-level session.

Teardown accepts client config: Teardown now takes a clientConfig object (from App.getClientConfig()) instead of a profile string. This reuses the same credential provider that worked throughout the migration, avoiding issues where fromIni can't resolve a freshly-written profile.

Changes

  • 8 Jest test files in amplify-e2e-tests/src/__tests__/gen2-migration/, one per app, plus a shared helper
  • Split script makes a second splitTestsV3 call for migration tests (isMigration=true, BUILD_GENERAL1_LARGE, DISABLE_COVERAGE=1)
  • Removed 8 hardcoded migrate_* jobs from e2e_workflow_base.yml
  • Deleted codebuild_specs/run_gen2_migration_e2e.yml and the _runGen2MigrationE2E/runGen2MigrationE2eTestCb shell functions from shared-scripts.sh
  • CredentialManager.refresh() now uses fromContainerMetadata() explicitly instead of the default provider chain
  • App.getEnv() strips credential env vars so subprocesses use only the profile
  • Teardown constructor accepts a client config object instead of a profile string
  • nexpect non-zero exit code errors now include the last 20 lines of process output; updated 3 test assertions from exact match to substring match

Issue #, if available

Description of how you validated changes

  • Ran the split script and verified generated YAML contains 8 migration jobs with correct buildspec, compute type (BUILD_GENERAL1_LARGE), and DISABLE_COVERAGE=1
  • Verified regular E2E jobs don't include gen2-migration test files
  • Ran migration E2E in CodeBuild — confirmed Gen1 push and Gen2 sandbox deploy target the same account, frontend tests pass end-to-end (project-boards, mood-board both passed)
  • Verified the nexpect error message improvement shows CLI output in test failures
  • Confirmed the hosting test assertion fix (toContain instead of toEqual) passes

Checklist

  • PR description included
  • yarn test passes
  • Tests are changed or added
  • Relevant documentation is changed or added (and PR referenced)
  • New AWS SDK calls or CloudFormation actions have been added to relevant test and service IAM policies
  • Pull request labels are added

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@iankhou iankhou requested a review from a team as a code owner April 30, 2026 23:16
@iankhou iankhou marked this pull request as draft May 1, 2026 14:45
@iankhou iankhou force-pushed the iankhou-gen2-migration-child-accounts branch from eefbe59 to 389ebc6 Compare May 1, 2026 17:51
@iankhou iankhou changed the title chore: use org child accounts and nexpect error exposure chore: use org child accounts with existing e2e test infra, and nexpect error exposure May 1, 2026
@iankhou iankhou marked this pull request as ready for review May 1, 2026 17:55
@iliapolo
Copy link
Copy Markdown
Contributor

iliapolo commented May 1, 2026

that shells out to the existing migration CLI. A shared helper handles the credential handoff: it reads the child account ID from the current STS identity, strips AWS_ACCESS_KEY_ID/SECRET/TOKEN from the subprocess env via extendEnv: false, and passes CHILD_ACCOUNT_ID so the migration CLI's CredentialManager can perform its two-hop assume-role chain from long-lived CodeBuild container credentials.

I think we can make it simpler. We shouldn't need to shell out from typescript to typescript. Can the jest wrapper just call app.migrate()? You also wouldn't need any custom STS handoff since its all in the same process and I believe the standard E2Es already have a mechanism for credentials refresh.

app.migrate can accept an optional credentials refresher function that it will run at the start of each step.

@iankhou iankhou force-pushed the iankhou-gen2-migration-child-accounts branch from 674e522 to 7222393 Compare May 4, 2026 20:29
@iankhou iankhou changed the title chore: use org child accounts with existing e2e test infra, and nexpect error exposure chore: use org child accounts with existing e2e test infra May 4, 2026
@iankhou
Copy link
Copy Markdown
Contributor Author

iankhou commented May 4, 2026

that shells out to the existing migration CLI. A shared helper handles the credential handoff: it reads the child account ID from the current STS identity, strips AWS_ACCESS_KEY_ID/SECRET/TOKEN from the subprocess env via extendEnv: false, and passes CHILD_ACCOUNT_ID so the migration CLI's CredentialManager can perform its two-hop assume-role chain from long-lived CodeBuild container credentials.

I think we can make it simpler. We shouldn't need to shell out from typescript to typescript. Can the jest wrapper just call app.migrate()? You also wouldn't need any custom STS handoff since its all in the same process and I believe the standard E2Es already have a mechanism for credentials refresh.

app.migrate can accept an optional credentials refresher function that it will run at the start of each step.

Existing E2Es do not have a way to refresh credentials for org child accounts, only for the org parent account. Since we are running long-running tests on the child accounts, we need another mechanism for two-hop creds refresh.

If we used the existing one, we would need to only run gen2-migration tests on a single account, which we have decided not to do.

@iankhou iankhou force-pushed the iankhou-gen2-migration-child-accounts branch from d498286 to bc0f53b Compare May 7, 2026 16:42
Comment thread scripts/split-e2e-tests-codebuild.ts Outdated
@iankhou iankhou force-pushed the iankhou-gen2-migration-child-accounts branch from fb0280a to 05ff875 Compare May 7, 2026 19:07
@iliapolo iliapolo enabled auto-merge (squash) May 7, 2026 20:22
@iliapolo iliapolo merged commit 3720d62 into dev May 7, 2026
5 of 6 checks passed
@iliapolo iliapolo deleted the iankhou-gen2-migration-child-accounts branch May 7, 2026 21:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants