Skip to content

Commit 57ee733

Browse files
authored
Remove inline container build from vended cdk-stack.ts (#954)
* Remove DockerImageAsset from vended cdk-stack.ts Container image building is now handled by AgentCoreHarnessEnvironment inside the L3 CDK construct via CodeBuild, matching the runtime pattern. The vended stack no longer needs DockerImageAsset, the toPascalId helper, or the per-harness build loop. Update snapshot to match. * Support both old and new CDK output key patterns for harness outputs The new AgentCoreHarnessEnvironment construct nests AgentCoreHarnessRole under a 'Role' child, which changes the CDK output key from ApplicationHarness<Name>RoleArnOutput to ApplicationHarness<Name>Role RoleArnOutput. Similarly, the container URI output moves from a stack- level Harness<Name>ContainerUri key to ApplicationHarness<Name>ImageUri. Update both resolvers to try the new pattern first, falling back to the old pattern for backward compatibility with existing stacks that haven't upgraded their CDK constructs. * Align vended CDK field names with HarnessRoleConfig interface The preview branch renamed dockerfile→dockerfileName and codeLocation→harnessDir, but the CDK construct's HarnessRoleConfig still uses dockerfile and codeLocation. Without matching field names, AgentCoreHarnessEnvironment never sees the dockerfile and skips the CodeBuild container build entirely. * Add tests for new AgentCoreHarnessEnvironment CDK output key patterns * fix(harness): include Dockerfile content in config hash Editing a Dockerfile no longer silently keeps the old container image live after redeploy. `computeHarnessHash` now reads and hashes the Dockerfile (by name from `harnessSpec.dockerfile`) alongside `harness.json` and `system-prompt.md`, so any content change produces a new hash and triggers a real update. * Address review: comment on prefix ordering + precedence tests for dual-key resolution
1 parent 398dc50 commit 57ee733

7 files changed

Lines changed: 294 additions & 103 deletions

File tree

src/assets/__tests__/__snapshots__/assets.snapshot.test.ts.snap

Lines changed: 11 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,8 @@ async function main() {
110110
memoryName?: string;
111111
containerUri?: string;
112112
hasDockerfile?: boolean;
113-
dockerfileName?: string;
114-
harnessDir?: string;
113+
dockerfile?: string;
114+
codeLocation?: string;
115115
tools?: { type: string; name: string }[];
116116
apiKeyArn?: string;
117117
}[] = [];
@@ -126,8 +126,8 @@ async function main() {
126126
memoryName: harnessSpec.memory?.name,
127127
containerUri: harnessSpec.containerUri,
128128
hasDockerfile: !!harnessSpec.dockerfile,
129-
dockerfileName: harnessSpec.dockerfile,
130-
harnessDir,
129+
dockerfile: harnessSpec.dockerfile,
130+
codeLocation: harnessSpec.dockerfile ? harnessDir : undefined,
131131
tools: harnessSpec.tools,
132132
apiKeyArn: harnessSpec.model?.apiKeyArn,
133133
});
@@ -301,10 +301,6 @@ exports[`Assets Directory Snapshots > CDK assets > cdk/cdk/lib/cdk-stack.ts shou
301301
AgentCoreMcp,
302302
type AgentCoreProjectSpec,
303303
type AgentCoreMcpSpec,
304-
ContainerSourceAssetFromPath,
305-
AgentEcrRepository,
306-
ContainerBuildProject,
307-
ContainerImageBuilder,
308304
} from '@aws/agentcore-cdk';
309305
import { CfnOutput, Stack, type StackProps } from 'aws-cdk-lib';
310306
import { Construct } from 'constructs';
@@ -315,8 +311,8 @@ export interface HarnessConfig {
315311
memoryName?: string;
316312
containerUri?: string;
317313
hasDockerfile?: boolean;
318-
dockerfileName?: string;
319-
harnessDir?: string;
314+
dockerfile?: string;
315+
codeLocation?: string;
320316
tools?: { type: string; name: string }[];
321317
apiKeyArn?: string;
322318
}
@@ -336,6 +332,10 @@ export interface AgentCoreStackProps extends StackProps {
336332
credentials?: Record<string, { credentialProviderArn: string; clientSecretArn?: string }>;
337333
/**
338334
* Harness role configurations. Each entry creates an IAM execution role for a harness.
335+
*
336+
* When \`hasDockerfile\` is true and \`codeLocation\` is provided (without an explicit
337+
* \`containerUri\`), the L3 construct builds and pushes a container image via CodeBuild
338+
* and emits its URI as a stack output for the post-CDK harness deployer.
339339
*/
340340
harnesses?: HarnessConfig[];
341341
}
@@ -355,46 +355,10 @@ export class AgentCoreStack extends Stack {
355355
356356
const { spec, mcpSpec, credentials, harnesses } = props;
357357
358-
// Build container images for harnesses that specify a dockerfile (no containerUri).
359-
// Produces CDK outputs consumed by the imperative harness deployer.
360-
const harnessesForCdk = harnesses ? [...harnesses] : [];
361-
if (harnesses) {
362-
for (let i = 0; i < harnesses.length; i++) {
363-
const h = harnesses[i]!;
364-
if (h.hasDockerfile && !h.containerUri && h.harnessDir) {
365-
const pascalName = h.name.replace(/(^|_)([a-z])/g, (_: string, __: string, c: string) => c.toUpperCase());
366-
const sourceAsset = new ContainerSourceAssetFromPath(this, \`Harness\${pascalName}SourceAsset\`, {
367-
sourcePath: h.harnessDir,
368-
});
369-
const ecrRepo = new AgentEcrRepository(this, \`Harness\${pascalName}EcrRepo\`, {
370-
projectName: spec.name,
371-
agentName: \`harness-\${h.name}\`,
372-
});
373-
const buildProject = ContainerBuildProject.getOrCreate(this);
374-
buildProject.grantPushTo(ecrRepo.repository);
375-
sourceAsset.asset.grantRead(buildProject.role);
376-
377-
const builder = new ContainerImageBuilder(this, \`Harness\${pascalName}ContainerBuild\`, {
378-
buildProject,
379-
sourceAsset,
380-
repository: ecrRepo,
381-
dockerfile: h.dockerfileName ?? 'Dockerfile',
382-
});
383-
384-
new CfnOutput(this, \`Harness\${pascalName}ContainerUriOutput\`, {
385-
value: builder.containerUri,
386-
});
387-
388-
// Pass the built containerUri to the harness role construct so it gets ECR pull permissions
389-
harnessesForCdk[i] = { ...h, containerUri: builder.containerUri };
390-
}
391-
}
392-
}
393-
394358
// Create AgentCoreApplication with all agents and harness roles
395359
this.application = new AgentCoreApplication(this, 'Application', {
396360
spec,
397-
harnesses: harnessesForCdk.length > 0 ? harnessesForCdk : undefined,
361+
harnesses: harnesses?.length ? harnesses : undefined,
398362
});
399363
400364
// Create AgentCoreMcp if there are gateways configured

src/assets/cdk/bin/cdk.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,8 +65,8 @@ async function main() {
6565
memoryName?: string;
6666
containerUri?: string;
6767
hasDockerfile?: boolean;
68-
dockerfileName?: string;
69-
harnessDir?: string;
68+
dockerfile?: string;
69+
codeLocation?: string;
7070
tools?: { type: string; name: string }[];
7171
apiKeyArn?: string;
7272
}[] = [];
@@ -81,8 +81,8 @@ async function main() {
8181
memoryName: harnessSpec.memory?.name,
8282
containerUri: harnessSpec.containerUri,
8383
hasDockerfile: !!harnessSpec.dockerfile,
84-
dockerfileName: harnessSpec.dockerfile,
85-
harnessDir,
84+
dockerfile: harnessSpec.dockerfile,
85+
codeLocation: harnessSpec.dockerfile ? harnessDir : undefined,
8686
tools: harnessSpec.tools,
8787
apiKeyArn: harnessSpec.model?.apiKeyArn,
8888
});

src/assets/cdk/lib/cdk-stack.ts

Lines changed: 7 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,6 @@ import {
33
AgentCoreMcp,
44
type AgentCoreProjectSpec,
55
type AgentCoreMcpSpec,
6-
ContainerSourceAssetFromPath,
7-
AgentEcrRepository,
8-
ContainerBuildProject,
9-
ContainerImageBuilder,
106
} from '@aws/agentcore-cdk';
117
import { CfnOutput, Stack, type StackProps } from 'aws-cdk-lib';
128
import { Construct } from 'constructs';
@@ -17,8 +13,8 @@ export interface HarnessConfig {
1713
memoryName?: string;
1814
containerUri?: string;
1915
hasDockerfile?: boolean;
20-
dockerfileName?: string;
21-
harnessDir?: string;
16+
dockerfile?: string;
17+
codeLocation?: string;
2218
tools?: { type: string; name: string }[];
2319
apiKeyArn?: string;
2420
}
@@ -38,6 +34,10 @@ export interface AgentCoreStackProps extends StackProps {
3834
credentials?: Record<string, { credentialProviderArn: string; clientSecretArn?: string }>;
3935
/**
4036
* Harness role configurations. Each entry creates an IAM execution role for a harness.
37+
*
38+
* When `hasDockerfile` is true and `codeLocation` is provided (without an explicit
39+
* `containerUri`), the L3 construct builds and pushes a container image via CodeBuild
40+
* and emits its URI as a stack output for the post-CDK harness deployer.
4141
*/
4242
harnesses?: HarnessConfig[];
4343
}
@@ -57,46 +57,10 @@ export class AgentCoreStack extends Stack {
5757

5858
const { spec, mcpSpec, credentials, harnesses } = props;
5959

60-
// Build container images for harnesses that specify a dockerfile (no containerUri).
61-
// Produces CDK outputs consumed by the imperative harness deployer.
62-
const harnessesForCdk = harnesses ? [...harnesses] : [];
63-
if (harnesses) {
64-
for (let i = 0; i < harnesses.length; i++) {
65-
const h = harnesses[i]!;
66-
if (h.hasDockerfile && !h.containerUri && h.harnessDir) {
67-
const pascalName = h.name.replace(/(^|_)([a-z])/g, (_: string, __: string, c: string) => c.toUpperCase());
68-
const sourceAsset = new ContainerSourceAssetFromPath(this, `Harness${pascalName}SourceAsset`, {
69-
sourcePath: h.harnessDir,
70-
});
71-
const ecrRepo = new AgentEcrRepository(this, `Harness${pascalName}EcrRepo`, {
72-
projectName: spec.name,
73-
agentName: `harness-${h.name}`,
74-
});
75-
const buildProject = ContainerBuildProject.getOrCreate(this);
76-
buildProject.grantPushTo(ecrRepo.repository);
77-
sourceAsset.asset.grantRead(buildProject.role);
78-
79-
const builder = new ContainerImageBuilder(this, `Harness${pascalName}ContainerBuild`, {
80-
buildProject,
81-
sourceAsset,
82-
repository: ecrRepo,
83-
dockerfile: h.dockerfileName ?? 'Dockerfile',
84-
});
85-
86-
new CfnOutput(this, `Harness${pascalName}ContainerUriOutput`, {
87-
value: builder.containerUri,
88-
});
89-
90-
// Pass the built containerUri to the harness role construct so it gets ECR pull permissions
91-
harnessesForCdk[i] = { ...h, containerUri: builder.containerUri };
92-
}
93-
}
94-
}
95-
9660
// Create AgentCoreApplication with all agents and harness roles
9761
this.application = new AgentCoreApplication(this, 'Application', {
9862
spec,
99-
harnesses: harnessesForCdk.length > 0 ? harnessesForCdk : undefined,
63+
harnesses: harnesses?.length ? harnesses : undefined,
10064
});
10165

10266
// Create AgentCoreMcp if there are gateways configured

0 commit comments

Comments
 (0)