fix: select deployed target's stack at Persist instead of stackNames[0]#1612
Conversation
The vended CDK app synthesizes one stack per target in aws-targets.json, so synthResult.stackNames contains every target's stack. The deploy flow used stackNames[0] for the deployability check and the Persist step (getStackOutputs / buildDeployedState), while deploy/diff correctly used toStackName(project, target). When --target was not first in aws-targets.json, Persist described the wrong (often undeployed) stack and failed with "Stack <first-target> does not exist", leaving AWS resources live with an empty deployed-state.json. Add a pure selectTargetStack(stackNames, project, target) that matches the deterministic toStackName, making selection ordering-independent, and make that stack name authoritative for the deployability check (now scoped to the single stack), diff, deploy, and Persist. Remove the redundant targetStackName. Verified end-to-end on CloudFormation: deploy --target qa (qa second in aws-targets.json) failed at Persist before the fix and succeeds after, recording deployed-state under qa.
|
Claude Security Review: no high-confidence findings. (run) |
Package TarballHow to installgh release download pr-1612-tarball --repo aws/agentcore-cli --pattern "*.tgz" --dir /tmp/pr-tarball
npm install -g /tmp/pr-tarball/aws-agentcore-0.20.2.tgz |
agentcore-cli-automation
left a comment
There was a problem hiding this comment.
LGTM — narrow, well-targeted bug fix.
A few things I checked and liked:
-
Correctness of the selection logic.
selectTargetStackmatches against the deterministictoStackName(project, target)fromimport-utils.ts(lines 298–300), which is the same formula the vended CDK app uses insrc/assets/cdk/bin/cdk.ts(lines 19–21), so the CLI's selection stays in lockstep with synthesis (including underscore→dash normalization, covered by the test on actions.test.ts:82-85). -
Behavior change in the deployability check is the right call. Switching
checkStackDeployability(target.region, [stackName])(actions.ts:459) from the fullstackNamesarray to just the deployed target's stack means a sibling target's in-progress/failed stack can't spuriously block this deploy. The inline comment makes the intent clear. -
Threading is complete. All four downstream uses of the selected name (deployability check, diff, deploy, persist via
getStackOutputs/buildDeployedState) now consume the samestackName, and the deadtargetStackNamelocal is gone with no stragglers (grep targetStackName src/is empty). -
Tests are clean. The new
selectTargetStackcases test a pure function with real inputs — no mocking — and explicitly cover the ordering-independence regression (actions.test.ts:67-75) plus the empty-assembly and no-matching-stack failure modes. Author also reports red→green verification by reintroducingstackNames[0]. -
Scope is appropriately narrow. The TUI path's analogous
stackNames[0]inuseDeployFlow.ts:265is correctly called out as out-of-scope in the PR description, andselectTargetStackis exported so the follow-up can reuse it. Worth opening a tracking issue if one doesn't already exist.
No blocking issues.
Coverage Report
|
Description
agentcore deploy --target <name>failed at the Persist deployment state step when thetarget was not the first entry in
aws-targets.json, erroring withStack <first-target> does not exist— even though the requested target's stack deployed successfully. AWS resources wereleft running while
deployed-state.jsonwas never written (orphaned infrastructure with no localpointer for teardown/status).
Root cause. The vended CDK app (
src/assets/cdk/bin/cdk.ts) synthesizes one stack pertarget in
aws-targets.json, sosynthResult.stackNamescontains every target's stack. Thedeploy flow used
stackNames[0]for the deployability check and the Persist step(
getStackOutputs/buildDeployedState), while the deploy and diff steps correctly usedtoStackName(project, target). When the deployed--targetwasn't first in the file,stackNames[0]pointed at a different (usually undeployed) stack, soDescribeStacksat Persistthrew.
Fix. Introduce a pure
selectTargetStack(stackNames, projectName, targetName)that matches thedeterministic
toStackName(project, target)against the synthesized stacks — making selectionordering-independent — and returns a clear
ValidationError(naming the synthesized stacks andthe expected one) if the target's stack is absent. That selected stack name is now authoritative for
the deployability check (scoped to the single stack instead of looping
DescribeStacksover everytarget), diff, deploy, and Persist. The redundant
targetStackNamelocal is removed.Single-target projects are unaffected (where
stackNames[0]happened to already be the right stack).Scope note (for reviewers)
This fixes the CLI deploy path (
handleDeploy). The TUI deploy path (useDeployFlow.ts)has a separate, related multi-target limitation — it has no
--targetselector (the--targetflag always routes to the CLI path), always uses
awsTargets[0]/stackNames[0](which are mutuallyconsistent, so it is not the same cross-mismatch bug), and persists state for only the first of N
deployed targets. That is intentionally out of scope here and should be tracked as a follow-up;
the new
selectTargetStackis exported so it can be reused there.Related Issue
No existing GitHub issue. Reported via internal feedback:
9013745d-b4aa-4b20-a1ca-e03fa712ffbfV2260713830Documentation PR
N/A — bug fix, no user-facing documentation change.
Type of Change
Testing
How have you tested the change?
npm run test:unitandnpm run test:integnpm run typechecknpm run lintsrc/assets/, I rannpm run test:update-snapshotsand committed the updated snapshots — N/A,src/assets/not modifiedUnit (
selectTargetStack) — 6 cases: ordering (--target qawith qa first vs. second),single-target, underscore normalization, empty assembly, and target-with-no-matching-stack. Verified
red→green by reintroducing
stackNames[0](the ordering tests fail) and reverting (they pass).Full suites: unit 5415 passed, integ 310 passed, typecheck clean, lint 0 errors.
End-to-end on live CloudFormation (us-east-1) with a 2-target project
(
defaultfirst,qasecond):main(before)deploy --target qa --yes --jsonCREATE_COMPLETE) → Persist →Stack with id AgentCore-<project>-default does not exist;deployed-state.jsonleft{"targets":{}}deploy --target qa --yes --json{"success":true,"targetName":"qa","stackName":"AgentCore-<project>-qa", ...}; Persist SUCCESS;deployed-state.jsonkeyed underqa; only the qa stack created/describedAll test CloudFormation stacks and resources were torn down after verification.
Checklist
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.