Skip to content

fix(amplify-graphql-api-construct-tests): pin cdk init CLI and type e2e lambda scaffolds - #3519

Merged
Simone319 merged 1 commit into
mainfrom
fix/pin-cdk-init-cli-e2e-scaffold
Aug 3, 2026
Merged

fix(amplify-graphql-api-construct-tests): pin cdk init CLI and type e2e lambda scaffolds#3519
Simone319 merged 1 commit into
mainfrom
fix/pin-cdk-init-cli-e2e-scaffold

Conversation

@Simone319

Copy link
Copy Markdown
Contributor

Problem

Two CDK e2e groups fail deterministically (6/6 locally reproduced), on main and on every open PR:

group file error
custom_query_mutation_extension backends/custom-query-mutation-extension/authorizer.ts:1:26 TS7006 — Parameter event implicitly has an any type
admin_role backends/admin-role/apiInvoker.ts:6:51 TS2307 — Cannot find module '../../../lambda-request'

Both fail before cdk synth runs, so no stack is ever deployed.

Root cause: unpinned cdk init CLI toolchain drift

initCDKProject() in packages/amplify-graphql-api-construct-tests/src/commands.ts pins aws-cdk-lib (2.260.0) but ran cdk init with a floating CLI:

await spawn(getNpxPath(), ['cdk', 'init', 'app', '--language', 'typescript'], { ... })

The upstream TypeScript app template has since changed. Verified by running both CLIs into temp dirs:

CLI 2.179.0 (old, working) CLI 2.1134.0 (current)
cdk.json app npx ts-node --prefer-ts-exts bin/app.ts npx tsc && npx tsx bin/app.ts
typescript ~5.6.3 ~7.0.2
tsconfig include none none
strict / noImplicitAny on on

The critical change is the npx tsc && prefix. ts-node only ever compiled the import graph reachable from app.ts. npx tsc with no include glob typechecks every .ts file in the scratch project.

That matters because copyTemplateDirectory() copySyncs the whole backend directory flat into bin/. Several of those files are lambda entry points that are only ever referenced by esbuild as a path string — never imported:

const apiInvoker = new NodejsFunction(stack, 'ApiInvoker', {
  entry: path.join(__dirname, 'apiInvoker.ts'),   // <- string, not an import

So they are now typechecked from bin/, a directory they were never written to resolve from, and their relative import '../../../lambda-request' escapes the scratch project entirely.

This is pre-existing on main and unrelated to any product code.

Fix

  1. Pin the aws-cdk CLI (durable — stops the template drifting again).
    Note the CLI could not be pinned to cdkVersion: aws-cdk and aws-cdk-lib have used separate version lines since CLI v2.1000.0, so there is no aws-cdk@2.260.0 (nor aws-cdk@2.224.0) to install — and cdkVersion is legitimately 'latest' in some tests. It therefore gets its own CDK_CLI_VERSION constant.
  2. Drop the whole-project typecheck from the generated synth command, restoring the historical ts-node semantics where synth only loads the app's import graph. The runtime invocation (npx tsx bin/app.ts) is unchanged — only the npx tsc && gate is removed. This makes the scaffolder immune to any stray non-imported .ts in a backend, not just today's two.
  3. Fix the two scaffold files so they are clean even under a full typecheck:
    • authorizer.ts — type the handler event param (behavior identical).
    • apiInvoker.ts — inline the self-contained GraphqlProxiedLambdaResponse type instead of importing it from outside the bundle. All previously exported names remain exported, so admin-role.test.ts's import type { CreateTodoHandlerEvent, CreateTodoResponseData } still compiles.

Validation

Faithful local repro of initCDKProject() (pinned cdk init → copy backend flat into bin/ → rename app.ts → install additionalDependencies):

BEFORE (main)
  custom-query-mutation-extension  npx tsc exit=1
    bin/authorizer.ts(1,26): error TS7006: Parameter 'event' implicitly has an 'any' type.
  admin-role                       npx tsc exit=1
    bin/apiInvoker.ts(6,51): error TS2307: Cannot find module '../../../lambda-request'

AFTER (this branch)
  custom-query-mutation-extension  cdk.json app => npx tsx bin/<app>.ts
    zero errors in backend entry files
  admin-role                       npx tsc exit=0   (clean, whole project)
  • tsc --build tsconfig.tests.json → exit 0
  • prettier --check on all 3 changed files → clean
  • Commit passed the full husky pre-commit gate (e2e split reconciliation PASS, construct-dependency validation, license extraction)

Full e2e is CI's job — CodeBuild batches triggered on this branch.

…2e lambda scaffolds

Fixes the deterministic custom_query_mutation_extension and admin_role e2e failures.

The e2e scratch-project scaffolder pinned aws-cdk-lib but ran `npx cdk init` with a
floating CLI. The upstream template has since changed the cdk.json synth command from
`npx ts-node --prefer-ts-exts bin/app.ts` to `npx tsc && npx tsx bin/app.ts` on
TypeScript ~7.0 with strict/noImplicitAny and no tsconfig include, so synth now begins
with a whole-project typecheck of every .ts in the scratch project.

Backend templates are copied wholesale into bin/, including lambda entry points that are
only ever referenced by esbuild as a path string and never imported by app.ts. Those files
are now typechecked from a directory they were never written to resolve from, failing
before synth:
  - custom-query-mutation-extension/authorizer.ts:1:26  TS7006 (untyped event)
  - admin-role/apiInvoker.ts:6:51  TS2307 ('../../../lambda-request' escapes the project)

- Pin the aws-cdk CLI so the template cannot drift again. The CLI and aws-cdk-lib have
  used separate version lines since CLI v2.1000.0, so the CLI is pinned to its own
  constant rather than to cdkVersion (no aws-cdk release matches aws-cdk-lib 2.260.0,
  and cdkVersion may legitimately be 'latest').
- Drop the whole-project typecheck from the generated synth command, restoring the
  historical behavior where synth only loads the app's import graph. The runtime
  invocation is unchanged.
- Type the authorizer handler event, and inline the response type in apiInvoker.ts so the
  bundled lambda entry is self-contained. All previously exported names remain exported.
@Simone319

Copy link
Copy Markdown
Contributor Author

CI Status

The e2e runs for this PR are green except for the replace_2_gsis_update_attr_* GSI groups, which fail for a different, pre-existing reason that is unrelated to this change and is fixed separately in #3518.

What this PR fixes (now passing ✅): the two toolchain-drift failures caused by the unpinned cdk init CLI —

  • custom_query_mutation_extension (was bin/authorizer.ts:1:26 TS7006, implicit-any event)
  • admin_role (was bin/apiInvoker.ts:6:51 TS2307, ../../../lambda-request escaping the scratch project)

Both now pass on the pinned CLI (CDK_CLI_VERSION = 2.1134.0) plus the npx tsc && synth-prefix strip. The pr_workflow gate is green.

Remaining e2e failures — NOT caused by this PR: the replace_2_gsis_update_attr_{empty_table,single_record,1k_records,10k_records,100k_records} groups fail with a DynamoDB Custom::AmplifyDynamoDBTable UPDATE_FAILED (globalSecondaryIndexUpdates.1...provisionedThroughput.{read,write}CapacityUnits must not be null). This is a latent per-GSI provisioned-throughput defect in amplify-table-manager-handler.ts, unrelated to the e2e-scaffolding changes here. This branch is cut from main, which still contains that bug — it is fixed in #3518 and validated green there.

Once #3518 merges, these groups will pass on this branch as well. This PR should not be blocked on them.

(cleanup_e2e_resources failures are the standard allowed-failure teardown group.)

@Simone319
Simone319 marked this pull request as ready for review July 31, 2026 10:14
@Simone319
Simone319 requested a review from a team as a code owner July 31, 2026 10:14
if (typeof cdkJson.app !== 'string') {
return;
}
const appWithoutTypecheck = cdkJson.app.replace(/^\s*npx\s+tsc\s*&&\s*/, '');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

minor: Since the regex and CDK_CLI_VERSION are coupled — if someone bumps the version and the new template's synth command is slightly different (e.g. tsc --build && or no npx prefix), this silently becomes a no-op and you'd get a confusing synth failure. Might be worth adding a warning when tsc is present but the regex didn't match:

if (appWithoutTypecheck === cdkJson.app && cdkJson.app.includes('tsc')) {
  console.warn(`[initCDKProject] synth command contains 'tsc' but didn't match removal pattern: ${cdkJson.app}`);
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. Will adjust in the next PR.

@Simone319
Simone319 enabled auto-merge (squash) August 3, 2026 12:53
@Simone319
Simone319 disabled auto-merge August 3, 2026 12:54
@Simone319
Simone319 merged commit 2c2f531 into main Aug 3, 2026
7 of 8 checks passed
@Simone319
Simone319 deleted the fix/pin-cdk-init-cli-e2e-scaffold branch August 3, 2026 12:54
Simone319 added a commit that referenced this pull request Aug 3, 2026
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