Skip to content

feat(project): implement safe CDK deployment - #2058

Merged
notgitika merged 5 commits into
refactorfrom
feat/project-deploy-implementation
Aug 24, 2026
Merged

feat(project): implement safe CDK deployment#2058
notgitika merged 5 commits into
refactorfrom
feat/project-deploy-implementation

Conversation

@notgitika

@notgitika notgitika commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Summary

  • resolve and validate one deployment target before backend dispatch
  • resolve one CDK CLI-compatible credential provider and share it across STS, CloudFormation, and Toolkit operations
  • reject credentials for the wrong AWS account before synthesis or mutation
  • synthesize to a fixed assembly directory and select exactly one tagged stack
  • bootstrap only absent or stably outdated environments, propagating unsafe and ambiguous states
  • deploy through the backend-local Toolkit adapter and return stack outputs
  • embed and clean up the Toolkit bootstrap template for standalone executables

Known gap: projects that declare credentials

This PR deploys the stack; it does not run the pre-deploy identity setup, so it does
not write agentcore/.cli/deployed-state.json. Nothing on refactor writes that file
today, so this is a gap being carried forward rather than a regression, but it is worth
stating rather than leaving implied:

  • Projects with no credentials and no payments deploy correctly. credentials is
    read as undefined by the vended app (src/assets/cdk/bin/cdk.ts:150), which is the
    same value it sees today.
  • A project that declares an api-key or OAuth credential deploys and reports success,
    but the declaration is silently dropped: no credential resource appears in the template
    and no provider is created. Measured on a real deploy from this branch — the deploy
    exits 0, the template contains only the runtime, role, policy, metadata and SSM
    parameter, and identity api-key-credential-provider get answers
    ApiKeyCredentialProvider not found. Since credentials is undefined on refactor
    too, this is inherited behavior, not something this PR introduces.
  • A project that declares a payment connector fails during synth, because the vended
    app requires a credentialProviderArn per connector (cdk.ts:177-186). Its error
    message also names agentcore deploy, which does not exist on this branch.

Provisioning credential providers, syncing their client secrets, and writing that state
file is a change of comparable size to this PR and lands next to two open provider
lifecycle bugs (#1673, #2022), so it is the immediate follow-up rather than part of the
deploy spine. That follow-up is now open as #2089, which turns the silent drop into a
created provider and the payment case into an accurate error, verified end-to-end against
a real account.

Stack

This is PR 4 of 4 decomposing #2001 and is the first PR in the stack that activates deployment. Review and merge bottom-up.

  1. refactor(project): move build behind a project backend #2055 - backend build boundary
  2. feat(project): add deploy command contract #2056 - deploy command contract
  3. feat(project): add CDK Toolkit adapter #2057 - CDK Toolkit adapter
  4. feat(project): implement safe CDK deployment #2058 - safe deployment implementation (this PR)

Follow-ups

typecheck, lint, format, test all pass
did npm bundle and standalone executable smoke tests

@github-actions github-actions Bot added the size/xl PR size: XL label Aug 20, 2026
@github-actions github-actions Bot added agentcore-harness-reviewing AgentCore Harness review in progress size/xl PR size: XL and removed size/xl PR size: XL agentcore-harness-reviewing AgentCore Harness review in progress labels Aug 20, 2026
@notgitika
notgitika force-pushed the feat/project-deploy-implementation branch from e34662d to c843d80 Compare August 20, 2026 04:19
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Aug 20, 2026
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Aug 20, 2026
@notgitika
notgitika marked this pull request as ready for review August 20, 2026 04:24
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Aug 20, 2026
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Aug 20, 2026
@notgitika
notgitika force-pushed the feat/project-deploy-implementation branch from c76b638 to 8ea3f87 Compare August 20, 2026 17:06
@github-actions github-actions Bot removed the size/xl PR size: XL label Aug 20, 2026
@notgitika
notgitika force-pushed the feat/project-deploy-implementation branch from 8fc3679 to f3c270c Compare August 21, 2026 17:43
@notgitika
notgitika force-pushed the feat/project-deploy-implementation branch from f3c270c to 9168096 Compare August 21, 2026 18:13
@notgitika
notgitika force-pushed the feat/project-deploy-implementation branch from 9168096 to 9d9e7f6 Compare August 21, 2026 18:21
@notgitika
notgitika force-pushed the feat/project-deploy-implementation branch from 9d9e7f6 to c715bfd Compare August 24, 2026 15:10
@notgitika
notgitika force-pushed the feat/project-deploy-implementation branch from 8484de4 to 1ab4382 Compare August 24, 2026 16:01
Base automatically changed from feat/project-cdk-toolkit to refactor August 24, 2026 17:18
@tejaskash
tejaskash force-pushed the feat/project-deploy-implementation branch from 1ab4382 to a04f19b Compare August 24, 2026 17:18
);
}

yield* this.build(project);

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.

Could we do the identity setup before synthesizing here? The generated CDK app reads agentcore/.cli/deployed-state.json during synth to resolve configured credential names to provider ARNs, but this path never creates or updates those providers, syncs their secrets, or writes the target state. On a first deploy, payment projects fail synthesis because the ARN is missing, and other resources can carry a name for a provider that does not exist. We need to provision the configured credentials and persist their target state before calling build().

@notgitika notgitika Aug 24, 2026

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.

you are correct but the intention was to keep it out of this PR as to not inflate it for ease of review.

it will be done in a follow up right after this is merged. would you rather me do an interim fix that fails fast on specs containing creds?

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.

Nopem, good for now. I would structure it as a post-deploy hook. Credentials are now created by CDK so the post-deploy hook will simply update the credential.

Comment thread scripts/build.ts
…emplate

loadBootstrapTemplate() returned undefined both when there is nothing
embedded and when the embed is missing from a standalone binary. The first
case is fine: scripts and the npm bundle have node_modules, so the Toolkit
reads the template from its own package. The second is not. A binary has no
node_modules, and the Toolkit resolves its package directory from a
__dirname that Bun rewrote to the build machine's path, so the user sees
"Unable to find package manifest" rather than anything about bootstrapping.

Treat other embedded files as proof this is a binary and fail with a message
that names the missing file.
Bun appends .exe to a Windows executable whose outfile carries no
extension, so the emitted path was never the one we asked for. The embed
assertion then read the extensionless path and failed with ENOENT, which
is what turned the Windows build red. The CI smoke test already expects
agentcore-windows-x64.exe, so build.ts was the only place disagreeing.

Derived from the target rather than hardcoded, since `bun run compile`
also builds windows-arm64, which CI does not smoke test.
@tejaskash
tejaskash force-pushed the feat/project-deploy-implementation branch from 1819c84 to 04663bf Compare August 24, 2026 18:13

@tejaskash tejaskash left a comment

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.

Approving with the credentials followup

@@ -104,7 +195,7 @@ export async function performCdkOperation(
// deletion a successful deploy.
if (result.stacks.length !== 1) {

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.

We're running this check after toolkit.deploy() deletes an existing stack with no resources. Should we validate the template has resources before invoking toolkit deploy?

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.

I think it does, good catch. let me check to see if i can recreate this. if i can, lemme push in a fix here itself

Comment thread src/core/project/backends/cdk/assembly.ts
@notgitika

Copy link
Copy Markdown
Contributor Author

good comments, I am raising a follow up addressing the 3 comments

@notgitika
notgitika merged commit 768ef10 into refactor Aug 24, 2026
14 checks passed
@notgitika
notgitika deleted the feat/project-deploy-implementation branch August 24, 2026 19:39
notgitika added a commit that referenced this pull request Aug 24, 2026
Two review findings from #2058, both cases of deploy trusting something it
had not checked.

A synthesized template with no resources makes the CDK Toolkit *delete* an
existing stack of that name and return as though it deployed. #2058 caught
that after the fact, by which point the stack was already gone. Check the
resource count before handing the assembly to the Toolkit instead.

Stack selection matched on the target-name tag alone, never on the account
and region the artifact was synthesized for. Those derive from the same
target today and so cannot disagree, but nothing enforced it, and the
Toolkit deploys where the artifact's environment points rather than where
the tag says. Both fields were also being stripped on read, since the
manifest schema declared neither.

stackArtifactIdForTarget becomes stackArtifactForTarget, returning the
template path alongside the id so the resource check needs no second read
of the manifest.
notgitika added a commit that referenced this pull request Aug 24, 2026
Two review findings from #2058, both cases of deploy trusting something it
had not checked.

A synthesized template with no resources makes the CDK Toolkit *delete* an
existing stack of that name and return as though it deployed. #2058 caught
that after the fact, by which point the stack was already gone. Check the
resource count before handing the assembly to the Toolkit instead.

Stack selection matched on the target-name tag alone, never on the account
and region the artifact was synthesized for. Those derive from the same
target today and so cannot disagree, but nothing enforced it, and the
Toolkit deploys where the artifact's environment points rather than where
the tag says. Both fields were also being stripped on read, since the
manifest schema declared neither.

stackArtifactIdForTarget becomes stackArtifactForTarget, returning the
template path alongside the id so the resource check needs no second read
of the manifest.
notgitika added a commit that referenced this pull request Aug 25, 2026
Two review findings from #2058, both cases of deploy trusting something it
had not checked.

A synthesized template with no resources makes the CDK Toolkit *delete* an
existing stack of that name and return as though it deployed. #2058 caught
that after the fact, by which point the stack was already gone. Check the
resource count before handing the assembly to the Toolkit instead.

Stack selection matched on the target-name tag alone, never on the account
and region the artifact was synthesized for. Those derive from the same
target today and so cannot disagree, but nothing enforced it, and the
Toolkit deploys where the artifact's environment points rather than where
the tag says. Both fields were also being stripped on read, since the
manifest schema declared neither.

stackArtifactIdForTarget becomes stackArtifactForTarget, returning the
template path alongside the id so the resource check needs no second read
of the manifest.
notgitika added a commit that referenced this pull request Aug 27, 2026
Two review findings from #2058, both cases of deploy trusting something it
had not checked.

A synthesized template with no resources makes the CDK Toolkit *delete* an
existing stack of that name and return as though it deployed. #2058 caught
that after the fact, by which point the stack was already gone. Check the
resource count before handing the assembly to the Toolkit instead.

Stack selection matched on the target-name tag alone, never on the account
and region the artifact was synthesized for. Those derive from the same
target today and so cannot disagree, but nothing enforced it, and the
Toolkit deploys where the artifact's environment points rather than where
the tag says. Both fields were also being stripped on read, since the
manifest schema declared neither.

stackArtifactIdForTarget becomes stackArtifactForTarget, returning the
template path alongside the id so the resource check needs no second read
of the manifest.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/xl PR size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants