@aws/nx-plugin 1.0.0-rc.91 → 1.0.0-rc.92

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/migrations.json +6 -1
  2. package/package.json +1 -1
  3. package/src/internal/test-matrix/generator.js +28 -0
  4. package/src/internal/test-matrix/generator.js.map +1 -1
  5. package/src/migrations/latest/react-website-unique-dev-ports/metadata.json +3 -0
  6. package/src/migrations/latest/react-website-unique-dev-ports/migration.d.ts +6 -0
  7. package/src/migrations/latest/react-website-unique-dev-ports/migration.js +79 -0
  8. package/src/migrations/latest/react-website-unique-dev-ports/migration.js.map +1 -0
  9. package/src/py/agent/__snapshots__/generator.protocols.spec.ts.snap +90 -115
  10. package/src/py/agent/files/package/main.py.template +13 -0
  11. package/src/py/agent/generator.d.ts +6 -1
  12. package/src/py/agent/generator.js +82 -45
  13. package/src/py/agent/generator.js.map +1 -1
  14. package/src/py/agent/schema.d.js.map +1 -1
  15. package/src/py/agent/schema.d.ts +2 -1
  16. package/src/py/agent/schema.json +2 -2
  17. package/src/py/mcp-server/__snapshots__/generator.spec.ts.snap +64 -113
  18. package/src/py/mcp-server/files/package/main.py.template +13 -0
  19. package/src/py/mcp-server/generator.d.ts +6 -1
  20. package/src/py/mcp-server/generator.js +79 -43
  21. package/src/py/mcp-server/generator.js.map +1 -1
  22. package/src/py/mcp-server/schema.d.js.map +1 -1
  23. package/src/py/mcp-server/schema.d.ts +2 -1
  24. package/src/py/mcp-server/schema.json +2 -2
  25. package/src/py/rdb/__snapshots__/generator.spec.ts.snap +12 -59
  26. package/src/ts/agent/__snapshots__/generator.spec.ts.snap +77 -114
  27. package/src/ts/agent/generator.d.ts +26 -1
  28. package/src/ts/agent/generator.js +71 -45
  29. package/src/ts/agent/generator.js.map +1 -1
  30. package/src/ts/agent/schema.d.js.map +1 -1
  31. package/src/ts/agent/schema.d.ts +2 -1
  32. package/src/ts/agent/schema.json +2 -2
  33. package/src/ts/mcp-server/__snapshots__/generator.spec.ts.snap +64 -113
  34. package/src/ts/mcp-server/generator.d.ts +26 -1
  35. package/src/ts/mcp-server/generator.js +66 -38
  36. package/src/ts/mcp-server/generator.js.map +1 -1
  37. package/src/ts/mcp-server/schema.d.js.map +1 -1
  38. package/src/ts/mcp-server/schema.d.ts +2 -1
  39. package/src/ts/mcp-server/schema.json +2 -2
  40. package/src/ts/rdb/__snapshots__/generator.spec.ts.snap +16 -110
  41. package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +2 -0
  42. package/src/ts/react-website/app/generator.js +16 -0
  43. package/src/ts/react-website/app/generator.js.map +1 -1
  44. package/src/ts/react-website/cognito-auth/generator.js +14 -2
  45. package/src/ts/react-website/cognito-auth/generator.js.map +1 -1
  46. package/src/utils/agent-core-constructs/agent-core-constructs.d.ts +25 -6
  47. package/src/utils/agent-core-constructs/agent-core-constructs.js +36 -7
  48. package/src/utils/agent-core-constructs/agent-core-constructs.js.map +1 -1
  49. package/src/utils/agent-core-constructs/files/cdk/app/agent-core/__nameKebabCase__/__nameKebabCase__.ts.template +20 -4
  50. package/src/utils/agent-core-constructs/files/terraform/app/agent-core/__nameKebabCase__/__nameKebabCase__.tf.template +34 -1
  51. package/src/utils/agent-core-constructs/files/terraform/core/agent-core/runtime.tf.template +51 -112
  52. package/src/utils/agent-core-constructs/files/terraform/core/agent-core-code/runtime.tf.template +204 -0
  53. package/src/utils/agent-core-constructs/files/terraform/core/agent-core-container/runtime.tf.template +235 -0
  54. package/src/utils/agent-core-packaging.d.ts +119 -0
  55. package/src/utils/agent-core-packaging.js +131 -0
  56. package/src/utils/agent-core-packaging.js.map +1 -0
  57. package/src/utils/agent-core-runtime-resolution.d.ts +35 -0
  58. package/src/utils/agent-core-runtime-resolution.js +68 -0
  59. package/src/utils/agent-core-runtime-resolution.js.map +1 -0
  60. package/src/utils/files/terraform/src/core/asset-ecr/asset-ecr.tf.template +137 -0
  61. package/src/utils/identity-constructs/files/cdk/core/user-identity.ts.template +1 -1
  62. package/src/utils/identity-constructs/files/terraform/core/user-identity/identity/identity.tf.template +1 -4
  63. package/src/utils/identity-constructs/identity-constructs.d.ts +22 -2
  64. package/src/utils/identity-constructs/identity-constructs.js +75 -5
  65. package/src/utils/identity-constructs/identity-constructs.js.map +1 -1
  66. package/src/utils/port.d.ts +5 -0
  67. package/src/utils/port.js +1 -1
  68. package/src/utils/port.js.map +1 -1
  69. package/src/utils/rdb-constructs/files/terraform/app/dbs/__nameKebabCase__/__nameKebabCase__.tf.template +12 -59
  70. package/src/utils/versions.d.ts +20 -0
  71. package/src/utils/versions.js +17 -0
  72. package/src/utils/versions.js.map +1 -1
  73. /package/src/ts/mcp-server/files/{http.ts.template → app/http.ts.template} +0 -0
  74. /package/src/ts/mcp-server/files/{index.ts.template → app/index.ts.template} +0 -0
  75. /package/src/ts/mcp-server/files/{resources → app/resources}/sample-guidance.ts.template +0 -0
  76. /package/src/ts/mcp-server/files/{server.ts.template → app/server.ts.template} +0 -0
  77. /package/src/ts/mcp-server/files/{stdio.ts.template → app/stdio.ts.template} +0 -0
  78. /package/src/ts/mcp-server/files/{tools → app/tools}/divide.ts.template +0 -0
  79. /package/src/ts/mcp-server/files/{Dockerfile.template → deploy/Dockerfile.template} +0 -0
@@ -4,6 +4,7 @@
4
4
  */ import { generateFiles, joinPathFragments, OverwriteStrategy, updateProjectConfiguration } from "@nx/devkit";
5
5
  import { addPyDependencies, addTsDependencies } from "../../utils/add-dependencies.js";
6
6
  import { addMcpServerInfra } from "../../utils/agent-core-constructs/agent-core-constructs.js";
7
+ import { addPythonCodePackageTarget, agentCorePythonRuntime, isAgentCoreHosted, isContainerHosted } from "../../utils/agent-core-packaging.js";
7
8
  import { addPythonBundleTarget } from "../../utils/bundle/bundle.js";
8
9
  import { resolveContainers } from "../../utils/containers.js";
9
10
  import { declareDependencies, ownedElsewhere } from "../../utils/declared-dependencies.js";
@@ -89,53 +90,88 @@ export const pyMcpServerGenerator = async (tree, options)=>{
89
90
  }, {
90
91
  overwriteStrategy: OverwriteStrategy.KeepExisting
91
92
  });
92
- if (infra === 'agentcore') {
93
+ if (isAgentCoreHosted(infra)) {
94
+ const container = isContainerHosted(infra);
93
95
  const containers = await resolveContainers(tree, 'inherit');
94
96
  const dockerImageTag = `${getNpmScope(tree)}-${name}:latest`;
95
97
  // Add bundle target
96
98
  const { bundleTargetName, bundleOutputDir } = addPythonBundleTarget(project, {
97
99
  pythonPlatform: 'aarch64-manylinux_2_28'
98
100
  });
99
- generateFiles(tree, joinPathFragments(import.meta.dirname, 'files', 'deploy'), targetSourceDir, {
100
- mcpServerNameSnakeCase,
101
- moduleName,
102
- bundleOutputDir,
103
- pythonBaseImage: BASE_IMAGES.python
104
- }, {
105
- overwriteStrategy: OverwriteStrategy.KeepExisting
106
- });
107
- const dockerOutputDir = joinPathFragments('dist', project.root, 'docker', name);
108
- const dockerTargetName = `${mcpTargetPrefix}-docker`;
109
- // Add a docker target that prepares the docker context and builds the image
110
- const fs = new FsCommands(tree, DEPENDENCIES);
111
- project.targets[dockerTargetName] = {
112
- cache: IMAGE_BUILD_CACHE,
113
- executor: 'nx:run-commands',
114
- options: {
115
- commands: [
116
- fs.rm(dockerOutputDir),
117
- fs.mkdir(dockerOutputDir),
118
- fs.cp(bundleOutputDir, dockerOutputDir),
119
- fs.cp(`${targetSourceDir}/Dockerfile`, `${dockerOutputDir}/Dockerfile`),
120
- `${containers} build --platform linux/arm64 -t ${dockerImageTag} ${dockerOutputDir}`
121
- ],
122
- parallel: false
123
- },
124
- dependsOn: [
125
- bundleTargetName
126
- ]
127
- };
128
- addDependencyToTargetIfNotPresent(project, 'docker', dockerTargetName);
129
- addArtifactDependencyToTargets(project, 'docker');
130
- addDockerScanTarget(tree, {
131
- project,
132
- containerEngine: containers,
133
- trivyTargetName: `${mcpTargetPrefix}-trivy`,
134
- dockerTargetName,
135
- imageTags: [
136
- dockerImageTag
137
- ]
138
- }, DEPENDENCIES);
101
+ let artifact;
102
+ if (container) {
103
+ generateFiles(tree, joinPathFragments(import.meta.dirname, 'files', 'deploy'), targetSourceDir, {
104
+ mcpServerNameSnakeCase,
105
+ moduleName,
106
+ bundleOutputDir,
107
+ pythonBaseImage: BASE_IMAGES.python
108
+ }, {
109
+ overwriteStrategy: OverwriteStrategy.KeepExisting
110
+ });
111
+ const dockerOutputDir = joinPathFragments('dist', project.root, 'docker', name);
112
+ const dockerTargetName = `${mcpTargetPrefix}-docker`;
113
+ // Add a docker target that prepares the docker context and builds the image
114
+ const fs = new FsCommands(tree, DEPENDENCIES);
115
+ project.targets[dockerTargetName] = {
116
+ cache: IMAGE_BUILD_CACHE,
117
+ executor: 'nx:run-commands',
118
+ options: {
119
+ commands: [
120
+ fs.rm(dockerOutputDir),
121
+ fs.mkdir(dockerOutputDir),
122
+ fs.cp(bundleOutputDir, dockerOutputDir),
123
+ fs.cp(`${targetSourceDir}/Dockerfile`, `${dockerOutputDir}/Dockerfile`),
124
+ `${containers} build --platform linux/arm64 -t ${dockerImageTag} ${dockerOutputDir}`
125
+ ],
126
+ parallel: false
127
+ },
128
+ dependsOn: [
129
+ bundleTargetName
130
+ ]
131
+ };
132
+ addDependencyToTargetIfNotPresent(project, 'docker', dockerTargetName);
133
+ addArtifactDependencyToTargets(project, 'docker');
134
+ addDockerScanTarget(tree, {
135
+ project,
136
+ containerEngine: containers,
137
+ trivyTargetName: `${mcpTargetPrefix}-trivy`,
138
+ dockerTargetName,
139
+ imageTags: [
140
+ dockerImageTag
141
+ ]
142
+ }, DEPENDENCIES);
143
+ artifact = {
144
+ type: 'container',
145
+ dockerImageTag,
146
+ outputDir: dockerOutputDir
147
+ };
148
+ } else {
149
+ // The entry point the managed runtime runs, at the package root.
150
+ generateFiles(tree, joinPathFragments(import.meta.dirname, 'files', 'package'), joinPathFragments(project.root, 'package', mcpServerNameSnakeCase), {
151
+ mcpServerNameSnakeCase,
152
+ moduleName
153
+ }, {
154
+ overwriteStrategy: OverwriteStrategy.KeepExisting
155
+ });
156
+ const packageOutputDir = joinPathFragments('dist', project.root, 'package', name);
157
+ addPythonCodePackageTarget(tree, {
158
+ project,
159
+ targetName: `${mcpTargetPrefix}-package`,
160
+ bundleTargetName,
161
+ bundleOutputDir,
162
+ packageOutputDir,
163
+ sourceRoot: project.sourceRoot,
164
+ moduleName,
165
+ entryPointPath: joinPathFragments(project.root, 'package', mcpServerNameSnakeCase, 'main.py'),
166
+ entryPointFileName: 'main.py'
167
+ }, DEPENDENCIES);
168
+ artifact = {
169
+ type: 'code',
170
+ outputDir: packageOutputDir,
171
+ runtime: agentCorePythonRuntime(),
172
+ entryPoint: 'main.py'
173
+ };
174
+ }
139
175
  // Add shared constructs
140
176
  await sharedConstructsGenerator(tree, {
141
177
  iac
@@ -145,8 +181,7 @@ export const pyMcpServerGenerator = async (tree, options)=>{
145
181
  mcpServerNameKebabCase: name,
146
182
  mcpServerNameClassName,
147
183
  projectName: project.name,
148
- dockerImageTag,
149
- dockerOutputDir,
184
+ artifact,
150
185
  iac,
151
186
  auth,
152
187
  containers
@@ -161,6 +196,7 @@ export const pyMcpServerGenerator = async (tree, options)=>{
161
196
  // Recorded below and read by the declaration's predicates, so the packages
162
197
  // added here are exactly the ones the version sync will own.
163
198
  const metadata = {
199
+ infra,
164
200
  port: localDevPort,
165
201
  rc: mcpServerNameClassName,
166
202
  auth,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../packages/nx-plugin/src/py/mcp-server/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport {\n addPyDependencies,\n addTsDependencies,\n} from '../../utils/add-dependencies.js';\nimport { addMcpServerInfra } from '../../utils/agent-core-constructs/agent-core-constructs.js';\nimport { addPythonBundleTarget } from '../../utils/bundle/bundle.js';\nimport { resolveContainers } from '../../utils/containers.js';\nimport {\n declareDependencies,\n ownedElsewhere,\n} from '../../utils/declared-dependencies.js';\nimport {\n addDockerScanTarget,\n DOCKER_DEPENDENCIES,\n IMAGE_BUILD_CACHE,\n} from '../../utils/docker.js';\nimport { formatFilesInSubtree } from '../../utils/format.js';\nimport { FS_DEPENDENCIES, FsCommands } from '../../utils/fs.js';\nimport { resolveIac } from '../../utils/iac.js';\nimport { installDependencies } from '../../utils/install.js';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics.js';\nimport { kebabCase, toClassName, toSnakeCase } from '../../utils/names.js';\nimport { getNpmScope } from '../../utils/npm-scope.js';\nimport {\n addArtifactDependencyToTargets,\n addComponentDevTarget,\n addComponentGeneratorMetadata,\n addDependencyToTargetIfNotPresent,\n getGeneratorInfo,\n type NxGeneratorInfo,\n readProjectConfigurationUnqualified,\n} from '../../utils/nx.js';\nimport { toProjectRelativePath } from '../../utils/paths.js';\nimport { registerPnpmBuiltDependencies } from '../../utils/pnpm-workspace.js';\nimport { assignPort } from '../../utils/port.js';\nimport {\n SHARED_CONSTRUCTS_DEPENDENCIES,\n sharedConstructsGenerator,\n} from '../../utils/shared-constructs.js';\nimport type { IacMetadata } from '../../utils/shared-constructs-constants.js';\nimport { BASE_IMAGES } from '../../utils/versions.js';\nimport type { PyMcpServerGeneratorSchema } from './schema';\n\n/** The metadata this generator records, which its predicates read. */\nexport interface PyMcpServerMetadata extends IacMetadata {\n readonly port: number;\n readonly rc: string;\n readonly auth: string;\n}\n\nexport const DEPENDENCIES = declareDependencies<PyMcpServerMetadata>()({\n ts: [\n // The MCP inspector is shared tooling.\n { name: '@modelcontextprotocol/inspector', dev: true, root: true },\n // Added by the helpers that own the projects they belong to.\n ...ownedElsewhere(FS_DEPENDENCIES),\n ...ownedElsewhere(DOCKER_DEPENDENCIES),\n ...ownedElsewhere(SHARED_CONSTRUCTS_DEPENDENCIES),\n ],\n py: [\n { name: 'aws-lambda-powertools' },\n { name: 'mcp' },\n { name: 'uvicorn' },\n { name: 'boto3' },\n { name: 'aws-opentelemetry-distro' },\n ],\n});\n\nexport const PY_MCP_SERVER_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\nexport const pyMcpServerGenerator = async (\n tree: Tree,\n options: PyMcpServerGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const project = readProjectConfigurationUnqualified(tree, options.project);\n\n const pyProjectPath = joinPathFragments(project.root, 'pyproject.toml');\n\n // Check if the project has a pyproject.toml file\n if (!pyProjectPath) {\n throw new Error(\n `Unsupported project ${options.project}. Expected a Python project (with a pyproject.toml)`,\n );\n }\n\n if (!project.sourceRoot) {\n throw new Error(\n `This project does not have a source root. Please add a source root to the project configuration before running this generator.`,\n );\n }\n\n // Module name is the last part of the source root,\n const sourceParts = project.sourceRoot.split('/');\n const moduleName = sourceParts[sourceParts.length - 1];\n\n const name = kebabCase(\n options.name || `${kebabCase(project.name.split('.').pop())}-mcp-server`,\n );\n const mcpTargetPrefix = options.name ? name : 'mcp-server';\n\n const mcpServerNameSnakeCase = toSnakeCase(options.name || 'mcp-server');\n const mcpServerNameClassName = toClassName(name);\n\n const targetSourceDir = joinPathFragments(\n project.sourceRoot,\n mcpServerNameSnakeCase,\n );\n\n const infra = options.infra ?? 'agentcore';\n\n // Recorded in the metadata below so the version sync can tell a CDK\n // project from a Terraform one; undefined when no infrastructure was\n // generated, in which case neither provider's packages were added.\n const iac =\n infra !== 'none' ? await resolveIac(tree, options.iac) : undefined;\n\n if (infra === 'none' && options.auth && options.auth !== 'iam') {\n console.warn(\n 'Warning: auth is ignored when no infrastructure is configured (no infrastructure is generated)',\n );\n }\n\n const auth = options.auth ?? 'iam';\n\n // Generate example server\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'app'),\n targetSourceDir,\n {\n name,\n mcpServerNameSnakeCase,\n mcpServerNameClassName,\n moduleName,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n if (infra === 'agentcore') {\n const containers = await resolveContainers(tree, 'inherit');\n const dockerImageTag = `${getNpmScope(tree)}-${name}:latest`;\n\n // Add bundle target\n const { bundleTargetName, bundleOutputDir } = addPythonBundleTarget(\n project,\n {\n pythonPlatform: 'aarch64-manylinux_2_28',\n },\n );\n\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'deploy'),\n targetSourceDir,\n {\n mcpServerNameSnakeCase,\n moduleName,\n bundleOutputDir,\n pythonBaseImage: BASE_IMAGES.python,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n const dockerOutputDir = joinPathFragments(\n 'dist',\n project.root,\n 'docker',\n name,\n );\n const dockerTargetName = `${mcpTargetPrefix}-docker`;\n\n // Add a docker target that prepares the docker context and builds the image\n const fs = new FsCommands(tree, DEPENDENCIES);\n project.targets[dockerTargetName] = {\n cache: IMAGE_BUILD_CACHE,\n executor: 'nx:run-commands',\n options: {\n commands: [\n fs.rm(dockerOutputDir),\n fs.mkdir(dockerOutputDir),\n fs.cp(bundleOutputDir, dockerOutputDir),\n fs.cp(\n `${targetSourceDir}/Dockerfile`,\n `${dockerOutputDir}/Dockerfile`,\n ),\n `${containers} build --platform linux/arm64 -t ${dockerImageTag} ${dockerOutputDir}`,\n ],\n parallel: false,\n },\n dependsOn: [bundleTargetName],\n };\n\n addDependencyToTargetIfNotPresent(project, 'docker', dockerTargetName);\n addArtifactDependencyToTargets(project, 'docker');\n\n addDockerScanTarget(\n tree,\n {\n project,\n containerEngine: containers,\n trivyTargetName: `${mcpTargetPrefix}-trivy`,\n dockerTargetName,\n imageTags: [dockerImageTag],\n },\n DEPENDENCIES,\n );\n\n // Add shared constructs\n await sharedConstructsGenerator(tree, { iac }, DEPENDENCIES);\n\n // Add the construct to deploy the mcp server\n await addMcpServerInfra(tree, {\n mcpServerNameKebabCase: name,\n mcpServerNameClassName,\n projectName: project.name,\n dockerImageTag,\n dockerOutputDir,\n iac,\n auth,\n containers,\n });\n }\n\n const localDevPort = assignPort(tree, project, 8000, {\n component: { info: PY_MCP_SERVER_GENERATOR_INFO, name: mcpTargetPrefix },\n });\n\n // Recorded below and read by the declaration's predicates, so the packages\n // added here are exactly the ones the version sync will own.\n const metadata: PyMcpServerMetadata = {\n port: localDevPort,\n rc: mcpServerNameClassName,\n auth,\n ...(iac ? { iac } : {}),\n };\n\n // The MCP inspector has a postinstall script that cascades installs into its\n // client packages, which no-ops when the package is installed as a dependency.\n // Register it as an explicitly-rejected build so pnpm 11's default\n // `strictDepBuilds=true` skips it instead of failing the install.\n registerPnpmBuiltDependencies(tree, {\n '@modelcontextprotocol/inspector': false,\n });\n\n addPyDependencies(tree, DEPENDENCIES, {\n metadata,\n projectRoot: project.root,\n });\n addTsDependencies(tree, DEPENDENCIES, { metadata });\n\n const mcpTargets = {\n ...project.targets,\n // Add targets for running the MCP server\n [`${mcpTargetPrefix}-serve-stdio`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [`uv run -m ${moduleName}.${mcpServerNameSnakeCase}.stdio`],\n cwd: '{projectRoot}',\n },\n },\n [`${mcpTargetPrefix}-serve`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [\n `uv run uvicorn --reload ${moduleName}.${mcpServerNameSnakeCase}.http:app --host 0.0.0.0 --port ${localDevPort}`,\n ],\n cwd: '{projectRoot}',\n env: {\n PORT: `${localDevPort}`,\n },\n },\n },\n [`${mcpTargetPrefix}-dev`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [\n `uv run uvicorn --reload ${moduleName}.${mcpServerNameSnakeCase}.http:app --host 0.0.0.0 --port ${localDevPort}`,\n ],\n cwd: '{projectRoot}',\n env: {\n PORT: `${localDevPort}`,\n LOCAL_DEV: 'true',\n },\n },\n },\n [`${mcpTargetPrefix}-inspect`]: {\n executor: 'nx:run-commands',\n continuous: true,\n // Launch the inspector against the locally served HTTP server. The dev\n // target starts the server and any connected dependencies (e.g. a local\n // database).\n dependsOn: [`${mcpTargetPrefix}-dev`],\n options: {\n commands: [\n `mcp-inspector --transport http --server-url http://localhost:${localDevPort}/mcp`,\n ],\n cwd: '{projectRoot}',\n },\n },\n [`${mcpTargetPrefix}-inspect-stdio`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [\n `mcp-inspector -- uv run -m ${moduleName}.${mcpServerNameSnakeCase}.stdio`,\n ],\n cwd: '{projectRoot}',\n },\n },\n };\n\n // Aggregate `<mcp>-dev` under the project-level `dev` target.\n addComponentDevTarget(mcpTargets, `${mcpTargetPrefix}-dev`);\n\n updateProjectConfiguration(tree, project.name, {\n ...project,\n targets: mcpTargets,\n });\n\n addComponentGeneratorMetadata(\n tree,\n project.name,\n PY_MCP_SERVER_GENERATOR_INFO,\n toProjectRelativePath(project, targetSourceDir),\n mcpTargetPrefix,\n metadata,\n );\n\n await addGeneratorMetricsIfApplicable(tree, [PY_MCP_SERVER_GENERATOR_INFO]);\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript', 'python'],\n });\n};\n\nexport default pyMcpServerGenerator;\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","updateProjectConfiguration","addPyDependencies","addTsDependencies","addMcpServerInfra","addPythonBundleTarget","resolveContainers","declareDependencies","ownedElsewhere","addDockerScanTarget","DOCKER_DEPENDENCIES","IMAGE_BUILD_CACHE","formatFilesInSubtree","FS_DEPENDENCIES","FsCommands","resolveIac","installDependencies","addGeneratorMetricsIfApplicable","kebabCase","toClassName","toSnakeCase","getNpmScope","addArtifactDependencyToTargets","addComponentDevTarget","addComponentGeneratorMetadata","addDependencyToTargetIfNotPresent","getGeneratorInfo","readProjectConfigurationUnqualified","toProjectRelativePath","registerPnpmBuiltDependencies","assignPort","SHARED_CONSTRUCTS_DEPENDENCIES","sharedConstructsGenerator","BASE_IMAGES","DEPENDENCIES","ts","name","dev","root","py","PY_MCP_SERVER_GENERATOR_INFO","filename","pyMcpServerGenerator","tree","options","project","pyProjectPath","Error","sourceRoot","sourceParts","split","moduleName","length","pop","mcpTargetPrefix","mcpServerNameSnakeCase","mcpServerNameClassName","targetSourceDir","infra","iac","undefined","auth","console","warn","dirname","overwriteStrategy","KeepExisting","containers","dockerImageTag","bundleTargetName","bundleOutputDir","pythonPlatform","pythonBaseImage","python","dockerOutputDir","dockerTargetName","fs","targets","cache","executor","commands","rm","mkdir","cp","parallel","dependsOn","containerEngine","trivyTargetName","imageTags","mcpServerNameKebabCase","projectName","localDevPort","component","info","metadata","port","rc","projectRoot","mcpTargets","continuous","cwd","env","PORT","LOCAL_DEV","preferInstallDependencies","languages"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../packages/nx-plugin/src/py/mcp-server/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport {\n addPyDependencies,\n addTsDependencies,\n} from '../../utils/add-dependencies.js';\nimport {\n type AgentCoreArtifact,\n addMcpServerInfra,\n} from '../../utils/agent-core-constructs/agent-core-constructs.js';\nimport {\n addPythonCodePackageTarget,\n agentCorePythonRuntime,\n isAgentCoreHosted,\n isContainerHosted,\n} from '../../utils/agent-core-packaging.js';\nimport { addPythonBundleTarget } from '../../utils/bundle/bundle.js';\nimport { resolveContainers } from '../../utils/containers.js';\nimport {\n declareDependencies,\n ownedElsewhere,\n} from '../../utils/declared-dependencies.js';\nimport {\n addDockerScanTarget,\n DOCKER_DEPENDENCIES,\n IMAGE_BUILD_CACHE,\n} from '../../utils/docker.js';\nimport { formatFilesInSubtree } from '../../utils/format.js';\nimport { FS_DEPENDENCIES, FsCommands } from '../../utils/fs.js';\nimport { resolveIac } from '../../utils/iac.js';\nimport { installDependencies } from '../../utils/install.js';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics.js';\nimport { kebabCase, toClassName, toSnakeCase } from '../../utils/names.js';\nimport { getNpmScope } from '../../utils/npm-scope.js';\nimport {\n addArtifactDependencyToTargets,\n addComponentDevTarget,\n addComponentGeneratorMetadata,\n addDependencyToTargetIfNotPresent,\n getGeneratorInfo,\n type NxGeneratorInfo,\n readProjectConfigurationUnqualified,\n} from '../../utils/nx.js';\nimport { toProjectRelativePath } from '../../utils/paths.js';\nimport { registerPnpmBuiltDependencies } from '../../utils/pnpm-workspace.js';\nimport { assignPort } from '../../utils/port.js';\nimport {\n SHARED_CONSTRUCTS_DEPENDENCIES,\n sharedConstructsGenerator,\n} from '../../utils/shared-constructs.js';\nimport type { IacMetadata } from '../../utils/shared-constructs-constants.js';\nimport { BASE_IMAGES } from '../../utils/versions.js';\nimport type { PyMcpServerGeneratorSchema, PyMcpServerInfra } from './schema';\n\n/** The metadata this generator records, which its predicates read. */\nexport interface PyMcpServerMetadata extends IacMetadata {\n readonly port: number;\n readonly rc: string;\n readonly auth: string;\n /**\n * How this component is packaged and hosted, so a consumer can tell a\n * code-packaged runtime from a container-packaged one without re-deriving it.\n */\n readonly infra: PyMcpServerInfra;\n}\n\nexport const DEPENDENCIES = declareDependencies<PyMcpServerMetadata>()({\n ts: [\n // The MCP inspector is shared tooling.\n { name: '@modelcontextprotocol/inspector', dev: true, root: true },\n // Added by the helpers that own the projects they belong to.\n ...ownedElsewhere(FS_DEPENDENCIES),\n ...ownedElsewhere(DOCKER_DEPENDENCIES),\n ...ownedElsewhere(SHARED_CONSTRUCTS_DEPENDENCIES),\n ],\n py: [\n { name: 'aws-lambda-powertools' },\n { name: 'mcp' },\n { name: 'uvicorn' },\n { name: 'boto3' },\n { name: 'aws-opentelemetry-distro' },\n ],\n});\n\nexport const PY_MCP_SERVER_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\nexport const pyMcpServerGenerator = async (\n tree: Tree,\n options: PyMcpServerGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const project = readProjectConfigurationUnqualified(tree, options.project);\n\n const pyProjectPath = joinPathFragments(project.root, 'pyproject.toml');\n\n // Check if the project has a pyproject.toml file\n if (!pyProjectPath) {\n throw new Error(\n `Unsupported project ${options.project}. Expected a Python project (with a pyproject.toml)`,\n );\n }\n\n if (!project.sourceRoot) {\n throw new Error(\n `This project does not have a source root. Please add a source root to the project configuration before running this generator.`,\n );\n }\n\n // Module name is the last part of the source root,\n const sourceParts = project.sourceRoot.split('/');\n const moduleName = sourceParts[sourceParts.length - 1];\n\n const name = kebabCase(\n options.name || `${kebabCase(project.name.split('.').pop())}-mcp-server`,\n );\n const mcpTargetPrefix = options.name ? name : 'mcp-server';\n\n const mcpServerNameSnakeCase = toSnakeCase(options.name || 'mcp-server');\n const mcpServerNameClassName = toClassName(name);\n\n const targetSourceDir = joinPathFragments(\n project.sourceRoot,\n mcpServerNameSnakeCase,\n );\n\n const infra = options.infra ?? 'agentcore';\n\n // Recorded in the metadata below so the version sync can tell a CDK\n // project from a Terraform one; undefined when no infrastructure was\n // generated, in which case neither provider's packages were added.\n const iac =\n infra !== 'none' ? await resolveIac(tree, options.iac) : undefined;\n\n if (infra === 'none' && options.auth && options.auth !== 'iam') {\n console.warn(\n 'Warning: auth is ignored when no infrastructure is configured (no infrastructure is generated)',\n );\n }\n\n const auth = options.auth ?? 'iam';\n\n // Generate example server\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'app'),\n targetSourceDir,\n {\n name,\n mcpServerNameSnakeCase,\n mcpServerNameClassName,\n moduleName,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n if (isAgentCoreHosted(infra)) {\n const container = isContainerHosted(infra);\n const containers = await resolveContainers(tree, 'inherit');\n const dockerImageTag = `${getNpmScope(tree)}-${name}:latest`;\n\n // Add bundle target\n const { bundleTargetName, bundleOutputDir } = addPythonBundleTarget(\n project,\n {\n pythonPlatform: 'aarch64-manylinux_2_28',\n },\n );\n\n let artifact: AgentCoreArtifact;\n\n if (container) {\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'deploy'),\n targetSourceDir,\n {\n mcpServerNameSnakeCase,\n moduleName,\n bundleOutputDir,\n pythonBaseImage: BASE_IMAGES.python,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n const dockerOutputDir = joinPathFragments(\n 'dist',\n project.root,\n 'docker',\n name,\n );\n const dockerTargetName = `${mcpTargetPrefix}-docker`;\n\n // Add a docker target that prepares the docker context and builds the image\n const fs = new FsCommands(tree, DEPENDENCIES);\n project.targets[dockerTargetName] = {\n cache: IMAGE_BUILD_CACHE,\n executor: 'nx:run-commands',\n options: {\n commands: [\n fs.rm(dockerOutputDir),\n fs.mkdir(dockerOutputDir),\n fs.cp(bundleOutputDir, dockerOutputDir),\n fs.cp(\n `${targetSourceDir}/Dockerfile`,\n `${dockerOutputDir}/Dockerfile`,\n ),\n `${containers} build --platform linux/arm64 -t ${dockerImageTag} ${dockerOutputDir}`,\n ],\n parallel: false,\n },\n dependsOn: [bundleTargetName],\n };\n\n addDependencyToTargetIfNotPresent(project, 'docker', dockerTargetName);\n addArtifactDependencyToTargets(project, 'docker');\n\n addDockerScanTarget(\n tree,\n {\n project,\n containerEngine: containers,\n trivyTargetName: `${mcpTargetPrefix}-trivy`,\n dockerTargetName,\n imageTags: [dockerImageTag],\n },\n DEPENDENCIES,\n );\n\n artifact = {\n type: 'container',\n dockerImageTag,\n outputDir: dockerOutputDir,\n };\n } else {\n // The entry point the managed runtime runs, at the package root.\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'package'),\n joinPathFragments(project.root, 'package', mcpServerNameSnakeCase),\n {\n mcpServerNameSnakeCase,\n moduleName,\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n\n const packageOutputDir = joinPathFragments(\n 'dist',\n project.root,\n 'package',\n name,\n );\n addPythonCodePackageTarget(\n tree,\n {\n project,\n targetName: `${mcpTargetPrefix}-package`,\n bundleTargetName,\n bundleOutputDir,\n packageOutputDir,\n sourceRoot: project.sourceRoot,\n moduleName,\n entryPointPath: joinPathFragments(\n project.root,\n 'package',\n mcpServerNameSnakeCase,\n 'main.py',\n ),\n entryPointFileName: 'main.py',\n },\n DEPENDENCIES,\n );\n\n artifact = {\n type: 'code',\n outputDir: packageOutputDir,\n runtime: agentCorePythonRuntime(),\n entryPoint: 'main.py',\n };\n }\n\n // Add shared constructs\n await sharedConstructsGenerator(tree, { iac }, DEPENDENCIES);\n\n // Add the construct to deploy the mcp server\n await addMcpServerInfra(tree, {\n mcpServerNameKebabCase: name,\n mcpServerNameClassName,\n projectName: project.name,\n artifact,\n iac,\n auth,\n containers,\n });\n }\n\n const localDevPort = assignPort(tree, project, 8000, {\n component: { info: PY_MCP_SERVER_GENERATOR_INFO, name: mcpTargetPrefix },\n });\n\n // Recorded below and read by the declaration's predicates, so the packages\n // added here are exactly the ones the version sync will own.\n const metadata: PyMcpServerMetadata = {\n infra,\n port: localDevPort,\n rc: mcpServerNameClassName,\n auth,\n ...(iac ? { iac } : {}),\n };\n\n // The MCP inspector has a postinstall script that cascades installs into its\n // client packages, which no-ops when the package is installed as a dependency.\n // Register it as an explicitly-rejected build so pnpm 11's default\n // `strictDepBuilds=true` skips it instead of failing the install.\n registerPnpmBuiltDependencies(tree, {\n '@modelcontextprotocol/inspector': false,\n });\n\n addPyDependencies(tree, DEPENDENCIES, {\n metadata,\n projectRoot: project.root,\n });\n addTsDependencies(tree, DEPENDENCIES, { metadata });\n\n const mcpTargets = {\n ...project.targets,\n // Add targets for running the MCP server\n [`${mcpTargetPrefix}-serve-stdio`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [`uv run -m ${moduleName}.${mcpServerNameSnakeCase}.stdio`],\n cwd: '{projectRoot}',\n },\n },\n [`${mcpTargetPrefix}-serve`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [\n `uv run uvicorn --reload ${moduleName}.${mcpServerNameSnakeCase}.http:app --host 0.0.0.0 --port ${localDevPort}`,\n ],\n cwd: '{projectRoot}',\n env: {\n PORT: `${localDevPort}`,\n },\n },\n },\n [`${mcpTargetPrefix}-dev`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [\n `uv run uvicorn --reload ${moduleName}.${mcpServerNameSnakeCase}.http:app --host 0.0.0.0 --port ${localDevPort}`,\n ],\n cwd: '{projectRoot}',\n env: {\n PORT: `${localDevPort}`,\n LOCAL_DEV: 'true',\n },\n },\n },\n [`${mcpTargetPrefix}-inspect`]: {\n executor: 'nx:run-commands',\n continuous: true,\n // Launch the inspector against the locally served HTTP server. The dev\n // target starts the server and any connected dependencies (e.g. a local\n // database).\n dependsOn: [`${mcpTargetPrefix}-dev`],\n options: {\n commands: [\n `mcp-inspector --transport http --server-url http://localhost:${localDevPort}/mcp`,\n ],\n cwd: '{projectRoot}',\n },\n },\n [`${mcpTargetPrefix}-inspect-stdio`]: {\n executor: 'nx:run-commands',\n continuous: true,\n options: {\n commands: [\n `mcp-inspector -- uv run -m ${moduleName}.${mcpServerNameSnakeCase}.stdio`,\n ],\n cwd: '{projectRoot}',\n },\n },\n };\n\n // Aggregate `<mcp>-dev` under the project-level `dev` target.\n addComponentDevTarget(mcpTargets, `${mcpTargetPrefix}-dev`);\n\n updateProjectConfiguration(tree, project.name, {\n ...project,\n targets: mcpTargets,\n });\n\n addComponentGeneratorMetadata(\n tree,\n project.name,\n PY_MCP_SERVER_GENERATOR_INFO,\n toProjectRelativePath(project, targetSourceDir),\n mcpTargetPrefix,\n metadata,\n );\n\n await addGeneratorMetricsIfApplicable(tree, [PY_MCP_SERVER_GENERATOR_INFO]);\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript', 'python'],\n });\n};\n\nexport default pyMcpServerGenerator;\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","updateProjectConfiguration","addPyDependencies","addTsDependencies","addMcpServerInfra","addPythonCodePackageTarget","agentCorePythonRuntime","isAgentCoreHosted","isContainerHosted","addPythonBundleTarget","resolveContainers","declareDependencies","ownedElsewhere","addDockerScanTarget","DOCKER_DEPENDENCIES","IMAGE_BUILD_CACHE","formatFilesInSubtree","FS_DEPENDENCIES","FsCommands","resolveIac","installDependencies","addGeneratorMetricsIfApplicable","kebabCase","toClassName","toSnakeCase","getNpmScope","addArtifactDependencyToTargets","addComponentDevTarget","addComponentGeneratorMetadata","addDependencyToTargetIfNotPresent","getGeneratorInfo","readProjectConfigurationUnqualified","toProjectRelativePath","registerPnpmBuiltDependencies","assignPort","SHARED_CONSTRUCTS_DEPENDENCIES","sharedConstructsGenerator","BASE_IMAGES","DEPENDENCIES","ts","name","dev","root","py","PY_MCP_SERVER_GENERATOR_INFO","filename","pyMcpServerGenerator","tree","options","project","pyProjectPath","Error","sourceRoot","sourceParts","split","moduleName","length","pop","mcpTargetPrefix","mcpServerNameSnakeCase","mcpServerNameClassName","targetSourceDir","infra","iac","undefined","auth","console","warn","dirname","overwriteStrategy","KeepExisting","container","containers","dockerImageTag","bundleTargetName","bundleOutputDir","pythonPlatform","artifact","pythonBaseImage","python","dockerOutputDir","dockerTargetName","fs","targets","cache","executor","commands","rm","mkdir","cp","parallel","dependsOn","containerEngine","trivyTargetName","imageTags","type","outputDir","packageOutputDir","targetName","entryPointPath","entryPointFileName","runtime","entryPoint","mcpServerNameKebabCase","projectName","localDevPort","component","info","metadata","port","rc","projectRoot","mcpTargets","continuous","cwd","env","PORT","LOCAL_DEV","preferInstallDependencies","languages"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../packages/nx-plugin/src/py/mcp-server/schema.d.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { IacOption } from '../../utils/iac.js';\n\nexport type PyMcpServerInfra = 'none' | 'agentcore';\n\nexport type PyMcpServerAuth = 'iam' | 'cognito';\n\nexport interface PyMcpServerGeneratorSchema {\n project: string;\n name?: string;\n infra?: PyMcpServerInfra;\n auth?: PyMcpServerAuth;\n iac: IacOption;\n preferInstallDependencies?: boolean;\n}\n"],"names":[],"mappings":"AAAA;;;CAGC,GAQD,WAOC"}
1
+ {"version":3,"sources":["../../../../../../packages/nx-plugin/src/py/mcp-server/schema.d.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\n\nimport { AgentCoreInfra } from '../../utils/agent-core-packaging.js';\nimport { IacOption } from '../../utils/iac.js';\n\nexport type PyMcpServerInfra = AgentCoreInfra;\n\nexport type PyMcpServerAuth = 'iam' | 'cognito';\n\nexport interface PyMcpServerGeneratorSchema {\n project: string;\n name?: string;\n infra?: PyMcpServerInfra;\n auth?: PyMcpServerAuth;\n iac: IacOption;\n preferInstallDependencies?: boolean;\n}\n"],"names":[],"mappings":"AAAA;;;CAGC,GASD,WAOC"}
@@ -3,9 +3,10 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
 
6
+ import { AgentCoreInfra } from '../../utils/agent-core-packaging.js';
6
7
  import { IacOption } from '../../utils/iac.js';
7
8
 
8
- export type PyMcpServerInfra = 'none' | 'agentcore';
9
+ export type PyMcpServerInfra = AgentCoreInfra;
9
10
 
10
11
  export type PyMcpServerAuth = 'iam' | 'cognito';
11
12
 
@@ -39,9 +39,9 @@
39
39
  },
40
40
  "infra": {
41
41
  "type": "string",
42
- "description": "The type of infrastructure to host your MCP server. Select none for no hosting.",
42
+ "description": "The type of infrastructure to host your MCP server. agentcore deploys your code as a zip to an AgentCore managed runtime for the fastest build and deploy cycle. agentcore-ecr builds and hosts a container image instead, for OS-level control or an established container pipeline. Select none for no hosting.",
43
43
  "x-prompt": "How would you like to host your MCP server?",
44
- "enum": ["agentcore", "none"],
44
+ "enum": ["agentcore", "agentcore-ecr", "none"],
45
45
  "default": "agentcore",
46
46
  "x-priority": "important"
47
47
  },
@@ -343,6 +343,11 @@ variable "create_db_user_docker_image_tag" {
343
343
  }
344
344
 
345
345
 
346
+ variable "asset_ecr_repository_url" {
347
+ description = "URL of the shared asset ECR repository the Lambda container images are published to. Instantiate the \`core/asset-ecr\` module once per deployment and pass its \`repository_url\` output here."
348
+ type = string
349
+ }
350
+
346
351
  data "aws_region" "current" {}
347
352
  data "aws_caller_identity" "current" {}
348
353
 
@@ -420,76 +425,26 @@ module "add_rdb_to_runtime_config" {
420
425
  }
421
426
  }
422
427
 
423
- resource "aws_ecr_repository" "migration_handler" {
424
- #checkov:skip=CKV_AWS_136:AES256 encryption is sufficient for ECR repositories
425
- name = "db-migration-\${random_string.suffix.result}"
426
- image_tag_mutability = "IMMUTABLE"
427
- force_delete = true
428
-
429
- image_scanning_configuration {
430
- scan_on_push = true
431
- }
432
-
433
- tags = var.tags
434
- }
435
-
436
- resource "aws_ecr_repository_policy" "migration_handler" {
437
- repository = aws_ecr_repository.migration_handler.name
438
-
439
- policy = jsonencode({
440
- Version = "2012-10-17"
441
- Statement = [
442
- {
443
- Sid = "AllowPushPull"
444
- Effect = "Allow"
445
- Principal = {
446
- AWS = "arn:aws:iam::\${data.aws_caller_identity.current.account_id}:root"
447
- }
448
- Action = [
449
- "ecr:BatchCheckLayerAvailability",
450
- "ecr:CompleteLayerUpload",
451
- "ecr:GetDownloadUrlForLayer",
452
- "ecr:InitiateLayerUpload",
453
- "ecr:PutImage",
454
- "ecr:UploadLayerPart"
455
- ]
456
- },
457
- {
458
- Sid = "AllowLambdaPull"
459
- Effect = "Allow"
460
- Principal = {
461
- Service = "lambda.amazonaws.com"
462
- }
463
- Action = [
464
- "ecr:BatchCheckLayerAvailability",
465
- "ecr:BatchGetImage",
466
- "ecr:GetDownloadUrlForLayer"
467
- ]
468
- }
469
- ]
470
- })
471
- }
472
-
473
428
  data "external" "docker_digest" {
474
429
  program = ["sh", "-c", "echo '{\\"digest\\":\\"'$(docker inspect \${var.migration_docker_image_tag} --format '{{.Id}}')'\\"}' "]
475
430
  }
476
431
 
477
432
  locals {
478
433
  # Content-based, immutable image tag derived from the local image digest
479
- image_tag = replace(data.external.docker_digest.result.digest, "sha256:", "")
434
+ image_tag = "db-migration-\${replace(data.external.docker_digest.result.digest, "sha256:", "")}"
480
435
  }
481
436
  data "external" "create_db_user_docker_digest" {
482
437
  program = ["sh", "-c", "echo '{\\"digest\\":\\"'$(docker inspect \${var.create_db_user_docker_image_tag} --format '{{.Id}}')'\\"}' "]
483
438
  }
484
439
 
485
440
  locals {
486
- create_db_user_image_tag = replace(data.external.create_db_user_docker_digest.result.digest, "sha256:", "")
441
+ create_db_user_image_tag = "db-create-db-user-\${replace(data.external.create_db_user_docker_digest.result.digest, "sha256:", "")}"
487
442
  }
488
443
 
489
444
  resource "null_resource" "docker_publish" {
490
445
  triggers = {
491
446
  docker_digest = data.external.docker_digest.result.digest
492
- repository_url = aws_ecr_repository.migration_handler.repository_url
447
+ repository_url = var.asset_ecr_repository_url
493
448
  migration_docker_image_tag = var.migration_docker_image_tag
494
449
  image_tag = local.image_tag
495
450
  create_db_user_docker_digest = data.external.create_db_user_docker_digest.result.digest
@@ -502,8 +457,8 @@ resource "null_resource" "docker_publish" {
502
457
  aws ecr get-login-password --region "$AWS_REGION" | docker login --username AWS --password-stdin "$REPOSITORY_URL"
503
458
  docker tag "$MIGRATION_DOCKER_IMAGE_TAG" "$REPOSITORY_URL:$IMAGE_TAG"
504
459
  docker push "$REPOSITORY_URL:$IMAGE_TAG"
505
- docker tag "$CREATE_DB_USER_DOCKER_IMAGE_TAG" "$REPOSITORY_URL:create-db-user-$CREATE_DB_USER_IMAGE_TAG"
506
- docker push "$REPOSITORY_URL:create-db-user-$CREATE_DB_USER_IMAGE_TAG"
460
+ docker tag "$CREATE_DB_USER_DOCKER_IMAGE_TAG" "$REPOSITORY_URL:$CREATE_DB_USER_IMAGE_TAG"
461
+ docker push "$REPOSITORY_URL:$CREATE_DB_USER_IMAGE_TAG"
507
462
  EOT
508
463
  environment = {
509
464
  AWS_REGION = data.aws_region.current.region
@@ -514,8 +469,6 @@ resource "null_resource" "docker_publish" {
514
469
  CREATE_DB_USER_IMAGE_TAG = self.triggers.create_db_user_image_tag
515
470
  }
516
471
  }
517
-
518
- depends_on = [aws_ecr_repository_policy.migration_handler]
519
472
  }
520
473
 
521
474
  resource "aws_iam_role" "migration_handler" {
@@ -724,7 +677,7 @@ resource "aws_lambda_function" "create_db_user" {
724
677
  #checkov:skip=CKV_AWS_173:Lambda environment variables encrypted by managed key
725
678
  #checkov:skip=CKV_AWS_272:Code signing not configured as deployment packages are built and deployed within the same pipeline
726
679
  package_type = "Image"
727
- image_uri = "\${aws_ecr_repository.migration_handler.repository_url}:create-db-user-\${local.create_db_user_image_tag}"
680
+ image_uri = "\${var.asset_ecr_repository_url}:\${local.create_db_user_image_tag}"
728
681
  function_name = local.create_db_user_function_name
729
682
  role = aws_iam_role.create_db_user.arn
730
683
  timeout = 300
@@ -808,7 +761,7 @@ resource "aws_lambda_function" "migration_handler" {
808
761
  package_type = "Image"
809
762
  function_name = local.migration_function_name
810
763
  role = aws_iam_role.migration_handler.arn
811
- image_uri = "\${aws_ecr_repository.migration_handler.repository_url}:\${local.image_tag}"
764
+ image_uri = "\${var.asset_ecr_repository_url}:\${local.image_tag}"
812
765
  memory_size = 1024
813
766
  timeout = 300
814
767
  architectures = ["arm64"]