@aws/nx-plugin 1.0.0-rc.82 → 1.0.0-rc.83
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.
- package/migrations.json +16 -1
- package/package.json +1 -1
- package/src/agentcore-gateway/generator.d.ts +7 -6
- package/src/agentcore-gateway/generator.js +2 -12
- package/src/agentcore-gateway/generator.js.map +1 -1
- package/src/migrations/latest/dynamodb-terraform-app-module-outputs/metadata.json +3 -0
- package/src/migrations/latest/dynamodb-terraform-app-module-outputs/migration.d.ts +6 -0
- package/src/migrations/latest/dynamodb-terraform-app-module-outputs/migration.js +69 -0
- package/src/migrations/latest/dynamodb-terraform-app-module-outputs/migration.js.map +1 -0
- package/src/migrations/latest/terraform-data-resource-destroy-protection/__snapshots__/migration.spec.ts.snap +75 -0
- package/src/migrations/latest/terraform-data-resource-destroy-protection/metadata.json +3 -0
- package/src/migrations/latest/terraform-data-resource-destroy-protection/migration.d.ts +6 -0
- package/src/migrations/latest/terraform-data-resource-destroy-protection/migration.js +78 -0
- package/src/migrations/latest/terraform-data-resource-destroy-protection/migration.js.map +1 -0
- package/src/migrations/latest/terraform-gateway-cedar-render-root-ejs/metadata.json +3 -0
- package/src/migrations/latest/terraform-gateway-cedar-render-root-ejs/migration.d.ts +6 -0
- package/src/migrations/latest/terraform-gateway-cedar-render-root-ejs/migration.js +38 -0
- package/src/migrations/latest/terraform-gateway-cedar-render-root-ejs/migration.js.map +1 -0
- package/src/py/dynamodb/__snapshots__/generator.spec.ts.snap +21 -0
- package/src/ts/dynamodb/__snapshots__/generator.spec.ts.snap +21 -0
- package/src/ts/rdb/__snapshots__/generator.spec.ts.snap +12 -0
- package/src/utils/agent-core-constructs/agent-core-constructs.d.ts +9 -2
- package/src/utils/agent-core-constructs/agent-core-constructs.js +22 -8
- package/src/utils/agent-core-constructs/agent-core-constructs.js.map +1 -1
- package/src/utils/dynamodb-constructs/files/terraform/app/dynamodb/__nameKebabCase__/__nameKebabCase__.tf.template +15 -0
- package/src/utils/dynamodb-constructs/files/terraform/core/dynamodb/dynamodb.tf.template +6 -0
- package/src/utils/rdb-constructs/files/terraform/core/rdb/aurora/aurora.tf.template +6 -0
- package/src/utils/shared-constructs-constants.d.ts +5 -0
- package/src/utils/shared-constructs-constants.js +4 -0
- package/src/utils/shared-constructs-constants.js.map +1 -1
package/migrations.json
CHANGED
|
@@ -32,6 +32,21 @@
|
|
|
32
32
|
"description": "Provision AppConfig configuration profiles for every namespace the vended terraform modules write to",
|
|
33
33
|
"implementation": "./src/migrations/latest/runtime-config-namespace-defaults/migration"
|
|
34
34
|
},
|
|
35
|
+
"latest-dynamodb-terraform-app-module-outputs": {
|
|
36
|
+
"version": "1.0.0-rc.83",
|
|
37
|
+
"description": "Re-export the DynamoDB table and KMS key attributes from the vended Terraform per-table app module",
|
|
38
|
+
"implementation": "./src/migrations/latest/dynamodb-terraform-app-module-outputs/migration"
|
|
39
|
+
},
|
|
40
|
+
"latest-terraform-data-resource-destroy-protection": {
|
|
41
|
+
"version": "1.0.0-rc.83",
|
|
42
|
+
"description": "Add prevent_destroy and a 30 day KMS deletion window to the vended Terraform DynamoDB table and Aurora cluster modules",
|
|
43
|
+
"implementation": "./src/migrations/latest/terraform-data-resource-destroy-protection/migration"
|
|
44
|
+
},
|
|
45
|
+
"latest-terraform-gateway-cedar-render-root-ejs": {
|
|
46
|
+
"version": "1.0.0-rc.83",
|
|
47
|
+
"description": "Declare ejs at the workspace root so the Terraform gateway's Cedar render script resolves it",
|
|
48
|
+
"implementation": "./src/migrations/latest/terraform-gateway-cedar-render-root-ejs/migration"
|
|
49
|
+
},
|
|
35
50
|
"v1.0.0-rc.50-0001-modernize-function-props-cast": {
|
|
36
51
|
"version": "1.0.0-rc.50",
|
|
37
52
|
"description": "Replace the legacy angle-bracket FunctionProps type assertion with the modern as syntax in generated API constructs",
|
|
@@ -173,7 +188,7 @@
|
|
|
173
188
|
"implementation": "./src/migrations/v1.0.0-rc.75/0001-ts-agent-session-id-middleware-extraction/migration"
|
|
174
189
|
},
|
|
175
190
|
"sync-vended-versions": {
|
|
176
|
-
"version": "1.0.0-rc.
|
|
191
|
+
"version": "1.0.0-rc.83",
|
|
177
192
|
"description": "Sync vended dependency versions and the tracked plugin version to those vended by this release",
|
|
178
193
|
"implementation": "./src/utils/version-upgrade-migration/migration"
|
|
179
194
|
}
|
package/package.json
CHANGED
|
@@ -14,12 +14,6 @@ export declare const DEPENDENCIES: import("../utils/declared-dependencies.js").D
|
|
|
14
14
|
}, {
|
|
15
15
|
readonly name: "@types/express";
|
|
16
16
|
readonly dev: true;
|
|
17
|
-
}, {
|
|
18
|
-
readonly name: "ejs";
|
|
19
|
-
readonly dev: true;
|
|
20
|
-
}, {
|
|
21
|
-
readonly name: "@types/ejs";
|
|
22
|
-
readonly dev: true;
|
|
23
17
|
}, {
|
|
24
18
|
readonly name: "tsx";
|
|
25
19
|
readonly dev: true;
|
|
@@ -39,6 +33,13 @@ export declare const DEPENDENCIES: import("../utils/declared-dependencies.js").D
|
|
|
39
33
|
readonly when: (m: IacMetadata) => boolean;
|
|
40
34
|
} & {
|
|
41
35
|
versionOnly: true;
|
|
36
|
+
}, {
|
|
37
|
+
readonly name: "ejs";
|
|
38
|
+
readonly when: (m: IacMetadata) => boolean;
|
|
39
|
+
readonly dev: true;
|
|
40
|
+
readonly root: true;
|
|
41
|
+
} & {
|
|
42
|
+
versionOnly: true;
|
|
42
43
|
}, {
|
|
43
44
|
readonly name: "constructs";
|
|
44
45
|
readonly when: (m: IacMetadata) => boolean;
|
|
@@ -15,9 +15,8 @@ import { addGeneratorMetadata, getGeneratorInfo, projectExists, readProjectConfi
|
|
|
15
15
|
import { assignPort } from "../utils/port.js";
|
|
16
16
|
import { ensureProjectPackageJson } from "../utils/project-package-json.js";
|
|
17
17
|
import { SHARED_CONSTRUCTS_DEPENDENCIES, sharedConstructsGenerator } from "../utils/shared-constructs.js";
|
|
18
|
-
// The gateway's local-dev server
|
|
19
|
-
//
|
|
20
|
-
// gateway is a plain proxy).
|
|
18
|
+
// The gateway's local-dev server needs these whatever the auth; only the MCP
|
|
19
|
+
// SDK is protocol-specific (the http local gateway is a plain proxy).
|
|
21
20
|
export const DEPENDENCIES = declareDependencies()({
|
|
22
21
|
ts: [
|
|
23
22
|
{
|
|
@@ -31,15 +30,6 @@ export const DEPENDENCIES = declareDependencies()({
|
|
|
31
30
|
name: '@types/express',
|
|
32
31
|
dev: true
|
|
33
32
|
},
|
|
34
|
-
// ejs renders the Cedar policy in the shared gateway construct.
|
|
35
|
-
{
|
|
36
|
-
name: 'ejs',
|
|
37
|
-
dev: true
|
|
38
|
-
},
|
|
39
|
-
{
|
|
40
|
-
name: '@types/ejs',
|
|
41
|
-
dev: true
|
|
42
|
-
},
|
|
43
33
|
// local-dev.ts runs via tsx, which is shared tooling.
|
|
44
34
|
{
|
|
45
35
|
name: 'tsx',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../packages/nx-plugin/src/agentcore-gateway/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n addProjectConfiguration,\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n logger,\n OverwriteStrategy,\n type ProjectConfiguration,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { addTsDependencies } from '../utils/add-dependencies.js';\nimport {\n AGENT_CORE_CONSTRUCTS_DEPENDENCIES,\n AGENT_CORE_CONSTRUCTS_PY_DEPENDENCIES,\n addAgentCoreGatewayInfra,\n} from '../utils/agent-core-constructs/agent-core-constructs.js';\nimport {\n declareDependencies,\n ownedElsewhere,\n} from '../utils/declared-dependencies.js';\nimport { formatFilesInSubtree } from '../utils/format.js';\nimport { resolveIac } from '../utils/iac.js';\nimport { installDependencies } from '../utils/install.js';\nimport { addGeneratorMetricsIfApplicable } from '../utils/metrics.js';\nimport { kebabCase, toClassName } from '../utils/names.js';\nimport { getNpmScopePrefix } from '../utils/npm-scope.js';\nimport {\n addGeneratorMetadata,\n getGeneratorInfo,\n type NxGeneratorInfo,\n projectExists,\n readProjectConfigurationUnqualified,\n} from '../utils/nx.js';\nimport { assignPort } from '../utils/port.js';\nimport { ensureProjectPackageJson } from '../utils/project-package-json.js';\nimport {\n SHARED_CONSTRUCTS_DEPENDENCIES,\n sharedConstructsGenerator,\n} from '../utils/shared-constructs.js';\nimport type { IacMetadata } from '../utils/shared-constructs-constants.js';\nimport type { AgentcoreGatewayGeneratorSchema } from './schema';\n\n// The gateway's local-dev server and Cedar policy rendering need these\n// whatever the auth; only the MCP SDK is protocol-specific (the http local\n// gateway is a plain proxy).\nexport const DEPENDENCIES = declareDependencies<AgentCoreGatewayMetadata>()({\n ts: [\n { name: '@modelcontextprotocol/sdk', when: (m) => m.protocol === 'mcp' },\n { name: 'express' },\n { name: '@types/express', dev: true },\n // ejs renders the Cedar policy in the shared gateway construct.\n { name: 'ejs', dev: true },\n { name: '@types/ejs', dev: true },\n // local-dev.ts runs via tsx, which is shared tooling.\n { name: 'tsx', dev: true, root: true },\n ...ownedElsewhere(AGENT_CORE_CONSTRUCTS_DEPENDENCIES),\n ...ownedElsewhere(SHARED_CONSTRUCTS_DEPENDENCIES),\n ],\n py: ownedElsewhere(AGENT_CORE_CONSTRUCTS_PY_DEPENDENCIES),\n});\n\nexport const AGENTCORE_GATEWAY_GENERATOR_INFO: NxGeneratorInfo =\n getGeneratorInfo(import.meta.filename);\n\nexport const agentcoreGatewayGenerator = async (\n tree: Tree,\n options: AgentcoreGatewayGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const name = kebabCase(options.name);\n const nameClassName = toClassName(name);\n const parentDir = options.directory ?? 'packages';\n const subDir = options.subDirectory ?? name;\n const projectRoot = joinPathFragments(parentDir, subDir);\n const fullyQualifiedName = `${getNpmScopePrefix(tree)}${name}`;\n\n // Protocol is mcp (aggregate MCP server targets into one MCP endpoint) or\n // http (proxy agent runtime targets via path-based routing). Persisted in\n // metadata so connection generators can validate it.\n const protocol = options.protocol ?? 'mcp';\n // Inbound auth is iam (default) or cognito. Persisted in metadata so\n // connection generators can validate it (agent -> gateway connections\n // require an IAM gateway).\n const auth = options.auth ?? 'iam';\n // Cedar policies authorize MCP tool actions, which an http gateway has none\n // of — its runtime targets are plain proxied endpoints — so the policy\n // engine only applies to mcp gateways. cedarPolicy defaults to true in the\n // schema, so an http gateway quietly drops it rather than requiring\n // --cedarPolicy=false.\n if (protocol === 'http' && options.cedarPolicy) {\n logger.warn(\n 'Cedar policies authorize MCP tool actions, so cedarPolicy is ignored for http-protocol gateways.',\n );\n }\n const cedarPolicy = protocol === 'mcp' && (options.cedarPolicy ?? true);\n const infra = options.infra ?? 'agentcore';\n\n // local-dev.ts is the local gateway: a continuous MCP aggregator chaining\n // onto attached MCP servers' dev targets (added by the mcp-connection\n // generator), so a single `nx dev <gateway>` boots the gateway and every\n // attached MCP server together.\n //\n // `serve` exists for parity with other generators; the deployed Gateway is\n // a managed AWS resource, so `serve`-mode agents talk to it via runtime\n // config and the local gateway sits idle.\n const localGatewayTarget = (port: number) => ({\n executor: 'nx:run-commands' as const,\n continuous: true,\n options: {\n command: 'tsx local-dev.ts',\n cwd: '{projectRoot}',\n env: { PORT: `${port}` },\n },\n dependsOn: [] as Array<string | { projects: string[]; target: string }>,\n });\n let project: ProjectConfiguration;\n if (projectExists(tree, fullyQualifiedName)) {\n project = readProjectConfigurationUnqualified(tree, fullyQualifiedName);\n } else {\n addProjectConfiguration(tree, fullyQualifiedName, {\n name: fullyQualifiedName,\n root: projectRoot,\n projectType: 'library',\n sourceRoot: projectRoot,\n tags: [],\n targets: {},\n metadata: {\n generator: AGENTCORE_GATEWAY_GENERATOR_INFO.id,\n } as any,\n });\n project = readProjectConfigurationUnqualified(tree, fullyQualifiedName);\n }\n // Ensure the project has its own package.json so its runtime dependencies\n // (added below) are declared in it rather than the workspace root.\n ensureProjectPackageJson(tree, {\n dir: projectRoot,\n fullyQualifiedName,\n });\n const port = assignPort(tree, project, 8100);\n // A gateway is its own standalone project, so it uses plain `serve` / `dev`\n // targets. Re-run: keep existing targets (their dependsOn may have been\n // populated by the mcp-connection generator), just ensure both exist.\n project.targets ??= {};\n project.targets['serve'] ??= localGatewayTarget(port);\n project.targets['dev'] ??= localGatewayTarget(port);\n updateProjectConfiguration(tree, project.name, project);\n\n // Scaffold the gateway project: local-dev.ts (+ Cedar policies if requested)\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'project', protocol),\n projectRoot,\n {\n nameClassName,\n nameKebabCase: name,\n port,\n attachedMcpServers: [],\n attachedAgents: [],\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n if (cedarPolicy) {\n // The default permit-all policy differs by auth type: AgentCore represents\n // IAM callers as `AgentCore::IamEntity` and Cognito/JWT callers as\n // `AgentCore::OAuthUser`, so the two policies match different principals.\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'cedar'),\n projectRoot,\n { nameClassName, auth },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n }\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 // 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: AgentCoreGatewayMetadata = {\n name,\n rc: nameClassName,\n protocol,\n auth,\n port,\n ...(iac ? { iac } : {}),\n };\n\n addGeneratorMetadata(\n tree,\n fullyQualifiedName,\n AGENTCORE_GATEWAY_GENERATOR_INFO,\n metadata,\n );\n\n addTsDependencies(tree, DEPENDENCIES, { metadata, projectRoot });\n\n // Wire up infra (CDK or Terraform); re-running with infra=agentcore adds\n // the infrastructure to a previously infra-less gateway.\n\n if (infra === 'agentcore') {\n await sharedConstructsGenerator(tree, { iac }, DEPENDENCIES);\n\n await addAgentCoreGatewayInfra(\n tree,\n {\n gatewayNameClassName: nameClassName,\n gatewayNameKebabCase: name,\n projectName: fullyQualifiedName,\n projectDirectory: projectRoot,\n cedarPolicy,\n auth,\n protocol,\n iac,\n },\n DEPENDENCIES,\n );\n }\n\n await addGeneratorMetricsIfApplicable(tree, [\n AGENTCORE_GATEWAY_GENERATOR_INFO,\n ]);\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript'],\n });\n};\n\n/**\n * Gateway details stored in the gateway project's metadata.\n */\nexport interface AgentCoreGatewayMetadata extends IacMetadata {\n name: string;\n rc: string;\n protocol: string;\n auth: string;\n port: number;\n}\n\n/**\n * Read a gateway project's metadata, validating it was generated by the\n * agentcore-gateway generator.\n */\nexport const readAgentCoreGatewayMetadata = (\n project: ProjectConfiguration,\n): AgentCoreGatewayMetadata => {\n const metadata = project.metadata as any;\n if (metadata?.generator !== AGENTCORE_GATEWAY_GENERATOR_INFO.id) {\n throw new Error(\n `Project '${project.name}' was not generated by the '${AGENTCORE_GATEWAY_GENERATOR_INFO.id}' generator.`,\n );\n }\n return metadata as AgentCoreGatewayMetadata;\n};\n\nexport default agentcoreGatewayGenerator;\n"],"names":["addProjectConfiguration","generateFiles","joinPathFragments","logger","OverwriteStrategy","updateProjectConfiguration","addTsDependencies","AGENT_CORE_CONSTRUCTS_DEPENDENCIES","AGENT_CORE_CONSTRUCTS_PY_DEPENDENCIES","addAgentCoreGatewayInfra","declareDependencies","ownedElsewhere","formatFilesInSubtree","resolveIac","installDependencies","addGeneratorMetricsIfApplicable","kebabCase","toClassName","getNpmScopePrefix","addGeneratorMetadata","getGeneratorInfo","projectExists","readProjectConfigurationUnqualified","assignPort","ensureProjectPackageJson","SHARED_CONSTRUCTS_DEPENDENCIES","sharedConstructsGenerator","DEPENDENCIES","ts","name","when","m","protocol","dev","root","py","AGENTCORE_GATEWAY_GENERATOR_INFO","filename","agentcoreGatewayGenerator","tree","options","nameClassName","parentDir","directory","subDir","subDirectory","projectRoot","fullyQualifiedName","auth","cedarPolicy","warn","infra","localGatewayTarget","port","executor","continuous","command","cwd","env","PORT","dependsOn","project","projectType","sourceRoot","tags","targets","metadata","generator","id","dir","dirname","nameKebabCase","attachedMcpServers","attachedAgents","overwriteStrategy","KeepExisting","iac","undefined","rc","gatewayNameClassName","gatewayNameKebabCase","projectName","projectDirectory","preferInstallDependencies","languages","readAgentCoreGatewayMetadata","Error"],"mappings":"AAAA;;;CAGC,GACD,SACEA,uBAAuB,EAEvBC,aAAa,EACbC,iBAAiB,EACjBC,MAAM,EACNC,iBAAiB,EAGjBC,0BAA0B,QACrB,aAAa;AACpB,SAASC,iBAAiB,QAAQ,+BAA+B;AACjE,SACEC,kCAAkC,EAClCC,qCAAqC,EACrCC,wBAAwB,QACnB,0DAA0D;AACjE,SACEC,mBAAmB,EACnBC,cAAc,QACT,oCAAoC;AAC3C,SAASC,oBAAoB,QAAQ,qBAAqB;AAC1D,SAASC,UAAU,QAAQ,kBAAkB;AAC7C,SAASC,mBAAmB,QAAQ,sBAAsB;AAC1D,SAASC,+BAA+B,QAAQ,sBAAsB;AACtE,SAASC,SAAS,EAAEC,WAAW,QAAQ,oBAAoB;AAC3D,SAASC,iBAAiB,QAAQ,wBAAwB;AAC1D,SACEC,oBAAoB,EACpBC,gBAAgB,EAEhBC,aAAa,EACbC,mCAAmC,QAC9B,iBAAiB;AACxB,SAASC,UAAU,QAAQ,mBAAmB;AAC9C,SAASC,wBAAwB,QAAQ,mCAAmC;AAC5E,SACEC,8BAA8B,EAC9BC,yBAAyB,QACpB,gCAAgC;AAIvC,uEAAuE;AACvE,2EAA2E;AAC3E,6BAA6B;AAC7B,OAAO,MAAMC,eAAejB,sBAAgD;IAC1EkB,IAAI;QACF;YAAEC,MAAM;YAA6BC,MAAM,CAACC,IAAMA,EAAEC,QAAQ,KAAK;QAAM;QACvE;YAAEH,MAAM;QAAU;QAClB;YAAEA,MAAM;YAAkBI,KAAK;QAAK;QACpC,gEAAgE;QAChE;YAAEJ,MAAM;YAAOI,KAAK;QAAK;QACzB;YAAEJ,MAAM;YAAcI,KAAK;QAAK;QAChC,sDAAsD;QACtD;YAAEJ,MAAM;YAAOI,KAAK;YAAMC,MAAM;QAAK;WAClCvB,eAAeJ;WACfI,eAAec;KACnB;IACDU,IAAIxB,eAAeH;AACrB,GAAG;AAEH,OAAO,MAAM4B,mCACXhB,iBAAiB,YAAYiB,QAAQ,EAAE;AAEzC,OAAO,MAAMC,4BAA4B,OACvCC,MACAC;IAEA,MAAMX,OAAOb,UAAUwB,QAAQX,IAAI;IACnC,MAAMY,gBAAgBxB,YAAYY;IAClC,MAAMa,YAAYF,QAAQG,SAAS,IAAI;IACvC,MAAMC,SAASJ,QAAQK,YAAY,IAAIhB;IACvC,MAAMiB,cAAc5C,kBAAkBwC,WAAWE;IACjD,MAAMG,qBAAqB,GAAG7B,kBAAkBqB,QAAQV,MAAM;IAE9D,0EAA0E;IAC1E,0EAA0E;IAC1E,qDAAqD;IACrD,MAAMG,WAAWQ,QAAQR,QAAQ,IAAI;IACrC,qEAAqE;IACrE,sEAAsE;IACtE,2BAA2B;IAC3B,MAAMgB,OAAOR,QAAQQ,IAAI,IAAI;IAC7B,4EAA4E;IAC5E,uEAAuE;IACvE,2EAA2E;IAC3E,oEAAoE;IACpE,uBAAuB;IACvB,IAAIhB,aAAa,UAAUQ,QAAQS,WAAW,EAAE;QAC9C9C,OAAO+C,IAAI,CACT;IAEJ;IACA,MAAMD,cAAcjB,aAAa,SAAUQ,CAAAA,QAAQS,WAAW,IAAI,IAAG;IACrE,MAAME,QAAQX,QAAQW,KAAK,IAAI;IAE/B,0EAA0E;IAC1E,sEAAsE;IACtE,yEAAyE;IACzE,gCAAgC;IAChC,EAAE;IACF,2EAA2E;IAC3E,wEAAwE;IACxE,0CAA0C;IAC1C,MAAMC,qBAAqB,CAACC,OAAkB,CAAA;YAC5CC,UAAU;YACVC,YAAY;YACZf,SAAS;gBACPgB,SAAS;gBACTC,KAAK;gBACLC,KAAK;oBAAEC,MAAM,GAAGN,MAAM;gBAAC;YACzB;YACAO,WAAW,EAAE;QACf,CAAA;IACA,IAAIC;IACJ,IAAIxC,cAAckB,MAAMQ,qBAAqB;QAC3Cc,UAAUvC,oCAAoCiB,MAAMQ;IACtD,OAAO;QACL/C,wBAAwBuC,MAAMQ,oBAAoB;YAChDlB,MAAMkB;YACNb,MAAMY;YACNgB,aAAa;YACbC,YAAYjB;YACZkB,MAAM,EAAE;YACRC,SAAS,CAAC;YACVC,UAAU;gBACRC,WAAW/B,iCAAiCgC,EAAE;YAChD;QACF;QACAP,UAAUvC,oCAAoCiB,MAAMQ;IACtD;IACA,0EAA0E;IAC1E,mEAAmE;IACnEvB,yBAAyBe,MAAM;QAC7B8B,KAAKvB;QACLC;IACF;IACA,MAAMM,OAAO9B,WAAWgB,MAAMsB,SAAS;IACvC,4EAA4E;IAC5E,wEAAwE;IACxE,sEAAsE;IACtEA,QAAQI,OAAO,KAAK,CAAC;IACrBJ,QAAQI,OAAO,CAAC,QAAQ,KAAKb,mBAAmBC;IAChDQ,QAAQI,OAAO,CAAC,MAAM,KAAKb,mBAAmBC;IAC9ChD,2BAA2BkC,MAAMsB,QAAQhC,IAAI,EAAEgC;IAE/C,6EAA6E;IAC7E5D,cACEsC,MACArC,kBAAkB,YAAYoE,OAAO,EAAE,SAAS,WAAWtC,WAC3Dc,aACA;QACEL;QACA8B,eAAe1C;QACfwB;QACAmB,oBAAoB,EAAE;QACtBC,gBAAgB,EAAE;IACpB,GACA;QAAEC,mBAAmBtE,kBAAkBuE,YAAY;IAAC;IAEtD,IAAI1B,aAAa;QACf,2EAA2E;QAC3E,mEAAmE;QACnE,0EAA0E;QAC1EhD,cACEsC,MACArC,kBAAkB,YAAYoE,OAAO,EAAE,SAAS,UAChDxB,aACA;YAAEL;YAAeO;QAAK,GACtB;YAAE0B,mBAAmBtE,kBAAkBuE,YAAY;QAAC;IAExD;IAEA,oEAAoE;IACpE,qEAAqE;IACrE,mEAAmE;IACnE,MAAMC,MACJzB,UAAU,SAAS,MAAMtC,WAAW0B,MAAMC,QAAQoC,GAAG,IAAIC;IAE3D,2EAA2E;IAC3E,6DAA6D;IAC7D,MAAMX,WAAqC;QACzCrC;QACAiD,IAAIrC;QACJT;QACAgB;QACAK;QACA,GAAIuB,MAAM;YAAEA;QAAI,IAAI,CAAC,CAAC;IACxB;IAEAzD,qBACEoB,MACAQ,oBACAX,kCACA8B;IAGF5D,kBAAkBiC,MAAMZ,cAAc;QAAEuC;QAAUpB;IAAY;IAE9D,yEAAyE;IACzE,yDAAyD;IAEzD,IAAIK,UAAU,aAAa;QACzB,MAAMzB,0BAA0Ba,MAAM;YAAEqC;QAAI,GAAGjD;QAE/C,MAAMlB,yBACJ8B,MACA;YACEwC,sBAAsBtC;YACtBuC,sBAAsBnD;YACtBoD,aAAalC;YACbmC,kBAAkBpC;YAClBG;YACAD;YACAhB;YACA4C;QACF,GACAjD;IAEJ;IAEA,MAAMZ,gCAAgCwB,MAAM;QAC1CH;KACD;IAED,MAAMxB,qBAAqB2B;IAC3B,OAAO,IACLzB,oBAAoByB,MAAMC,QAAQ2C,yBAAyB,EAAE;YAC3DC,WAAW;gBAAC;aAAa;QAC3B;AACJ,EAAE;AAaF;;;CAGC,GACD,OAAO,MAAMC,+BAA+B,CAC1CxB;IAEA,MAAMK,WAAWL,QAAQK,QAAQ;IACjC,IAAIA,UAAUC,cAAc/B,iCAAiCgC,EAAE,EAAE;QAC/D,MAAM,IAAIkB,MACR,CAAC,SAAS,EAAEzB,QAAQhC,IAAI,CAAC,4BAA4B,EAAEO,iCAAiCgC,EAAE,CAAC,YAAY,CAAC;IAE5G;IACA,OAAOF;AACT,EAAE;AAEF,eAAe5B,0BAA0B"}
|
|
1
|
+
{"version":3,"sources":["../../../../../packages/nx-plugin/src/agentcore-gateway/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n addProjectConfiguration,\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n logger,\n OverwriteStrategy,\n type ProjectConfiguration,\n type Tree,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { addTsDependencies } from '../utils/add-dependencies.js';\nimport {\n AGENT_CORE_CONSTRUCTS_DEPENDENCIES,\n AGENT_CORE_CONSTRUCTS_PY_DEPENDENCIES,\n addAgentCoreGatewayInfra,\n} from '../utils/agent-core-constructs/agent-core-constructs.js';\nimport {\n declareDependencies,\n ownedElsewhere,\n} from '../utils/declared-dependencies.js';\nimport { formatFilesInSubtree } from '../utils/format.js';\nimport { resolveIac } from '../utils/iac.js';\nimport { installDependencies } from '../utils/install.js';\nimport { addGeneratorMetricsIfApplicable } from '../utils/metrics.js';\nimport { kebabCase, toClassName } from '../utils/names.js';\nimport { getNpmScopePrefix } from '../utils/npm-scope.js';\nimport {\n addGeneratorMetadata,\n getGeneratorInfo,\n type NxGeneratorInfo,\n projectExists,\n readProjectConfigurationUnqualified,\n} from '../utils/nx.js';\nimport { assignPort } from '../utils/port.js';\nimport { ensureProjectPackageJson } from '../utils/project-package-json.js';\nimport {\n SHARED_CONSTRUCTS_DEPENDENCIES,\n sharedConstructsGenerator,\n} from '../utils/shared-constructs.js';\nimport type { IacMetadata } from '../utils/shared-constructs-constants.js';\nimport type { AgentcoreGatewayGeneratorSchema } from './schema';\n\n// The gateway's local-dev server needs these whatever the auth; only the MCP\n// SDK is protocol-specific (the http local gateway is a plain proxy).\nexport const DEPENDENCIES = declareDependencies<AgentCoreGatewayMetadata>()({\n ts: [\n { name: '@modelcontextprotocol/sdk', when: (m) => m.protocol === 'mcp' },\n { name: 'express' },\n { name: '@types/express', dev: true },\n // local-dev.ts runs via tsx, which is shared tooling.\n { name: 'tsx', dev: true, root: true },\n ...ownedElsewhere(AGENT_CORE_CONSTRUCTS_DEPENDENCIES),\n ...ownedElsewhere(SHARED_CONSTRUCTS_DEPENDENCIES),\n ],\n py: ownedElsewhere(AGENT_CORE_CONSTRUCTS_PY_DEPENDENCIES),\n});\n\nexport const AGENTCORE_GATEWAY_GENERATOR_INFO: NxGeneratorInfo =\n getGeneratorInfo(import.meta.filename);\n\nexport const agentcoreGatewayGenerator = async (\n tree: Tree,\n options: AgentcoreGatewayGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const name = kebabCase(options.name);\n const nameClassName = toClassName(name);\n const parentDir = options.directory ?? 'packages';\n const subDir = options.subDirectory ?? name;\n const projectRoot = joinPathFragments(parentDir, subDir);\n const fullyQualifiedName = `${getNpmScopePrefix(tree)}${name}`;\n\n // Protocol is mcp (aggregate MCP server targets into one MCP endpoint) or\n // http (proxy agent runtime targets via path-based routing). Persisted in\n // metadata so connection generators can validate it.\n const protocol = options.protocol ?? 'mcp';\n // Inbound auth is iam (default) or cognito. Persisted in metadata so\n // connection generators can validate it (agent -> gateway connections\n // require an IAM gateway).\n const auth = options.auth ?? 'iam';\n // Cedar policies authorize MCP tool actions, which an http gateway has none\n // of — its runtime targets are plain proxied endpoints — so the policy\n // engine only applies to mcp gateways. cedarPolicy defaults to true in the\n // schema, so an http gateway quietly drops it rather than requiring\n // --cedarPolicy=false.\n if (protocol === 'http' && options.cedarPolicy) {\n logger.warn(\n 'Cedar policies authorize MCP tool actions, so cedarPolicy is ignored for http-protocol gateways.',\n );\n }\n const cedarPolicy = protocol === 'mcp' && (options.cedarPolicy ?? true);\n const infra = options.infra ?? 'agentcore';\n\n // local-dev.ts is the local gateway: a continuous MCP aggregator chaining\n // onto attached MCP servers' dev targets (added by the mcp-connection\n // generator), so a single `nx dev <gateway>` boots the gateway and every\n // attached MCP server together.\n //\n // `serve` exists for parity with other generators; the deployed Gateway is\n // a managed AWS resource, so `serve`-mode agents talk to it via runtime\n // config and the local gateway sits idle.\n const localGatewayTarget = (port: number) => ({\n executor: 'nx:run-commands' as const,\n continuous: true,\n options: {\n command: 'tsx local-dev.ts',\n cwd: '{projectRoot}',\n env: { PORT: `${port}` },\n },\n dependsOn: [] as Array<string | { projects: string[]; target: string }>,\n });\n let project: ProjectConfiguration;\n if (projectExists(tree, fullyQualifiedName)) {\n project = readProjectConfigurationUnqualified(tree, fullyQualifiedName);\n } else {\n addProjectConfiguration(tree, fullyQualifiedName, {\n name: fullyQualifiedName,\n root: projectRoot,\n projectType: 'library',\n sourceRoot: projectRoot,\n tags: [],\n targets: {},\n metadata: {\n generator: AGENTCORE_GATEWAY_GENERATOR_INFO.id,\n } as any,\n });\n project = readProjectConfigurationUnqualified(tree, fullyQualifiedName);\n }\n // Ensure the project has its own package.json so its runtime dependencies\n // (added below) are declared in it rather than the workspace root.\n ensureProjectPackageJson(tree, {\n dir: projectRoot,\n fullyQualifiedName,\n });\n const port = assignPort(tree, project, 8100);\n // A gateway is its own standalone project, so it uses plain `serve` / `dev`\n // targets. Re-run: keep existing targets (their dependsOn may have been\n // populated by the mcp-connection generator), just ensure both exist.\n project.targets ??= {};\n project.targets['serve'] ??= localGatewayTarget(port);\n project.targets['dev'] ??= localGatewayTarget(port);\n updateProjectConfiguration(tree, project.name, project);\n\n // Scaffold the gateway project: local-dev.ts (+ Cedar policies if requested)\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'project', protocol),\n projectRoot,\n {\n nameClassName,\n nameKebabCase: name,\n port,\n attachedMcpServers: [],\n attachedAgents: [],\n },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n if (cedarPolicy) {\n // The default permit-all policy differs by auth type: AgentCore represents\n // IAM callers as `AgentCore::IamEntity` and Cognito/JWT callers as\n // `AgentCore::OAuthUser`, so the two policies match different principals.\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'cedar'),\n projectRoot,\n { nameClassName, auth },\n { overwriteStrategy: OverwriteStrategy.KeepExisting },\n );\n }\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 // 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: AgentCoreGatewayMetadata = {\n name,\n rc: nameClassName,\n protocol,\n auth,\n port,\n ...(iac ? { iac } : {}),\n };\n\n addGeneratorMetadata(\n tree,\n fullyQualifiedName,\n AGENTCORE_GATEWAY_GENERATOR_INFO,\n metadata,\n );\n\n addTsDependencies(tree, DEPENDENCIES, { metadata, projectRoot });\n\n // Wire up infra (CDK or Terraform); re-running with infra=agentcore adds\n // the infrastructure to a previously infra-less gateway.\n\n if (infra === 'agentcore') {\n await sharedConstructsGenerator(tree, { iac }, DEPENDENCIES);\n\n await addAgentCoreGatewayInfra(\n tree,\n {\n gatewayNameClassName: nameClassName,\n gatewayNameKebabCase: name,\n projectName: fullyQualifiedName,\n projectDirectory: projectRoot,\n cedarPolicy,\n auth,\n protocol,\n iac,\n },\n DEPENDENCIES,\n );\n }\n\n await addGeneratorMetricsIfApplicable(tree, [\n AGENTCORE_GATEWAY_GENERATOR_INFO,\n ]);\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript'],\n });\n};\n\n/**\n * Gateway details stored in the gateway project's metadata.\n */\nexport interface AgentCoreGatewayMetadata extends IacMetadata {\n name: string;\n rc: string;\n protocol: string;\n auth: string;\n port: number;\n}\n\n/**\n * Read a gateway project's metadata, validating it was generated by the\n * agentcore-gateway generator.\n */\nexport const readAgentCoreGatewayMetadata = (\n project: ProjectConfiguration,\n): AgentCoreGatewayMetadata => {\n const metadata = project.metadata as any;\n if (metadata?.generator !== AGENTCORE_GATEWAY_GENERATOR_INFO.id) {\n throw new Error(\n `Project '${project.name}' was not generated by the '${AGENTCORE_GATEWAY_GENERATOR_INFO.id}' generator.`,\n );\n }\n return metadata as AgentCoreGatewayMetadata;\n};\n\nexport default agentcoreGatewayGenerator;\n"],"names":["addProjectConfiguration","generateFiles","joinPathFragments","logger","OverwriteStrategy","updateProjectConfiguration","addTsDependencies","AGENT_CORE_CONSTRUCTS_DEPENDENCIES","AGENT_CORE_CONSTRUCTS_PY_DEPENDENCIES","addAgentCoreGatewayInfra","declareDependencies","ownedElsewhere","formatFilesInSubtree","resolveIac","installDependencies","addGeneratorMetricsIfApplicable","kebabCase","toClassName","getNpmScopePrefix","addGeneratorMetadata","getGeneratorInfo","projectExists","readProjectConfigurationUnqualified","assignPort","ensureProjectPackageJson","SHARED_CONSTRUCTS_DEPENDENCIES","sharedConstructsGenerator","DEPENDENCIES","ts","name","when","m","protocol","dev","root","py","AGENTCORE_GATEWAY_GENERATOR_INFO","filename","agentcoreGatewayGenerator","tree","options","nameClassName","parentDir","directory","subDir","subDirectory","projectRoot","fullyQualifiedName","auth","cedarPolicy","warn","infra","localGatewayTarget","port","executor","continuous","command","cwd","env","PORT","dependsOn","project","projectType","sourceRoot","tags","targets","metadata","generator","id","dir","dirname","nameKebabCase","attachedMcpServers","attachedAgents","overwriteStrategy","KeepExisting","iac","undefined","rc","gatewayNameClassName","gatewayNameKebabCase","projectName","projectDirectory","preferInstallDependencies","languages","readAgentCoreGatewayMetadata","Error"],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import { type MigrationReturnObject, type Tree } from '@nx/devkit';
|
|
6
|
+
export default function migration(tree: Tree): Promise<MigrationReturnObject>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/ import { joinPathFragments } from "@nx/devkit";
|
|
5
|
+
import { GRIT_INSERT_PLACEHOLDER, insertViaGritQL, matchGritQL } from "../../../utils/ast.js";
|
|
6
|
+
import { formatFilesInSubtree } from "../../../utils/format.js";
|
|
7
|
+
import { PACKAGES_DIR, SHARED_TERRAFORM_DIR } from "../../../utils/shared-constructs-constants.js";
|
|
8
|
+
/**
|
|
9
|
+
* Re-export the core dynamodb module's `table_name`, `table_arn` and
|
|
10
|
+
* `kms_key_arn` from each vended per-table Terraform app module
|
|
11
|
+
* (`app/dynamodb/<name>/<name>.tf`).
|
|
12
|
+
*
|
|
13
|
+
* The app module is what a root configuration instantiates, so without these
|
|
14
|
+
* outputs a root module cannot reference the table or its encryption key at
|
|
15
|
+
* all — for example to grant a consumer access to it.
|
|
16
|
+
*
|
|
17
|
+
* These files are generated with `KeepExisting`, so an upgraded workspace keeps
|
|
18
|
+
* a module with no outputs until this runs. Diverged files are left untouched
|
|
19
|
+
* and reported via `nextSteps`.
|
|
20
|
+
*/ const TERRAFORM_DYNAMODB_APP_DIR = `${PACKAGES_DIR}/${SHARED_TERRAFORM_DIR}/src/app/dynamodb`;
|
|
21
|
+
const divergedMessage = (filePath)=>`${filePath}: has diverged from the generated shape - left untouched. To reference the table from your root Terraform configuration, add table_name, table_arn and kms_key_arn outputs here forwarding the equivalent module.dynamodb_table attributes (see the ts#dynamodb generator's dynamodb app template).`;
|
|
22
|
+
const hcl = (pattern)=>`language hcl\n${pattern}`;
|
|
23
|
+
const OUTPUTS_TEXT = [
|
|
24
|
+
'output "table_name" {',
|
|
25
|
+
' description = "Name of the DynamoDB table"',
|
|
26
|
+
' value = module.dynamodb_table.table_name',
|
|
27
|
+
'}',
|
|
28
|
+
'',
|
|
29
|
+
'output "table_arn" {',
|
|
30
|
+
' description = "ARN of the DynamoDB table, for use in IAM policies granting access to the table. Suffix with /index/* to cover its global secondary indexes."',
|
|
31
|
+
' value = module.dynamodb_table.table_arn',
|
|
32
|
+
'}',
|
|
33
|
+
'',
|
|
34
|
+
'output "kms_key_arn" {',
|
|
35
|
+
' description = "ARN of the KMS key used to encrypt the DynamoDB table, for use in IAM policies granting access to the table. Null when using the AWS owned key (encryption = DEFAULT)."',
|
|
36
|
+
' value = module.dynamodb_table.kms_key_arn',
|
|
37
|
+
'}'
|
|
38
|
+
].join('\n');
|
|
39
|
+
export default async function migration(tree) {
|
|
40
|
+
const nextSteps = [];
|
|
41
|
+
if (!tree.exists(TERRAFORM_DYNAMODB_APP_DIR)) {
|
|
42
|
+
return {
|
|
43
|
+
nextSteps
|
|
44
|
+
}; // This workspace has no Terraform dynamodb modules.
|
|
45
|
+
}
|
|
46
|
+
for (const dirName of tree.children(TERRAFORM_DYNAMODB_APP_DIR)){
|
|
47
|
+
const filePath = joinPathFragments(TERRAFORM_DYNAMODB_APP_DIR, dirName, `${dirName}.tf`);
|
|
48
|
+
if (!tree.exists(filePath)) {
|
|
49
|
+
continue; // Not a dynamodb app module directory.
|
|
50
|
+
}
|
|
51
|
+
if (await matchGritQL(tree, filePath, hcl('`output "table_arn" { $_ }`'))) {
|
|
52
|
+
continue; // Already migrated.
|
|
53
|
+
}
|
|
54
|
+
const RUNTIME_CONFIG_MODULE_BLOCK = hcl('`module "add_to_runtime_config" { $_ }`');
|
|
55
|
+
if (!await matchGritQL(tree, filePath, RUNTIME_CONFIG_MODULE_BLOCK)) {
|
|
56
|
+
nextSteps.push(divergedMessage(filePath));
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
// Appended after the runtime config module call, which the template ends
|
|
60
|
+
// with, matching where the generator now writes the outputs.
|
|
61
|
+
await insertViaGritQL(tree, filePath, hcl(`\`module "add_to_runtime_config" { $body }\` => \`module "add_to_runtime_config" {\n $body\n}\n\n${GRIT_INSERT_PLACEHOLDER}\``), OUTPUTS_TEXT);
|
|
62
|
+
}
|
|
63
|
+
await formatFilesInSubtree(tree);
|
|
64
|
+
return {
|
|
65
|
+
nextSteps
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
//# sourceMappingURL=migration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/latest/dynamodb-terraform-app-module-outputs/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n joinPathFragments,\n type MigrationReturnObject,\n type Tree,\n} from '@nx/devkit';\nimport {\n GRIT_INSERT_PLACEHOLDER,\n insertViaGritQL,\n matchGritQL,\n} from '../../../utils/ast.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport {\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n} from '../../../utils/shared-constructs-constants.js';\n\n/**\n * Re-export the core dynamodb module's `table_name`, `table_arn` and\n * `kms_key_arn` from each vended per-table Terraform app module\n * (`app/dynamodb/<name>/<name>.tf`).\n *\n * The app module is what a root configuration instantiates, so without these\n * outputs a root module cannot reference the table or its encryption key at\n * all — for example to grant a consumer access to it.\n *\n * These files are generated with `KeepExisting`, so an upgraded workspace keeps\n * a module with no outputs until this runs. Diverged files are left untouched\n * and reported via `nextSteps`.\n */\n\nconst TERRAFORM_DYNAMODB_APP_DIR = `${PACKAGES_DIR}/${SHARED_TERRAFORM_DIR}/src/app/dynamodb`;\n\nconst divergedMessage = (filePath: string) =>\n `${filePath}: has diverged from the generated shape - left untouched. To reference the table from your root Terraform configuration, add table_name, table_arn and kms_key_arn outputs here forwarding the equivalent module.dynamodb_table attributes (see the ts#dynamodb generator's dynamodb app template).`;\n\nconst hcl = (pattern: string) => `language hcl\\n${pattern}`;\n\nconst OUTPUTS_TEXT = [\n 'output \"table_name\" {',\n ' description = \"Name of the DynamoDB table\"',\n ' value = module.dynamodb_table.table_name',\n '}',\n '',\n 'output \"table_arn\" {',\n ' description = \"ARN of the DynamoDB table, for use in IAM policies granting access to the table. Suffix with /index/* to cover its global secondary indexes.\"',\n ' value = module.dynamodb_table.table_arn',\n '}',\n '',\n 'output \"kms_key_arn\" {',\n ' description = \"ARN of the KMS key used to encrypt the DynamoDB table, for use in IAM policies granting access to the table. Null when using the AWS owned key (encryption = DEFAULT).\"',\n ' value = module.dynamodb_table.kms_key_arn',\n '}',\n].join('\\n');\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n if (!tree.exists(TERRAFORM_DYNAMODB_APP_DIR)) {\n return { nextSteps }; // This workspace has no Terraform dynamodb modules.\n }\n\n for (const dirName of tree.children(TERRAFORM_DYNAMODB_APP_DIR)) {\n const filePath = joinPathFragments(\n TERRAFORM_DYNAMODB_APP_DIR,\n dirName,\n `${dirName}.tf`,\n );\n if (!tree.exists(filePath)) {\n continue; // Not a dynamodb app module directory.\n }\n\n if (await matchGritQL(tree, filePath, hcl('`output \"table_arn\" { $_ }`'))) {\n continue; // Already migrated.\n }\n\n const RUNTIME_CONFIG_MODULE_BLOCK = hcl(\n '`module \"add_to_runtime_config\" { $_ }`',\n );\n if (!(await matchGritQL(tree, filePath, RUNTIME_CONFIG_MODULE_BLOCK))) {\n nextSteps.push(divergedMessage(filePath));\n continue;\n }\n\n // Appended after the runtime config module call, which the template ends\n // with, matching where the generator now writes the outputs.\n await insertViaGritQL(\n tree,\n filePath,\n hcl(\n `\\`module \"add_to_runtime_config\" { $body }\\` => \\`module \"add_to_runtime_config\" {\\n $body\\n}\\n\\n${GRIT_INSERT_PLACEHOLDER}\\``,\n ),\n OUTPUTS_TEXT,\n );\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["joinPathFragments","GRIT_INSERT_PLACEHOLDER","insertViaGritQL","matchGritQL","formatFilesInSubtree","PACKAGES_DIR","SHARED_TERRAFORM_DIR","TERRAFORM_DYNAMODB_APP_DIR","divergedMessage","filePath","hcl","pattern","OUTPUTS_TEXT","join","migration","tree","nextSteps","exists","dirName","children","RUNTIME_CONFIG_MODULE_BLOCK","push"],"mappings":"AAAA;;;CAGC,GACD,SACEA,iBAAiB,QAGZ,aAAa;AACpB,SACEC,uBAAuB,EACvBC,eAAe,EACfC,WAAW,QACN,wBAAwB;AAC/B,SAASC,oBAAoB,QAAQ,2BAA2B;AAChE,SACEC,YAAY,EACZC,oBAAoB,QACf,gDAAgD;AAEvD;;;;;;;;;;;;CAYC,GAED,MAAMC,6BAA6B,GAAGF,aAAa,CAAC,EAAEC,qBAAqB,iBAAiB,CAAC;AAE7F,MAAME,kBAAkB,CAACC,WACvB,GAAGA,SAAS,mSAAmS,CAAC;AAElT,MAAMC,MAAM,CAACC,UAAoB,CAAC,cAAc,EAAEA,SAAS;AAE3D,MAAMC,eAAe;IACnB;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACD,CAACC,IAAI,CAAC;AAEP,eAAe,eAAeC,UAC5BC,IAAU;IAEV,MAAMC,YAAsB,EAAE;IAE9B,IAAI,CAACD,KAAKE,MAAM,CAACV,6BAA6B;QAC5C,OAAO;YAAES;QAAU,GAAG,oDAAoD;IAC5E;IAEA,KAAK,MAAME,WAAWH,KAAKI,QAAQ,CAACZ,4BAA6B;QAC/D,MAAME,WAAWT,kBACfO,4BACAW,SACA,GAAGA,QAAQ,GAAG,CAAC;QAEjB,IAAI,CAACH,KAAKE,MAAM,CAACR,WAAW;YAC1B,UAAU,uCAAuC;QACnD;QAEA,IAAI,MAAMN,YAAYY,MAAMN,UAAUC,IAAI,iCAAiC;YACzE,UAAU,oBAAoB;QAChC;QAEA,MAAMU,8BAA8BV,IAClC;QAEF,IAAI,CAAE,MAAMP,YAAYY,MAAMN,UAAUW,8BAA+B;YACrEJ,UAAUK,IAAI,CAACb,gBAAgBC;YAC/B;QACF;QAEA,yEAAyE;QACzE,6DAA6D;QAC7D,MAAMP,gBACJa,MACAN,UACAC,IACE,CAAC,kGAAkG,EAAET,wBAAwB,EAAE,CAAC,GAElIW;IAEJ;IAEA,MAAMR,qBAAqBW;IAE3B,OAAO;QAAEC;IAAU;AACrB"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`terraform-data-resource-destroy-protection migration > should protect the aurora cluster and pin its key window 1`] = `
|
|
4
|
+
"resource "aws_kms_key" "database" {
|
|
5
|
+
description = "KMS key for Aurora cluster \${var.name}"
|
|
6
|
+
enable_key_rotation = var.enable_key_rotation
|
|
7
|
+
|
|
8
|
+
deletion_window_in_days = 30
|
|
9
|
+
|
|
10
|
+
tags = merge(var.tags, {
|
|
11
|
+
Name = "\${var.name}-aurora"
|
|
12
|
+
})
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
resource "aws_rds_cluster" "database" {
|
|
16
|
+
cluster_identifier = local.cluster_name
|
|
17
|
+
engine = var.engine
|
|
18
|
+
storage_encrypted = true
|
|
19
|
+
kms_key_id = aws_kms_key.database.arn
|
|
20
|
+
deletion_protection = var.deletion_protection
|
|
21
|
+
skip_final_snapshot = var.skip_final_snapshot
|
|
22
|
+
|
|
23
|
+
serverlessv2_scaling_configuration {
|
|
24
|
+
min_capacity = var.serverless_min_capacity
|
|
25
|
+
max_capacity = var.serverless_max_capacity
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
tags = merge(var.tags, {
|
|
29
|
+
Name = "\${var.name}-aurora"
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
lifecycle {
|
|
33
|
+
prevent_destroy = true
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
"
|
|
37
|
+
`;
|
|
38
|
+
|
|
39
|
+
exports[`terraform-data-resource-destroy-protection migration > should protect the dynamodb table and pin its key window 1`] = `
|
|
40
|
+
"resource "aws_kms_key" "table" {
|
|
41
|
+
count = local.create_table_key ? 1 : 0
|
|
42
|
+
|
|
43
|
+
description = "KMS key for DynamoDB table \${var.name}"
|
|
44
|
+
enable_key_rotation = var.enable_key_rotation
|
|
45
|
+
|
|
46
|
+
deletion_window_in_days = 30
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
resource "aws_dynamodb_table" "table" {
|
|
50
|
+
name = var.name
|
|
51
|
+
billing_mode = var.billing_mode
|
|
52
|
+
hash_key = "pk"
|
|
53
|
+
range_key = "sk"
|
|
54
|
+
deletion_protection_enabled = var.deletion_protection_enabled
|
|
55
|
+
|
|
56
|
+
attribute {
|
|
57
|
+
name = "pk"
|
|
58
|
+
type = "S"
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
point_in_time_recovery {
|
|
62
|
+
enabled = var.point_in_time_recovery_enabled
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
server_side_encryption {
|
|
66
|
+
enabled = var.encryption != "DEFAULT"
|
|
67
|
+
kms_key_arn = local.table_kms_key_arn
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
lifecycle {
|
|
71
|
+
prevent_destroy = true
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
"
|
|
75
|
+
`;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/ import { applyGritQL, matchGritQL } from "../../../utils/ast.js";
|
|
5
|
+
import { formatFilesInSubtree } from "../../../utils/format.js";
|
|
6
|
+
import { PACKAGES_DIR, SHARED_TERRAFORM_DIR } from "../../../utils/shared-constructs-constants.js";
|
|
7
|
+
/**
|
|
8
|
+
* Bring existing workspaces up to the destroy protection the generators now
|
|
9
|
+
* vend on the data-bearing Terraform resources:
|
|
10
|
+
*
|
|
11
|
+
* - The DynamoDB table and the Aurora cluster gain
|
|
12
|
+
* `lifecycle { prevent_destroy = true }`. This is a second, independent layer
|
|
13
|
+
* on top of the service-side `deletion_protection_enabled` /
|
|
14
|
+
* `deletion_protection` flags, matching the two guards the CDK constructs
|
|
15
|
+
* already have (`deletionProtection` plus `RemovalPolicy.RETAIN`). Without it,
|
|
16
|
+
* clearing the service-side flag destroys the data in the same apply.
|
|
17
|
+
* `prevent_destroy` cannot reference a variable, so it is vended as a literal
|
|
18
|
+
* and removed to tear down.
|
|
19
|
+
* - Their KMS keys pin `deletion_window_in_days = 30`, the provider maximum and
|
|
20
|
+
* the CDK default. Restoring either resource from a point-in-time backup or
|
|
21
|
+
* snapshot requires its key, so the window in which a scheduled key deletion
|
|
22
|
+
* can still be cancelled matters as much as the backup itself.
|
|
23
|
+
*
|
|
24
|
+
* These files are generated with `KeepExisting`, so without this an upgraded
|
|
25
|
+
* workspace keeps the weaker single-layer protection. Diverged files are left
|
|
26
|
+
* untouched and reported via `nextSteps`.
|
|
27
|
+
*/ const TERRAFORM_DYNAMODB_FILE = `${PACKAGES_DIR}/${SHARED_TERRAFORM_DIR}/src/core/dynamodb/dynamodb.tf`;
|
|
28
|
+
const TERRAFORM_AURORA_FILE = `${PACKAGES_DIR}/${SHARED_TERRAFORM_DIR}/src/core/rdb/aurora/aurora.tf`;
|
|
29
|
+
const hcl = (pattern)=>`language hcl\n${pattern}`;
|
|
30
|
+
const divergedMessage = (filePath, resource)=>`${filePath}: has diverged from the generated shape - left untouched. To protect the ${resource} from being destroyed when the service-side deletion protection flag is cleared, add \`lifecycle { prevent_destroy = true }\` to it, and set \`deletion_window_in_days = 30\` on its KMS key.`;
|
|
31
|
+
/**
|
|
32
|
+
* Add the maximum KMS pending window to a key that omits it, so a scheduled
|
|
33
|
+
* deletion stays cancellable for as long as the provider allows.
|
|
34
|
+
*/ const migrateKmsKey = async (tree, filePath, keyLabel)=>{
|
|
35
|
+
const keyBlock = hcl(`\`resource "aws_kms_key" "${keyLabel}" { $props }\``);
|
|
36
|
+
// Already pinned - nothing to do.
|
|
37
|
+
if (await matchGritQL(tree, filePath, hcl(`\`resource "aws_kms_key" "${keyLabel}" { $props }\` where { $props <: contains \`deletion_window_in_days = $_\` }`))) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (!await matchGritQL(tree, filePath, keyBlock)) {
|
|
41
|
+
return; // Reported by the caller, which matches the data resource too.
|
|
42
|
+
}
|
|
43
|
+
await applyGritQL(tree, filePath, hcl(`\`resource "aws_kms_key" "${keyLabel}" { $props }\` where { $props <: contains \`enable_key_rotation = $rotation\` => \`enable_key_rotation = $rotation\n\n deletion_window_in_days = 30\` }`));
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Add `lifecycle { prevent_destroy = true }` to a data-bearing resource.
|
|
47
|
+
*/ const migrateDataResource = async (tree, filePath, resourceType, resourceLabel, nextSteps, description)=>{
|
|
48
|
+
const resourceBlock = hcl(`\`resource "${resourceType}" "${resourceLabel}" { $props }\``);
|
|
49
|
+
if (!await matchGritQL(tree, filePath, resourceBlock)) {
|
|
50
|
+
nextSteps.push(divergedMessage(filePath, description));
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
// Already guarded - keep the user's block, whatever it is set to.
|
|
54
|
+
if (await matchGritQL(tree, filePath, hcl(`\`resource "${resourceType}" "${resourceLabel}" { $props }\` where { $props <: contains \`prevent_destroy = $_\` }`))) {
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
await applyGritQL(tree, filePath, hcl(`\`resource "${resourceType}" "${resourceLabel}" { $props }\` => \`resource "${resourceType}" "${resourceLabel}" {\n $props\n\n lifecycle {\n prevent_destroy = true\n }\n}\``));
|
|
58
|
+
return true;
|
|
59
|
+
};
|
|
60
|
+
export default async function migration(tree) {
|
|
61
|
+
const nextSteps = [];
|
|
62
|
+
if (tree.exists(TERRAFORM_DYNAMODB_FILE)) {
|
|
63
|
+
if (await migrateDataResource(tree, TERRAFORM_DYNAMODB_FILE, 'aws_dynamodb_table', 'table', nextSteps, 'DynamoDB table')) {
|
|
64
|
+
await migrateKmsKey(tree, TERRAFORM_DYNAMODB_FILE, 'table');
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (tree.exists(TERRAFORM_AURORA_FILE)) {
|
|
68
|
+
if (await migrateDataResource(tree, TERRAFORM_AURORA_FILE, 'aws_rds_cluster', 'database', nextSteps, 'Aurora cluster')) {
|
|
69
|
+
await migrateKmsKey(tree, TERRAFORM_AURORA_FILE, 'database');
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
await formatFilesInSubtree(tree);
|
|
73
|
+
return {
|
|
74
|
+
nextSteps
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
//# sourceMappingURL=migration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/latest/terraform-data-resource-destroy-protection/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport type { MigrationReturnObject, Tree } from '@nx/devkit';\nimport { applyGritQL, matchGritQL } from '../../../utils/ast.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport {\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n} from '../../../utils/shared-constructs-constants.js';\n\n/**\n * Bring existing workspaces up to the destroy protection the generators now\n * vend on the data-bearing Terraform resources:\n *\n * - The DynamoDB table and the Aurora cluster gain\n * `lifecycle { prevent_destroy = true }`. This is a second, independent layer\n * on top of the service-side `deletion_protection_enabled` /\n * `deletion_protection` flags, matching the two guards the CDK constructs\n * already have (`deletionProtection` plus `RemovalPolicy.RETAIN`). Without it,\n * clearing the service-side flag destroys the data in the same apply.\n * `prevent_destroy` cannot reference a variable, so it is vended as a literal\n * and removed to tear down.\n * - Their KMS keys pin `deletion_window_in_days = 30`, the provider maximum and\n * the CDK default. Restoring either resource from a point-in-time backup or\n * snapshot requires its key, so the window in which a scheduled key deletion\n * can still be cancelled matters as much as the backup itself.\n *\n * These files are generated with `KeepExisting`, so without this an upgraded\n * workspace keeps the weaker single-layer protection. Diverged files are left\n * untouched and reported via `nextSteps`.\n */\n\nconst TERRAFORM_DYNAMODB_FILE = `${PACKAGES_DIR}/${SHARED_TERRAFORM_DIR}/src/core/dynamodb/dynamodb.tf`;\nconst TERRAFORM_AURORA_FILE = `${PACKAGES_DIR}/${SHARED_TERRAFORM_DIR}/src/core/rdb/aurora/aurora.tf`;\n\nconst hcl = (pattern: string) => `language hcl\\n${pattern}`;\n\nconst divergedMessage = (filePath: string, resource: string) =>\n `${filePath}: has diverged from the generated shape - left untouched. To protect the ${resource} from being destroyed when the service-side deletion protection flag is cleared, add \\`lifecycle { prevent_destroy = true }\\` to it, and set \\`deletion_window_in_days = 30\\` on its KMS key.`;\n\n/**\n * Add the maximum KMS pending window to a key that omits it, so a scheduled\n * deletion stays cancellable for as long as the provider allows.\n */\nconst migrateKmsKey = async (\n tree: Tree,\n filePath: string,\n keyLabel: string,\n): Promise<void> => {\n const keyBlock = hcl(`\\`resource \"aws_kms_key\" \"${keyLabel}\" { $props }\\``);\n\n // Already pinned - nothing to do.\n if (\n await matchGritQL(\n tree,\n filePath,\n hcl(\n `\\`resource \"aws_kms_key\" \"${keyLabel}\" { $props }\\` where { $props <: contains \\`deletion_window_in_days = $_\\` }`,\n ),\n )\n ) {\n return;\n }\n\n if (!(await matchGritQL(tree, filePath, keyBlock))) {\n return; // Reported by the caller, which matches the data resource too.\n }\n\n await applyGritQL(\n tree,\n filePath,\n hcl(\n `\\`resource \"aws_kms_key\" \"${keyLabel}\" { $props }\\` where { $props <: contains \\`enable_key_rotation = $rotation\\` => \\`enable_key_rotation = $rotation\\n\\n deletion_window_in_days = 30\\` }`,\n ),\n );\n};\n\n/**\n * Add `lifecycle { prevent_destroy = true }` to a data-bearing resource.\n */\nconst migrateDataResource = async (\n tree: Tree,\n filePath: string,\n resourceType: string,\n resourceLabel: string,\n nextSteps: string[],\n description: string,\n): Promise<boolean> => {\n const resourceBlock = hcl(\n `\\`resource \"${resourceType}\" \"${resourceLabel}\" { $props }\\``,\n );\n\n if (!(await matchGritQL(tree, filePath, resourceBlock))) {\n nextSteps.push(divergedMessage(filePath, description));\n return false;\n }\n\n // Already guarded - keep the user's block, whatever it is set to.\n if (\n await matchGritQL(\n tree,\n filePath,\n hcl(\n `\\`resource \"${resourceType}\" \"${resourceLabel}\" { $props }\\` where { $props <: contains \\`prevent_destroy = $_\\` }`,\n ),\n )\n ) {\n return true;\n }\n\n await applyGritQL(\n tree,\n filePath,\n hcl(\n `\\`resource \"${resourceType}\" \"${resourceLabel}\" { $props }\\` => \\`resource \"${resourceType}\" \"${resourceLabel}\" {\\n $props\\n\\n lifecycle {\\n prevent_destroy = true\\n }\\n}\\``,\n ),\n );\n\n return true;\n};\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n if (tree.exists(TERRAFORM_DYNAMODB_FILE)) {\n if (\n await migrateDataResource(\n tree,\n TERRAFORM_DYNAMODB_FILE,\n 'aws_dynamodb_table',\n 'table',\n nextSteps,\n 'DynamoDB table',\n )\n ) {\n await migrateKmsKey(tree, TERRAFORM_DYNAMODB_FILE, 'table');\n }\n }\n\n if (tree.exists(TERRAFORM_AURORA_FILE)) {\n if (\n await migrateDataResource(\n tree,\n TERRAFORM_AURORA_FILE,\n 'aws_rds_cluster',\n 'database',\n nextSteps,\n 'Aurora cluster',\n )\n ) {\n await migrateKmsKey(tree, TERRAFORM_AURORA_FILE, 'database');\n }\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["applyGritQL","matchGritQL","formatFilesInSubtree","PACKAGES_DIR","SHARED_TERRAFORM_DIR","TERRAFORM_DYNAMODB_FILE","TERRAFORM_AURORA_FILE","hcl","pattern","divergedMessage","filePath","resource","migrateKmsKey","tree","keyLabel","keyBlock","migrateDataResource","resourceType","resourceLabel","nextSteps","description","resourceBlock","push","migration","exists"],"mappings":"AAAA;;;CAGC,GAED,SAASA,WAAW,EAAEC,WAAW,QAAQ,wBAAwB;AACjE,SAASC,oBAAoB,QAAQ,2BAA2B;AAChE,SACEC,YAAY,EACZC,oBAAoB,QACf,gDAAgD;AAEvD;;;;;;;;;;;;;;;;;;;;CAoBC,GAED,MAAMC,0BAA0B,GAAGF,aAAa,CAAC,EAAEC,qBAAqB,8BAA8B,CAAC;AACvG,MAAME,wBAAwB,GAAGH,aAAa,CAAC,EAAEC,qBAAqB,8BAA8B,CAAC;AAErG,MAAMG,MAAM,CAACC,UAAoB,CAAC,cAAc,EAAEA,SAAS;AAE3D,MAAMC,kBAAkB,CAACC,UAAkBC,WACzC,GAAGD,SAAS,yEAAyE,EAAEC,SAAS,6LAA6L,CAAC;AAEhS;;;CAGC,GACD,MAAMC,gBAAgB,OACpBC,MACAH,UACAI;IAEA,MAAMC,WAAWR,IAAI,CAAC,0BAA0B,EAAEO,SAAS,cAAc,CAAC;IAE1E,kCAAkC;IAClC,IACE,MAAMb,YACJY,MACAH,UACAH,IACE,CAAC,0BAA0B,EAAEO,SAAS,4EAA4E,CAAC,IAGvH;QACA;IACF;IAEA,IAAI,CAAE,MAAMb,YAAYY,MAAMH,UAAUK,WAAY;QAClD,QAAQ,+DAA+D;IACzE;IAEA,MAAMf,YACJa,MACAH,UACAH,IACE,CAAC,0BAA0B,EAAEO,SAAS,wJAAwJ,CAAC;AAGrM;AAEA;;CAEC,GACD,MAAME,sBAAsB,OAC1BH,MACAH,UACAO,cACAC,eACAC,WACAC;IAEA,MAAMC,gBAAgBd,IACpB,CAAC,YAAY,EAAEU,aAAa,GAAG,EAAEC,cAAc,cAAc,CAAC;IAGhE,IAAI,CAAE,MAAMjB,YAAYY,MAAMH,UAAUW,gBAAiB;QACvDF,UAAUG,IAAI,CAACb,gBAAgBC,UAAUU;QACzC,OAAO;IACT;IAEA,kEAAkE;IAClE,IACE,MAAMnB,YACJY,MACAH,UACAH,IACE,CAAC,YAAY,EAAEU,aAAa,GAAG,EAAEC,cAAc,oEAAoE,CAAC,IAGxH;QACA,OAAO;IACT;IAEA,MAAMlB,YACJa,MACAH,UACAH,IACE,CAAC,YAAY,EAAEU,aAAa,GAAG,EAAEC,cAAc,8BAA8B,EAAED,aAAa,GAAG,EAAEC,cAAc,oEAAoE,CAAC;IAIxL,OAAO;AACT;AAEA,eAAe,eAAeK,UAC5BV,IAAU;IAEV,MAAMM,YAAsB,EAAE;IAE9B,IAAIN,KAAKW,MAAM,CAACnB,0BAA0B;QACxC,IACE,MAAMW,oBACJH,MACAR,yBACA,sBACA,SACAc,WACA,mBAEF;YACA,MAAMP,cAAcC,MAAMR,yBAAyB;QACrD;IACF;IAEA,IAAIQ,KAAKW,MAAM,CAAClB,wBAAwB;QACtC,IACE,MAAMU,oBACJH,MACAP,uBACA,mBACA,YACAa,WACA,mBAEF;YACA,MAAMP,cAAcC,MAAMP,uBAAuB;QACnD;IACF;IAEA,MAAMJ,qBAAqBW;IAE3B,OAAO;QAAEM;IAAU;AACrB"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
import { type MigrationReturnObject, type Tree } from '@nx/devkit';
|
|
6
|
+
export default function migration(tree: Tree): Promise<MigrationReturnObject>;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/ import { getProjects, joinPathFragments } from "@nx/devkit";
|
|
5
|
+
import { AGENTCORE_GATEWAY_GENERATOR_INFO } from "../../../agentcore-gateway/generator.js";
|
|
6
|
+
import { addDependenciesToPackageJson } from "../../../utils/dependencies.js";
|
|
7
|
+
import { formatFilesInSubtree } from "../../../utils/format.js";
|
|
8
|
+
import { PACKAGES_DIR, SHARED_TERRAFORM_DIR } from "../../../utils/shared-constructs-constants.js";
|
|
9
|
+
import { TS_VERSIONS } from "../../../utils/versions.js";
|
|
10
|
+
/**
|
|
11
|
+
* Declare `ejs` at the workspace root for Terraform gateways with Cedar
|
|
12
|
+
* policies, which is where `render-cedar.cjs` resolves it from: the script runs
|
|
13
|
+
* in the shared terraform project, which has no `package.json` of its own.
|
|
14
|
+
*/ const RENDER_SCRIPT = 'render-cedar.cjs';
|
|
15
|
+
export default async function migration(tree) {
|
|
16
|
+
const gatewaysDir = joinPathFragments(PACKAGES_DIR, SHARED_TERRAFORM_DIR, 'src', 'app', 'gateways');
|
|
17
|
+
let needsRootEjs = false;
|
|
18
|
+
for (const project of getProjects(tree).values()){
|
|
19
|
+
const metadata = project.metadata;
|
|
20
|
+
if (metadata?.generator !== AGENTCORE_GATEWAY_GENERATOR_INFO.id) {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
// Only a Terraform gateway with Cedar policies vends the render script; a
|
|
24
|
+
// CDK one resolves ejs from the shared constructs project instead.
|
|
25
|
+
if (tree.exists(joinPathFragments(gatewaysDir, metadata.name ?? '', RENDER_SCRIPT))) {
|
|
26
|
+
needsRootEjs = true;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (needsRootEjs) {
|
|
30
|
+
addDependenciesToPackageJson(tree, {}, {
|
|
31
|
+
ejs: TS_VERSIONS.ejs
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
await formatFilesInSubtree(tree);
|
|
35
|
+
return {};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
//# sourceMappingURL=migration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/latest/terraform-gateway-cedar-render-root-ejs/migration.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n getProjects,\n joinPathFragments,\n type MigrationReturnObject,\n type Tree,\n} from '@nx/devkit';\nimport { AGENTCORE_GATEWAY_GENERATOR_INFO } from '../../../agentcore-gateway/generator.js';\nimport { addDependenciesToPackageJson } from '../../../utils/dependencies.js';\nimport { formatFilesInSubtree } from '../../../utils/format.js';\nimport {\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n} from '../../../utils/shared-constructs-constants.js';\nimport { TS_VERSIONS } from '../../../utils/versions.js';\n\n/**\n * Declare `ejs` at the workspace root for Terraform gateways with Cedar\n * policies, which is where `render-cedar.cjs` resolves it from: the script runs\n * in the shared terraform project, which has no `package.json` of its own.\n */\n\nconst RENDER_SCRIPT = 'render-cedar.cjs';\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const gatewaysDir = joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n 'src',\n 'app',\n 'gateways',\n );\n let needsRootEjs = false;\n\n for (const project of getProjects(tree).values()) {\n const metadata = project.metadata as\n | { generator?: string; name?: string }\n | undefined;\n if (metadata?.generator !== AGENTCORE_GATEWAY_GENERATOR_INFO.id) {\n continue;\n }\n\n // Only a Terraform gateway with Cedar policies vends the render script; a\n // CDK one resolves ejs from the shared constructs project instead.\n if (\n tree.exists(\n joinPathFragments(gatewaysDir, metadata.name ?? '', RENDER_SCRIPT),\n )\n ) {\n needsRootEjs = true;\n }\n }\n\n if (needsRootEjs) {\n addDependenciesToPackageJson(tree, {}, { ejs: TS_VERSIONS.ejs });\n }\n\n await formatFilesInSubtree(tree);\n\n return {};\n}\n"],"names":["getProjects","joinPathFragments","AGENTCORE_GATEWAY_GENERATOR_INFO","addDependenciesToPackageJson","formatFilesInSubtree","PACKAGES_DIR","SHARED_TERRAFORM_DIR","TS_VERSIONS","RENDER_SCRIPT","migration","tree","gatewaysDir","needsRootEjs","project","values","metadata","generator","id","exists","name","ejs"],"mappings":"AAAA;;;CAGC,GACD,SACEA,WAAW,EACXC,iBAAiB,QAGZ,aAAa;AACpB,SAASC,gCAAgC,QAAQ,0CAA0C;AAC3F,SAASC,4BAA4B,QAAQ,iCAAiC;AAC9E,SAASC,oBAAoB,QAAQ,2BAA2B;AAChE,SACEC,YAAY,EACZC,oBAAoB,QACf,gDAAgD;AACvD,SAASC,WAAW,QAAQ,6BAA6B;AAEzD;;;;CAIC,GAED,MAAMC,gBAAgB;AAEtB,eAAe,eAAeC,UAC5BC,IAAU;IAEV,MAAMC,cAAcV,kBAClBI,cACAC,sBACA,OACA,OACA;IAEF,IAAIM,eAAe;IAEnB,KAAK,MAAMC,WAAWb,YAAYU,MAAMI,MAAM,GAAI;QAChD,MAAMC,WAAWF,QAAQE,QAAQ;QAGjC,IAAIA,UAAUC,cAAcd,iCAAiCe,EAAE,EAAE;YAC/D;QACF;QAEA,0EAA0E;QAC1E,mEAAmE;QACnE,IACEP,KAAKQ,MAAM,CACTjB,kBAAkBU,aAAaI,SAASI,IAAI,IAAI,IAAIX,iBAEtD;YACAI,eAAe;QACjB;IACF;IAEA,IAAIA,cAAc;QAChBT,6BAA6BO,MAAM,CAAC,GAAG;YAAEU,KAAKb,YAAYa,GAAG;QAAC;IAChE;IAEA,MAAMhB,qBAAqBM;IAE3B,OAAO,CAAC;AACV"}
|
|
@@ -126,6 +126,8 @@ resource "aws_kms_key" "table" {
|
|
|
126
126
|
description = "KMS key for DynamoDB table \${var.name}"
|
|
127
127
|
enable_key_rotation = var.enable_key_rotation
|
|
128
128
|
|
|
129
|
+
deletion_window_in_days = 30
|
|
130
|
+
|
|
129
131
|
policy = jsonencode({
|
|
130
132
|
Version = "2012-10-17"
|
|
131
133
|
Statement = [
|
|
@@ -202,6 +204,10 @@ resource "aws_dynamodb_table" "table" {
|
|
|
202
204
|
enabled = var.encryption != "DEFAULT"
|
|
203
205
|
kms_key_arn = local.table_kms_key_arn
|
|
204
206
|
}
|
|
207
|
+
|
|
208
|
+
lifecycle {
|
|
209
|
+
prevent_destroy = true
|
|
210
|
+
}
|
|
205
211
|
}
|
|
206
212
|
|
|
207
213
|
output "table_name" {
|
|
@@ -320,6 +326,21 @@ module "add_to_runtime_config" {
|
|
|
320
326
|
tableName = module.dynamodb_table.table_name
|
|
321
327
|
}
|
|
322
328
|
}
|
|
329
|
+
|
|
330
|
+
output "table_name" {
|
|
331
|
+
description = "Name of the DynamoDB table"
|
|
332
|
+
value = module.dynamodb_table.table_name
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
output "table_arn" {
|
|
336
|
+
description = "ARN of the DynamoDB table, for use in IAM policies granting access to the table. Suffix with /index/* to cover its global secondary indexes."
|
|
337
|
+
value = module.dynamodb_table.table_arn
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
output "kms_key_arn" {
|
|
341
|
+
description = "ARN of the KMS key used to encrypt the DynamoDB table, for use in IAM policies granting access to the table. Null when using the AWS owned key (encryption = DEFAULT)."
|
|
342
|
+
value = module.dynamodb_table.kms_key_arn
|
|
343
|
+
}
|
|
323
344
|
"
|
|
324
345
|
`;
|
|
325
346
|
|
|
@@ -126,6 +126,8 @@ resource "aws_kms_key" "table" {
|
|
|
126
126
|
description = "KMS key for DynamoDB table \${var.name}"
|
|
127
127
|
enable_key_rotation = var.enable_key_rotation
|
|
128
128
|
|
|
129
|
+
deletion_window_in_days = 30
|
|
130
|
+
|
|
129
131
|
policy = jsonencode({
|
|
130
132
|
Version = "2012-10-17"
|
|
131
133
|
Statement = [
|
|
@@ -202,6 +204,10 @@ resource "aws_dynamodb_table" "table" {
|
|
|
202
204
|
enabled = var.encryption != "DEFAULT"
|
|
203
205
|
kms_key_arn = local.table_kms_key_arn
|
|
204
206
|
}
|
|
207
|
+
|
|
208
|
+
lifecycle {
|
|
209
|
+
prevent_destroy = true
|
|
210
|
+
}
|
|
205
211
|
}
|
|
206
212
|
|
|
207
213
|
output "table_name" {
|
|
@@ -320,6 +326,21 @@ module "add_to_runtime_config" {
|
|
|
320
326
|
tableName = module.dynamodb_table.table_name
|
|
321
327
|
}
|
|
322
328
|
}
|
|
329
|
+
|
|
330
|
+
output "table_name" {
|
|
331
|
+
description = "Name of the DynamoDB table"
|
|
332
|
+
value = module.dynamodb_table.table_name
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
output "table_arn" {
|
|
336
|
+
description = "ARN of the DynamoDB table, for use in IAM policies granting access to the table. Suffix with /index/* to cover its global secondary indexes."
|
|
337
|
+
value = module.dynamodb_table.table_arn
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
output "kms_key_arn" {
|
|
341
|
+
description = "ARN of the KMS key used to encrypt the DynamoDB table, for use in IAM policies granting access to the table. Null when using the AWS owned key (encryption = DEFAULT)."
|
|
342
|
+
value = module.dynamodb_table.kms_key_arn
|
|
343
|
+
}
|
|
323
344
|
"
|
|
324
345
|
`;
|
|
325
346
|
|
|
@@ -1008,6 +1008,8 @@ resource "aws_kms_key" "database" {
|
|
|
1008
1008
|
description = "KMS key for Aurora cluster \${var.name}"
|
|
1009
1009
|
enable_key_rotation = var.enable_key_rotation
|
|
1010
1010
|
|
|
1011
|
+
deletion_window_in_days = 30
|
|
1012
|
+
|
|
1011
1013
|
policy = jsonencode({
|
|
1012
1014
|
Version = "2012-10-17"
|
|
1013
1015
|
Statement = [
|
|
@@ -1150,6 +1152,10 @@ resource "aws_rds_cluster" "database" {
|
|
|
1150
1152
|
tags = merge(var.tags, {
|
|
1151
1153
|
Name = "\${var.name}-aurora"
|
|
1152
1154
|
})
|
|
1155
|
+
|
|
1156
|
+
lifecycle {
|
|
1157
|
+
prevent_destroy = true
|
|
1158
|
+
}
|
|
1153
1159
|
}
|
|
1154
1160
|
|
|
1155
1161
|
resource "aws_rds_cluster_instance" "database" {
|
|
@@ -2494,6 +2500,8 @@ resource "aws_kms_key" "database" {
|
|
|
2494
2500
|
description = "KMS key for Aurora cluster \${var.name}"
|
|
2495
2501
|
enable_key_rotation = var.enable_key_rotation
|
|
2496
2502
|
|
|
2503
|
+
deletion_window_in_days = 30
|
|
2504
|
+
|
|
2497
2505
|
policy = jsonencode({
|
|
2498
2506
|
Version = "2012-10-17"
|
|
2499
2507
|
Statement = [
|
|
@@ -2636,6 +2644,10 @@ resource "aws_rds_cluster" "database" {
|
|
|
2636
2644
|
tags = merge(var.tags, {
|
|
2637
2645
|
Name = "\${var.name}-aurora"
|
|
2638
2646
|
})
|
|
2647
|
+
|
|
2648
|
+
lifecycle {
|
|
2649
|
+
prevent_destroy = true
|
|
2650
|
+
}
|
|
2639
2651
|
}
|
|
2640
2652
|
|
|
2641
2653
|
resource "aws_rds_cluster_instance" "database" {
|
|
@@ -13,8 +13,10 @@ type IACProvider = {
|
|
|
13
13
|
/**
|
|
14
14
|
* Dependencies a caller must declare to add an AgentCore Gateway construct.
|
|
15
15
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
16
|
+
* Both providers render Cedar policies with `ejs`, each from a different
|
|
17
|
+
* manifest: the CDK construct imports it from the shared constructs project,
|
|
18
|
+
* while Terraform's `render-cedar.cjs` resolves it from the workspace root,
|
|
19
|
+
* since the shared terraform project it runs in has no `package.json`.
|
|
18
20
|
*/
|
|
19
21
|
export declare const AGENT_CORE_CONSTRUCTS_DEPENDENCIES: readonly [{
|
|
20
22
|
readonly name: "ejs";
|
|
@@ -25,6 +27,11 @@ export declare const AGENT_CORE_CONSTRUCTS_DEPENDENCIES: readonly [{
|
|
|
25
27
|
}, {
|
|
26
28
|
readonly name: "@types/ejs";
|
|
27
29
|
readonly when: (m: IacMetadata) => boolean;
|
|
30
|
+
}, {
|
|
31
|
+
readonly name: "ejs";
|
|
32
|
+
readonly when: (m: IacMetadata) => boolean;
|
|
33
|
+
readonly dev: true;
|
|
34
|
+
readonly root: true;
|
|
28
35
|
}];
|
|
29
36
|
/**
|
|
30
37
|
* Python versions the generated Terraform pins in an inline `uv run --with`
|
|
@@ -7,25 +7,33 @@ import { forDependencies } from "../declared-dependencies.js";
|
|
|
7
7
|
import { addDependenciesToPackageJson } from "../dependencies.js";
|
|
8
8
|
import { esmVars } from "../module-format.js";
|
|
9
9
|
import { addDependencyToTargetIfNotPresent } from "../nx.js";
|
|
10
|
-
import {
|
|
10
|
+
import { generatedCdk, generatedTerraform, PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, SHARED_TERRAFORM_DIR } from "../shared-constructs-constants.js";
|
|
11
11
|
import { PY_VERSIONS, terraformProviderVersions, withVersions } from "../versions.js";
|
|
12
12
|
/**
|
|
13
13
|
* Dependencies a caller must declare to add an AgentCore Gateway construct.
|
|
14
14
|
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
15
|
+
* Both providers render Cedar policies with `ejs`, each from a different
|
|
16
|
+
* manifest: the CDK construct imports it from the shared constructs project,
|
|
17
|
+
* while Terraform's `render-cedar.cjs` resolves it from the workspace root,
|
|
18
|
+
* since the shared terraform project it runs in has no `package.json`.
|
|
17
19
|
*/ export const AGENT_CORE_CONSTRUCTS_DEPENDENCIES = [
|
|
18
20
|
{
|
|
19
21
|
name: 'ejs',
|
|
20
|
-
when:
|
|
22
|
+
when: generatedCdk
|
|
21
23
|
},
|
|
22
24
|
{
|
|
23
25
|
name: '@aws-sdk/client-bedrock-agentcore',
|
|
24
|
-
when:
|
|
26
|
+
when: generatedCdk
|
|
25
27
|
},
|
|
26
28
|
{
|
|
27
29
|
name: '@types/ejs',
|
|
28
|
-
when:
|
|
30
|
+
when: generatedCdk
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: 'ejs',
|
|
34
|
+
when: generatedTerraform,
|
|
35
|
+
dev: true,
|
|
36
|
+
root: true
|
|
29
37
|
}
|
|
30
38
|
];
|
|
31
39
|
/**
|
|
@@ -134,7 +142,7 @@ export const addAgentCoreGatewayInfra = async (tree, options, declaration)=>{
|
|
|
134
142
|
await addAgentCoreGatewayCDKInfra(tree, options, declaration);
|
|
135
143
|
break;
|
|
136
144
|
case 'terraform':
|
|
137
|
-
addAgentCoreGatewayTerraformInfra(tree, options);
|
|
145
|
+
addAgentCoreGatewayTerraformInfra(tree, options, declaration);
|
|
138
146
|
break;
|
|
139
147
|
}
|
|
140
148
|
updateJson(tree, joinPathFragments(PACKAGES_DIR, options.iac === 'cdk' ? SHARED_CONSTRUCTS_DIR : SHARED_TERRAFORM_DIR, 'project.json'), (config)=>{
|
|
@@ -173,7 +181,7 @@ const addAgentCoreGatewayCDKInfra = async (tree, options, declaration)=>{
|
|
|
173
181
|
'@types/ejs'
|
|
174
182
|
]), joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, 'package.json'));
|
|
175
183
|
};
|
|
176
|
-
const addAgentCoreGatewayTerraformInfra = (tree, options)=>{
|
|
184
|
+
const addAgentCoreGatewayTerraformInfra = (tree, options, declaration)=>{
|
|
177
185
|
generateFiles(tree, joinPathFragments(import.meta.dirname, 'files', 'terraform', 'core', 'agentcore-gateway'), joinPathFragments(PACKAGES_DIR, SHARED_TERRAFORM_DIR, 'src', 'core', 'agentcore-gateway'), {
|
|
178
186
|
...terraformProviderVersions()
|
|
179
187
|
}, {
|
|
@@ -199,7 +207,13 @@ const addAgentCoreGatewayTerraformInfra = (tree, options)=>{
|
|
|
199
207
|
if (tree.exists(renderScript)) {
|
|
200
208
|
tree.delete(renderScript);
|
|
201
209
|
}
|
|
210
|
+
return;
|
|
202
211
|
}
|
|
212
|
+
// render-cedar.cjs resolves ejs from the workspace root, since the shared
|
|
213
|
+
// terraform project it runs in has no package.json.
|
|
214
|
+
addDependenciesToPackageJson(tree, {}, withVersions(forDependencies(declaration), [
|
|
215
|
+
'ejs'
|
|
216
|
+
]));
|
|
203
217
|
};
|
|
204
218
|
/**
|
|
205
219
|
* Add AgentCore Harness infrastructure for the selected IaC provider.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../packages/nx-plugin/src/utils/agent-core-constructs/agent-core-constructs.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n type ProjectConfiguration,\n type Tree,\n updateJson,\n} from '@nx/devkit';\nimport { addStarExport } from '../ast.js';\nimport type { Containers } from '../containers.js';\nimport {\n type DeclaredPyDependency,\n type DeclaredTsDependency,\n type DependencyDeclaration,\n forDependencies,\n type MustDeclare,\n} from '../declared-dependencies.js';\nimport { addDependenciesToPackageJson } from '../dependencies.js';\nimport type { Iac } from '../iac.js';\nimport { esmVars } from '../module-format.js';\nimport { addDependencyToTargetIfNotPresent } from '../nx.js';\nimport {\n generatedInfrastructure,\n generatedTerraform,\n type IacMetadata,\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n SHARED_TERRAFORM_DIR,\n} from '../shared-constructs-constants.js';\nimport {\n type IPyDepVersion,\n type ITsDepVersion,\n PY_VERSIONS,\n terraformProviderVersions,\n withVersions,\n} from '../versions.js';\n\ntype IACProvider = { iac: Iac };\n\n/**\n * Dependencies a caller must declare to add an AgentCore Gateway construct.\n *\n * Gated on infrastructure having been generated, since the construct helpers only\n * run on that branch.\n */\nexport const AGENT_CORE_CONSTRUCTS_DEPENDENCIES = [\n { name: 'ejs', when: generatedInfrastructure },\n { name: '@aws-sdk/client-bedrock-agentcore', when: generatedInfrastructure },\n { name: '@types/ejs', when: generatedInfrastructure },\n] as const satisfies readonly DeclaredTsDependency<\n ITsDepVersion,\n IacMetadata\n>[];\n\n/**\n * Python versions the generated Terraform pins in an inline `uv run --with`\n * script, rather than in any `pyproject.toml`.\n *\n * Spread through `ownedElsewhere` because nothing installs them into the\n * workspace — the pin is owned so the version sync keeps it current, and gated on\n * Terraform since the CDK branch writes no such script.\n */\nexport const AGENT_CORE_CONSTRUCTS_PY_DEPENDENCIES = [\n { name: 'boto3', when: generatedTerraform },\n { name: 'httpx', when: generatedTerraform },\n { name: 'mcp', when: generatedTerraform },\n] as const satisfies readonly DeclaredPyDependency<\n IPyDepVersion,\n IacMetadata\n>[];\n\nexport type AgentCoreAuth = 'iam' | 'cognito';\n\nexport type AgentCoreSession = 's3' | 'dynamodb-s3' | 'in-memory';\n\nexport interface AddAgentCoreInfraProps {\n nameClassName: string;\n nameKebabCase: string;\n projectName: string;\n dockerImageTag: string;\n dockerOutputDir: string;\n appDirectory: string;\n serverProtocol: 'mcp' | 'http' | 'a2a';\n auth: AgentCoreAuth;\n /** How this runtime's session should be persisted. MCP servers have no session, so pass 'in-memory'. */\n session: AgentCoreSession;\n containers: Containers;\n}\n\nconst addAgentCoreInfra = async (\n tree: Tree,\n options: AddAgentCoreInfraProps & { iac: Iac },\n) => {\n switch (options.iac) {\n case 'cdk':\n await addAgentCoreCDKInfra(tree, options);\n break;\n case 'terraform':\n addAgentCoreTerraformInfra(tree, options);\n break;\n }\n\n // Update shared constructs/terraform project configuration to depend on this project\n updateJson(\n tree,\n joinPathFragments(\n PACKAGES_DIR,\n options.iac === 'cdk' ? SHARED_CONSTRUCTS_DIR : SHARED_TERRAFORM_DIR,\n 'project.json',\n ),\n (config: ProjectConfiguration) => {\n addDependencyToTargetIfNotPresent(\n config,\n 'build',\n `${options.projectName}:build`,\n );\n return config;\n },\n );\n};\n\nconst addAgentCoreCDKInfra = async (\n tree: Tree,\n options: AddAgentCoreInfraProps,\n) => {\n // Generate app specific CDK construct\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'cdk', 'app', 'agent-core'),\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'app',\n options.appDirectory,\n ),\n { ...options, ...esmVars(tree) },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n\n // Export app specific CDK construct\n await addStarExport(\n tree,\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'app',\n options.appDirectory,\n 'index.ts',\n ),\n `./${options.nameKebabCase}/${options.nameKebabCase}.js`,\n );\n await addStarExport(\n tree,\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'app',\n 'index.ts',\n ),\n `./${options.appDirectory}/index.js`,\n );\n};\n\nconst addAgentCoreTerraformInfra = (\n tree: Tree,\n options: AddAgentCoreInfraProps,\n) => {\n // Add the AgentCore shared module\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'terraform',\n 'core',\n 'agent-core',\n ),\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n 'src',\n 'core',\n 'agent-core',\n ),\n {\n containers: options.containers,\n boto3Version: PY_VERSIONS.boto3,\n ...terraformProviderVersions(),\n },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n\n // Generate app specific agent core configuration\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'terraform',\n 'app',\n 'agent-core',\n ),\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n 'src',\n 'app',\n options.appDirectory,\n ),\n { ...options, ...terraformProviderVersions() },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n};\n\nexport interface AddMcpServerInfraProps {\n mcpServerNameClassName: string;\n mcpServerNameKebabCase: string;\n projectName: string;\n dockerImageTag: string;\n dockerOutputDir: string;\n auth: AgentCoreAuth;\n containers: Containers;\n}\n\n/**\n * Add an MCP server CDK construct\n */\nexport const addMcpServerInfra = async (\n tree: Tree,\n options: AddMcpServerInfraProps & IACProvider,\n) => {\n await addAgentCoreInfra(tree, {\n nameClassName: options.mcpServerNameClassName,\n nameKebabCase: options.mcpServerNameKebabCase,\n dockerImageTag: options.dockerImageTag,\n dockerOutputDir: options.dockerOutputDir,\n projectName: options.projectName,\n appDirectory: 'mcp-servers',\n serverProtocol: 'mcp',\n iac: options.iac,\n auth: options.auth,\n // MCP servers are stateless (no conversation session to persist).\n session: 'in-memory',\n containers: options.containers,\n });\n};\n\nexport interface AddAgentInfraProps {\n agentNameClassName: string;\n agentNameKebabCase: string;\n projectName: string;\n dockerImageTag: string;\n dockerOutputDir: string;\n auth: AgentCoreAuth;\n session: AgentCoreSession;\n serverProtocol?: 'http' | 'a2a';\n containers: Containers;\n}\n\n/**\n * Add an agent CDK construct\n */\nexport const addAgentInfra = async (\n tree: Tree,\n options: AddAgentInfraProps & IACProvider,\n) => {\n await addAgentCoreInfra(tree, {\n nameClassName: options.agentNameClassName,\n nameKebabCase: options.agentNameKebabCase,\n projectName: options.projectName,\n dockerImageTag: options.dockerImageTag,\n dockerOutputDir: options.dockerOutputDir,\n appDirectory: 'agents',\n session: options.session,\n serverProtocol: options.serverProtocol ?? 'http',\n iac: options.iac,\n auth: options.auth,\n containers: options.containers,\n });\n};\n\nexport interface AddAgentCoreGatewayInfraProps {\n gatewayNameClassName: string;\n gatewayNameKebabCase: string;\n projectName: string;\n projectDirectory: string;\n cedarPolicy: boolean;\n auth: AgentCoreAuth;\n /**\n * The gateway's protocol: mcp aggregates MCP server targets, http proxies\n * agent runtime targets via path-based routing.\n */\n protocol: 'mcp' | 'http';\n}\n\nexport const addAgentCoreGatewayInfra = async <\n const D extends DependencyDeclaration,\n>(\n tree: Tree,\n options: AddAgentCoreGatewayInfraProps & IACProvider,\n declaration: D & MustDeclare<typeof AGENT_CORE_CONSTRUCTS_DEPENDENCIES, D>,\n) => {\n switch (options.iac) {\n case 'cdk':\n await addAgentCoreGatewayCDKInfra(tree, options, declaration);\n break;\n case 'terraform':\n addAgentCoreGatewayTerraformInfra(tree, options);\n break;\n }\n\n updateJson(\n tree,\n joinPathFragments(\n PACKAGES_DIR,\n options.iac === 'cdk' ? SHARED_CONSTRUCTS_DIR : SHARED_TERRAFORM_DIR,\n 'project.json',\n ),\n (config: ProjectConfiguration) => {\n addDependencyToTargetIfNotPresent(\n config,\n 'build',\n `${options.projectName}:build`,\n );\n return config;\n },\n );\n};\n\nconst addAgentCoreGatewayCDKInfra = async (\n tree: Tree,\n options: AddAgentCoreGatewayInfraProps,\n declaration: DependencyDeclaration,\n) => {\n // Generic gateway construct (readiness probe, policy engine, Cedar policy\n // loading) shared by all gateways\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'cdk',\n 'core',\n 'agentcore-gateway',\n ),\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'core',\n 'agentcore-gateway',\n ),\n { ...esmVars(tree) },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'cdk',\n 'app',\n 'agentcore-gateway',\n ),\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'app',\n 'gateways',\n ),\n {\n nameClassName: options.gatewayNameClassName,\n nameKebabCase: options.gatewayNameKebabCase,\n projectDirectory: options.projectDirectory,\n cedarPolicy: options.cedarPolicy,\n auth: options.auth,\n protocol: options.protocol,\n ...esmVars(tree),\n },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n\n await addStarExport(\n tree,\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'core',\n 'index.ts',\n ),\n './agentcore-gateway/agentcore-gateway.js',\n );\n await addStarExport(\n tree,\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'app',\n 'gateways',\n 'index.ts',\n ),\n `./${options.gatewayNameKebabCase}/${options.gatewayNameKebabCase}.js`,\n );\n await addStarExport(\n tree,\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'app',\n 'index.ts',\n ),\n './gateways/index.js',\n );\n\n // The gateway construct renders Cedar policies with ejs and its readiness\n // probe uses the AgentCore SDK client; declare both so the lint passes.\n addDependenciesToPackageJson(\n tree,\n withVersions(\n forDependencies<typeof AGENT_CORE_CONSTRUCTS_DEPENDENCIES>(declaration),\n ['ejs', '@aws-sdk/client-bedrock-agentcore'],\n ),\n withVersions(\n forDependencies<typeof AGENT_CORE_CONSTRUCTS_DEPENDENCIES>(declaration),\n ['@types/ejs'],\n ),\n joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, 'package.json'),\n );\n};\n\nconst addAgentCoreGatewayTerraformInfra = (\n tree: Tree,\n options: AddAgentCoreGatewayInfraProps,\n) => {\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'terraform',\n 'core',\n 'agentcore-gateway',\n ),\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n 'src',\n 'core',\n 'agentcore-gateway',\n ),\n { ...terraformProviderVersions() },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'terraform',\n 'app',\n 'agentcore-gateway',\n ),\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n 'src',\n 'app',\n 'gateways',\n ),\n {\n nameClassName: options.gatewayNameClassName,\n nameKebabCase: options.gatewayNameKebabCase,\n projectDirectory: options.projectDirectory,\n cedarPolicy: options.cedarPolicy,\n auth: options.auth,\n protocol: options.protocol,\n boto3Version: PY_VERSIONS.boto3,\n httpxVersion: PY_VERSIONS.httpx,\n mcpVersion: PY_VERSIONS.mcp,\n ...terraformProviderVersions(),\n },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n\n // The Cedar render script is only needed when policies are enabled\n if (!options.cedarPolicy) {\n const renderScript = joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n 'src',\n 'app',\n 'gateways',\n options.gatewayNameKebabCase,\n 'render-cedar.cjs',\n );\n if (tree.exists(renderScript)) {\n tree.delete(renderScript);\n }\n }\n};\n\nexport interface AddAgentCoreHarnessInfraProps {\n harnessNameClassName: string;\n harnessNameKebabCase: string;\n /**\n * Workspace-root-relative harness project root, eg `packages/my-harness`.\n * The `src/PROMPT.md` path both templates read is derived from it.\n */\n projectRoot: string;\n /** Leading-letter-guaranteed, 31-char-truncated resource name prefix. */\n harnessNamePrefix: string;\n}\n\n/**\n * Template substitution context shared by the CDK and Terraform harness\n * branches. Both prompt path fields carry the same workspace-root-relative\n * path, named per provider so each template's usage reads on its own.\n */\ninterface HarnessTemplateContext {\n nameClassName: string;\n nameKebabCase: string;\n harnessNamePrefix: string;\n /** Joined onto `findWorkspaceRoot()` in the CDK construct. */\n promptPathFromCdk: string;\n /** Appended to the `path.module` walk to the workspace root in Terraform. */\n promptPathFromTerraform: string;\n}\n\n/**\n * Add AgentCore Harness infrastructure for the selected IaC provider.\n *\n * Renders the provider-specific Harness infrastructure (a CDK construct or\n * a Terraform module) into the Shared Infrastructure Project with\n * `KeepExisting`, so existing files become user-owned and are never\n * rewritten by reruns.\n *\n * Unlike agents, MCP servers and gateways, no build dependency is added\n * from the shared infrastructure project to the Harness Project: generated\n * Harness infrastructure does not import Harness Project source, so a\n * dependency would only create false rebuild coupling.\n */\nexport const addAgentCoreHarnessInfra = async (\n tree: Tree,\n options: AddAgentCoreHarnessInfraProps & IACProvider,\n): Promise<void> => {\n // One resolved template context, built once and passed to both provider\n // branches. The prompt path is derived from the same projectRoot the\n // Harness Project is written to, so explicit placement needs no extra logic.\n const promptPath = joinPathFragments(options.projectRoot, 'src', 'PROMPT.md');\n const templateContext: HarnessTemplateContext = {\n nameClassName: options.harnessNameClassName,\n nameKebabCase: options.harnessNameKebabCase,\n harnessNamePrefix: options.harnessNamePrefix,\n promptPathFromCdk: promptPath,\n promptPathFromTerraform: promptPath,\n };\n\n switch (options.iac) {\n case 'cdk':\n await addAgentCoreHarnessCDKInfra(tree, templateContext);\n break;\n case 'terraform':\n addAgentCoreHarnessTerraformInfra(tree, templateContext);\n break;\n }\n};\n\nconst addAgentCoreHarnessCDKInfra = async (\n tree: Tree,\n templateContext: HarnessTemplateContext,\n) => {\n // Generate the app specific CDK construct under\n // src/app/harnesses/<kebab-case-name>/\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'cdk',\n 'app',\n 'agentcore-harness',\n ),\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'app',\n 'harnesses',\n ),\n { ...templateContext, ...esmVars(tree) },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n\n // Export the construct through the harnesses app index and the shared\n // app index. addStarExport creates a missing index file and semantically\n // deduplicates equivalent exports on reruns.\n await addStarExport(\n tree,\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'app',\n 'harnesses',\n 'index.ts',\n ),\n `./${templateContext.nameKebabCase}/${templateContext.nameKebabCase}.js`,\n );\n await addStarExport(\n tree,\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'app',\n 'index.ts',\n ),\n './harnesses/index.js',\n );\n};\n\nconst addAgentCoreHarnessTerraformInfra = (\n tree: Tree,\n templateContext: HarnessTemplateContext,\n) => {\n // Generate the app specific Terraform module under\n // src/app/harnesses/<kebab-case-name>/. No CDK files or exports are\n // created on this path.\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'terraform',\n 'app',\n 'agentcore-harness',\n ),\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n 'src',\n 'app',\n 'harnesses',\n ),\n { ...templateContext, ...terraformProviderVersions() },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n};\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","updateJson","addStarExport","forDependencies","addDependenciesToPackageJson","esmVars","addDependencyToTargetIfNotPresent","generatedInfrastructure","generatedTerraform","PACKAGES_DIR","SHARED_CONSTRUCTS_DIR","SHARED_TERRAFORM_DIR","PY_VERSIONS","terraformProviderVersions","withVersions","AGENT_CORE_CONSTRUCTS_DEPENDENCIES","name","when","AGENT_CORE_CONSTRUCTS_PY_DEPENDENCIES","addAgentCoreInfra","tree","options","iac","addAgentCoreCDKInfra","addAgentCoreTerraformInfra","config","projectName","dirname","appDirectory","overwriteStrategy","KeepExisting","nameKebabCase","containers","boto3Version","boto3","addMcpServerInfra","nameClassName","mcpServerNameClassName","mcpServerNameKebabCase","dockerImageTag","dockerOutputDir","serverProtocol","auth","session","addAgentInfra","agentNameClassName","agentNameKebabCase","addAgentCoreGatewayInfra","declaration","addAgentCoreGatewayCDKInfra","addAgentCoreGatewayTerraformInfra","gatewayNameClassName","gatewayNameKebabCase","projectDirectory","cedarPolicy","protocol","httpxVersion","httpx","mcpVersion","mcp","renderScript","exists","delete","addAgentCoreHarnessInfra","promptPath","projectRoot","templateContext","harnessNameClassName","harnessNameKebabCase","harnessNamePrefix","promptPathFromCdk","promptPathFromTerraform","addAgentCoreHarnessCDKInfra","addAgentCoreHarnessTerraformInfra"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../packages/nx-plugin/src/utils/agent-core-constructs/agent-core-constructs.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n type ProjectConfiguration,\n type Tree,\n updateJson,\n} from '@nx/devkit';\nimport { addStarExport } from '../ast.js';\nimport type { Containers } from '../containers.js';\nimport {\n type DeclaredPyDependency,\n type DeclaredTsDependency,\n type DependencyDeclaration,\n forDependencies,\n type MustDeclare,\n} from '../declared-dependencies.js';\nimport { addDependenciesToPackageJson } from '../dependencies.js';\nimport type { Iac } from '../iac.js';\nimport { esmVars } from '../module-format.js';\nimport { addDependencyToTargetIfNotPresent } from '../nx.js';\nimport {\n generatedCdk,\n generatedTerraform,\n type IacMetadata,\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n SHARED_TERRAFORM_DIR,\n} from '../shared-constructs-constants.js';\nimport {\n type IPyDepVersion,\n type ITsDepVersion,\n PY_VERSIONS,\n terraformProviderVersions,\n withVersions,\n} from '../versions.js';\n\ntype IACProvider = { iac: Iac };\n\n/**\n * Dependencies a caller must declare to add an AgentCore Gateway construct.\n *\n * Both providers render Cedar policies with `ejs`, each from a different\n * manifest: the CDK construct imports it from the shared constructs project,\n * while Terraform's `render-cedar.cjs` resolves it from the workspace root,\n * since the shared terraform project it runs in has no `package.json`.\n */\nexport const AGENT_CORE_CONSTRUCTS_DEPENDENCIES = [\n { name: 'ejs', when: generatedCdk },\n { name: '@aws-sdk/client-bedrock-agentcore', when: generatedCdk },\n { name: '@types/ejs', when: generatedCdk },\n { name: 'ejs', when: generatedTerraform, dev: true, root: true },\n] as const satisfies readonly DeclaredTsDependency<\n ITsDepVersion,\n IacMetadata\n>[];\n\n/**\n * Python versions the generated Terraform pins in an inline `uv run --with`\n * script, rather than in any `pyproject.toml`.\n *\n * Spread through `ownedElsewhere` because nothing installs them into the\n * workspace — the pin is owned so the version sync keeps it current, and gated on\n * Terraform since the CDK branch writes no such script.\n */\nexport const AGENT_CORE_CONSTRUCTS_PY_DEPENDENCIES = [\n { name: 'boto3', when: generatedTerraform },\n { name: 'httpx', when: generatedTerraform },\n { name: 'mcp', when: generatedTerraform },\n] as const satisfies readonly DeclaredPyDependency<\n IPyDepVersion,\n IacMetadata\n>[];\n\nexport type AgentCoreAuth = 'iam' | 'cognito';\n\nexport type AgentCoreSession = 's3' | 'dynamodb-s3' | 'in-memory';\n\nexport interface AddAgentCoreInfraProps {\n nameClassName: string;\n nameKebabCase: string;\n projectName: string;\n dockerImageTag: string;\n dockerOutputDir: string;\n appDirectory: string;\n serverProtocol: 'mcp' | 'http' | 'a2a';\n auth: AgentCoreAuth;\n /** How this runtime's session should be persisted. MCP servers have no session, so pass 'in-memory'. */\n session: AgentCoreSession;\n containers: Containers;\n}\n\nconst addAgentCoreInfra = async (\n tree: Tree,\n options: AddAgentCoreInfraProps & { iac: Iac },\n) => {\n switch (options.iac) {\n case 'cdk':\n await addAgentCoreCDKInfra(tree, options);\n break;\n case 'terraform':\n addAgentCoreTerraformInfra(tree, options);\n break;\n }\n\n // Update shared constructs/terraform project configuration to depend on this project\n updateJson(\n tree,\n joinPathFragments(\n PACKAGES_DIR,\n options.iac === 'cdk' ? SHARED_CONSTRUCTS_DIR : SHARED_TERRAFORM_DIR,\n 'project.json',\n ),\n (config: ProjectConfiguration) => {\n addDependencyToTargetIfNotPresent(\n config,\n 'build',\n `${options.projectName}:build`,\n );\n return config;\n },\n );\n};\n\nconst addAgentCoreCDKInfra = async (\n tree: Tree,\n options: AddAgentCoreInfraProps,\n) => {\n // Generate app specific CDK construct\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files', 'cdk', 'app', 'agent-core'),\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'app',\n options.appDirectory,\n ),\n { ...options, ...esmVars(tree) },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n\n // Export app specific CDK construct\n await addStarExport(\n tree,\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'app',\n options.appDirectory,\n 'index.ts',\n ),\n `./${options.nameKebabCase}/${options.nameKebabCase}.js`,\n );\n await addStarExport(\n tree,\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'app',\n 'index.ts',\n ),\n `./${options.appDirectory}/index.js`,\n );\n};\n\nconst addAgentCoreTerraformInfra = (\n tree: Tree,\n options: AddAgentCoreInfraProps,\n) => {\n // Add the AgentCore shared module\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'terraform',\n 'core',\n 'agent-core',\n ),\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n 'src',\n 'core',\n 'agent-core',\n ),\n {\n containers: options.containers,\n boto3Version: PY_VERSIONS.boto3,\n ...terraformProviderVersions(),\n },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n\n // Generate app specific agent core configuration\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'terraform',\n 'app',\n 'agent-core',\n ),\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n 'src',\n 'app',\n options.appDirectory,\n ),\n { ...options, ...terraformProviderVersions() },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n};\n\nexport interface AddMcpServerInfraProps {\n mcpServerNameClassName: string;\n mcpServerNameKebabCase: string;\n projectName: string;\n dockerImageTag: string;\n dockerOutputDir: string;\n auth: AgentCoreAuth;\n containers: Containers;\n}\n\n/**\n * Add an MCP server CDK construct\n */\nexport const addMcpServerInfra = async (\n tree: Tree,\n options: AddMcpServerInfraProps & IACProvider,\n) => {\n await addAgentCoreInfra(tree, {\n nameClassName: options.mcpServerNameClassName,\n nameKebabCase: options.mcpServerNameKebabCase,\n dockerImageTag: options.dockerImageTag,\n dockerOutputDir: options.dockerOutputDir,\n projectName: options.projectName,\n appDirectory: 'mcp-servers',\n serverProtocol: 'mcp',\n iac: options.iac,\n auth: options.auth,\n // MCP servers are stateless (no conversation session to persist).\n session: 'in-memory',\n containers: options.containers,\n });\n};\n\nexport interface AddAgentInfraProps {\n agentNameClassName: string;\n agentNameKebabCase: string;\n projectName: string;\n dockerImageTag: string;\n dockerOutputDir: string;\n auth: AgentCoreAuth;\n session: AgentCoreSession;\n serverProtocol?: 'http' | 'a2a';\n containers: Containers;\n}\n\n/**\n * Add an agent CDK construct\n */\nexport const addAgentInfra = async (\n tree: Tree,\n options: AddAgentInfraProps & IACProvider,\n) => {\n await addAgentCoreInfra(tree, {\n nameClassName: options.agentNameClassName,\n nameKebabCase: options.agentNameKebabCase,\n projectName: options.projectName,\n dockerImageTag: options.dockerImageTag,\n dockerOutputDir: options.dockerOutputDir,\n appDirectory: 'agents',\n session: options.session,\n serverProtocol: options.serverProtocol ?? 'http',\n iac: options.iac,\n auth: options.auth,\n containers: options.containers,\n });\n};\n\nexport interface AddAgentCoreGatewayInfraProps {\n gatewayNameClassName: string;\n gatewayNameKebabCase: string;\n projectName: string;\n projectDirectory: string;\n cedarPolicy: boolean;\n auth: AgentCoreAuth;\n /**\n * The gateway's protocol: mcp aggregates MCP server targets, http proxies\n * agent runtime targets via path-based routing.\n */\n protocol: 'mcp' | 'http';\n}\n\nexport const addAgentCoreGatewayInfra = async <\n const D extends DependencyDeclaration,\n>(\n tree: Tree,\n options: AddAgentCoreGatewayInfraProps & IACProvider,\n declaration: D & MustDeclare<typeof AGENT_CORE_CONSTRUCTS_DEPENDENCIES, D>,\n) => {\n switch (options.iac) {\n case 'cdk':\n await addAgentCoreGatewayCDKInfra(tree, options, declaration);\n break;\n case 'terraform':\n addAgentCoreGatewayTerraformInfra(tree, options, declaration);\n break;\n }\n\n updateJson(\n tree,\n joinPathFragments(\n PACKAGES_DIR,\n options.iac === 'cdk' ? SHARED_CONSTRUCTS_DIR : SHARED_TERRAFORM_DIR,\n 'project.json',\n ),\n (config: ProjectConfiguration) => {\n addDependencyToTargetIfNotPresent(\n config,\n 'build',\n `${options.projectName}:build`,\n );\n return config;\n },\n );\n};\n\nconst addAgentCoreGatewayCDKInfra = async (\n tree: Tree,\n options: AddAgentCoreGatewayInfraProps,\n declaration: DependencyDeclaration,\n) => {\n // Generic gateway construct (readiness probe, policy engine, Cedar policy\n // loading) shared by all gateways\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'cdk',\n 'core',\n 'agentcore-gateway',\n ),\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'core',\n 'agentcore-gateway',\n ),\n { ...esmVars(tree) },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'cdk',\n 'app',\n 'agentcore-gateway',\n ),\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'app',\n 'gateways',\n ),\n {\n nameClassName: options.gatewayNameClassName,\n nameKebabCase: options.gatewayNameKebabCase,\n projectDirectory: options.projectDirectory,\n cedarPolicy: options.cedarPolicy,\n auth: options.auth,\n protocol: options.protocol,\n ...esmVars(tree),\n },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n\n await addStarExport(\n tree,\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'core',\n 'index.ts',\n ),\n './agentcore-gateway/agentcore-gateway.js',\n );\n await addStarExport(\n tree,\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'app',\n 'gateways',\n 'index.ts',\n ),\n `./${options.gatewayNameKebabCase}/${options.gatewayNameKebabCase}.js`,\n );\n await addStarExport(\n tree,\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'app',\n 'index.ts',\n ),\n './gateways/index.js',\n );\n\n // The gateway construct renders Cedar policies with ejs and its readiness\n // probe uses the AgentCore SDK client; declare both so the lint passes.\n addDependenciesToPackageJson(\n tree,\n withVersions(\n forDependencies<typeof AGENT_CORE_CONSTRUCTS_DEPENDENCIES>(declaration),\n ['ejs', '@aws-sdk/client-bedrock-agentcore'],\n ),\n withVersions(\n forDependencies<typeof AGENT_CORE_CONSTRUCTS_DEPENDENCIES>(declaration),\n ['@types/ejs'],\n ),\n joinPathFragments(PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, 'package.json'),\n );\n};\n\nconst addAgentCoreGatewayTerraformInfra = (\n tree: Tree,\n options: AddAgentCoreGatewayInfraProps,\n declaration: DependencyDeclaration,\n) => {\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'terraform',\n 'core',\n 'agentcore-gateway',\n ),\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n 'src',\n 'core',\n 'agentcore-gateway',\n ),\n { ...terraformProviderVersions() },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'terraform',\n 'app',\n 'agentcore-gateway',\n ),\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n 'src',\n 'app',\n 'gateways',\n ),\n {\n nameClassName: options.gatewayNameClassName,\n nameKebabCase: options.gatewayNameKebabCase,\n projectDirectory: options.projectDirectory,\n cedarPolicy: options.cedarPolicy,\n auth: options.auth,\n protocol: options.protocol,\n boto3Version: PY_VERSIONS.boto3,\n httpxVersion: PY_VERSIONS.httpx,\n mcpVersion: PY_VERSIONS.mcp,\n ...terraformProviderVersions(),\n },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n\n // The Cedar render script is only needed when policies are enabled\n if (!options.cedarPolicy) {\n const renderScript = joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n 'src',\n 'app',\n 'gateways',\n options.gatewayNameKebabCase,\n 'render-cedar.cjs',\n );\n if (tree.exists(renderScript)) {\n tree.delete(renderScript);\n }\n return;\n }\n\n // render-cedar.cjs resolves ejs from the workspace root, since the shared\n // terraform project it runs in has no package.json.\n addDependenciesToPackageJson(\n tree,\n {},\n withVersions(\n forDependencies<typeof AGENT_CORE_CONSTRUCTS_DEPENDENCIES>(declaration),\n ['ejs'],\n ),\n );\n};\n\nexport interface AddAgentCoreHarnessInfraProps {\n harnessNameClassName: string;\n harnessNameKebabCase: string;\n /**\n * Workspace-root-relative harness project root, eg `packages/my-harness`.\n * The `src/PROMPT.md` path both templates read is derived from it.\n */\n projectRoot: string;\n /** Leading-letter-guaranteed, 31-char-truncated resource name prefix. */\n harnessNamePrefix: string;\n}\n\n/**\n * Template substitution context shared by the CDK and Terraform harness\n * branches. Both prompt path fields carry the same workspace-root-relative\n * path, named per provider so each template's usage reads on its own.\n */\ninterface HarnessTemplateContext {\n nameClassName: string;\n nameKebabCase: string;\n harnessNamePrefix: string;\n /** Joined onto `findWorkspaceRoot()` in the CDK construct. */\n promptPathFromCdk: string;\n /** Appended to the `path.module` walk to the workspace root in Terraform. */\n promptPathFromTerraform: string;\n}\n\n/**\n * Add AgentCore Harness infrastructure for the selected IaC provider.\n *\n * Renders the provider-specific Harness infrastructure (a CDK construct or\n * a Terraform module) into the Shared Infrastructure Project with\n * `KeepExisting`, so existing files become user-owned and are never\n * rewritten by reruns.\n *\n * Unlike agents, MCP servers and gateways, no build dependency is added\n * from the shared infrastructure project to the Harness Project: generated\n * Harness infrastructure does not import Harness Project source, so a\n * dependency would only create false rebuild coupling.\n */\nexport const addAgentCoreHarnessInfra = async (\n tree: Tree,\n options: AddAgentCoreHarnessInfraProps & IACProvider,\n): Promise<void> => {\n // One resolved template context, built once and passed to both provider\n // branches. The prompt path is derived from the same projectRoot the\n // Harness Project is written to, so explicit placement needs no extra logic.\n const promptPath = joinPathFragments(options.projectRoot, 'src', 'PROMPT.md');\n const templateContext: HarnessTemplateContext = {\n nameClassName: options.harnessNameClassName,\n nameKebabCase: options.harnessNameKebabCase,\n harnessNamePrefix: options.harnessNamePrefix,\n promptPathFromCdk: promptPath,\n promptPathFromTerraform: promptPath,\n };\n\n switch (options.iac) {\n case 'cdk':\n await addAgentCoreHarnessCDKInfra(tree, templateContext);\n break;\n case 'terraform':\n addAgentCoreHarnessTerraformInfra(tree, templateContext);\n break;\n }\n};\n\nconst addAgentCoreHarnessCDKInfra = async (\n tree: Tree,\n templateContext: HarnessTemplateContext,\n) => {\n // Generate the app specific CDK construct under\n // src/app/harnesses/<kebab-case-name>/\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'cdk',\n 'app',\n 'agentcore-harness',\n ),\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'app',\n 'harnesses',\n ),\n { ...templateContext, ...esmVars(tree) },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n\n // Export the construct through the harnesses app index and the shared\n // app index. addStarExport creates a missing index file and semantically\n // deduplicates equivalent exports on reruns.\n await addStarExport(\n tree,\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'app',\n 'harnesses',\n 'index.ts',\n ),\n `./${templateContext.nameKebabCase}/${templateContext.nameKebabCase}.js`,\n );\n await addStarExport(\n tree,\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_CONSTRUCTS_DIR,\n 'src',\n 'app',\n 'index.ts',\n ),\n './harnesses/index.js',\n );\n};\n\nconst addAgentCoreHarnessTerraformInfra = (\n tree: Tree,\n templateContext: HarnessTemplateContext,\n) => {\n // Generate the app specific Terraform module under\n // src/app/harnesses/<kebab-case-name>/. No CDK files or exports are\n // created on this path.\n generateFiles(\n tree,\n joinPathFragments(\n import.meta.dirname,\n 'files',\n 'terraform',\n 'app',\n 'agentcore-harness',\n ),\n joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n 'src',\n 'app',\n 'harnesses',\n ),\n { ...templateContext, ...terraformProviderVersions() },\n {\n overwriteStrategy: OverwriteStrategy.KeepExisting,\n },\n );\n};\n"],"names":["generateFiles","joinPathFragments","OverwriteStrategy","updateJson","addStarExport","forDependencies","addDependenciesToPackageJson","esmVars","addDependencyToTargetIfNotPresent","generatedCdk","generatedTerraform","PACKAGES_DIR","SHARED_CONSTRUCTS_DIR","SHARED_TERRAFORM_DIR","PY_VERSIONS","terraformProviderVersions","withVersions","AGENT_CORE_CONSTRUCTS_DEPENDENCIES","name","when","dev","root","AGENT_CORE_CONSTRUCTS_PY_DEPENDENCIES","addAgentCoreInfra","tree","options","iac","addAgentCoreCDKInfra","addAgentCoreTerraformInfra","config","projectName","dirname","appDirectory","overwriteStrategy","KeepExisting","nameKebabCase","containers","boto3Version","boto3","addMcpServerInfra","nameClassName","mcpServerNameClassName","mcpServerNameKebabCase","dockerImageTag","dockerOutputDir","serverProtocol","auth","session","addAgentInfra","agentNameClassName","agentNameKebabCase","addAgentCoreGatewayInfra","declaration","addAgentCoreGatewayCDKInfra","addAgentCoreGatewayTerraformInfra","gatewayNameClassName","gatewayNameKebabCase","projectDirectory","cedarPolicy","protocol","httpxVersion","httpx","mcpVersion","mcp","renderScript","exists","delete","addAgentCoreHarnessInfra","promptPath","projectRoot","templateContext","harnessNameClassName","harnessNameKebabCase","harnessNamePrefix","promptPathFromCdk","promptPathFromTerraform","addAgentCoreHarnessCDKInfra","addAgentCoreHarnessTerraformInfra"],"mappings":"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"}
|
|
@@ -96,3 +96,18 @@ module "add_to_runtime_config" {
|
|
|
96
96
|
tableName = module.dynamodb_table.table_name
|
|
97
97
|
}
|
|
98
98
|
}
|
|
99
|
+
|
|
100
|
+
output "table_name" {
|
|
101
|
+
description = "Name of the DynamoDB table"
|
|
102
|
+
value = module.dynamodb_table.table_name
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
output "table_arn" {
|
|
106
|
+
description = "ARN of the DynamoDB table, for use in IAM policies granting access to the table. Suffix with /index/* to cover its global secondary indexes."
|
|
107
|
+
value = module.dynamodb_table.table_arn
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
output "kms_key_arn" {
|
|
111
|
+
description = "ARN of the KMS key used to encrypt the DynamoDB table, for use in IAM policies granting access to the table. Null when using the AWS owned key (encryption = DEFAULT)."
|
|
112
|
+
value = module.dynamodb_table.kms_key_arn
|
|
113
|
+
}
|
|
@@ -95,6 +95,8 @@ resource "aws_kms_key" "table" {
|
|
|
95
95
|
description = "KMS key for DynamoDB table ${var.name}"
|
|
96
96
|
enable_key_rotation = var.enable_key_rotation
|
|
97
97
|
|
|
98
|
+
deletion_window_in_days = 30
|
|
99
|
+
|
|
98
100
|
policy = jsonencode({
|
|
99
101
|
Version = "2012-10-17"
|
|
100
102
|
Statement = [
|
|
@@ -171,6 +173,10 @@ resource "aws_dynamodb_table" "table" {
|
|
|
171
173
|
enabled = var.encryption != "DEFAULT"
|
|
172
174
|
kms_key_arn = local.table_kms_key_arn
|
|
173
175
|
}
|
|
176
|
+
|
|
177
|
+
lifecycle {
|
|
178
|
+
prevent_destroy = true
|
|
179
|
+
}
|
|
174
180
|
}
|
|
175
181
|
|
|
176
182
|
output "table_name" {
|
|
@@ -215,6 +215,8 @@ resource "aws_kms_key" "database" {
|
|
|
215
215
|
description = "KMS key for Aurora cluster ${var.name}"
|
|
216
216
|
enable_key_rotation = var.enable_key_rotation
|
|
217
217
|
|
|
218
|
+
deletion_window_in_days = 30
|
|
219
|
+
|
|
218
220
|
policy = jsonencode({
|
|
219
221
|
Version = "2012-10-17"
|
|
220
222
|
Statement = [
|
|
@@ -357,6 +359,10 @@ resource "aws_rds_cluster" "database" {
|
|
|
357
359
|
tags = merge(var.tags, {
|
|
358
360
|
Name = "${var.name}-aurora"
|
|
359
361
|
})
|
|
362
|
+
|
|
363
|
+
lifecycle {
|
|
364
|
+
prevent_destroy = true
|
|
365
|
+
}
|
|
360
366
|
}
|
|
361
367
|
|
|
362
368
|
resource "aws_rds_cluster_instance" "database" {
|
|
@@ -54,6 +54,11 @@ export declare const generatedInfrastructure: (m: IacMetadata) => boolean;
|
|
|
54
54
|
* branch never writes.
|
|
55
55
|
*/
|
|
56
56
|
export declare const generatedTerraform: (m: IacMetadata) => boolean;
|
|
57
|
+
/**
|
|
58
|
+
* Whether CDK infrastructure was generated, for the packages only a construct
|
|
59
|
+
* imports.
|
|
60
|
+
*/
|
|
61
|
+
export declare const generatedCdk: (m: IacMetadata) => boolean;
|
|
57
62
|
/**
|
|
58
63
|
* Dependencies a caller must declare to use the shared constructs project.
|
|
59
64
|
* Lives here so generators can spread it without importing the generator.
|
|
@@ -43,6 +43,10 @@ export const DYNAMODB_GENERATOR_IDS = [
|
|
|
43
43
|
* module pins — a Terraform inline script's `uv run --with` pins, which the CDK
|
|
44
44
|
* branch never writes.
|
|
45
45
|
*/ export const generatedTerraform = (m)=>m.iac === 'terraform';
|
|
46
|
+
/**
|
|
47
|
+
* Whether CDK infrastructure was generated, for the packages only a construct
|
|
48
|
+
* imports.
|
|
49
|
+
*/ export const generatedCdk = (m)=>m.iac === 'cdk';
|
|
46
50
|
/**
|
|
47
51
|
* Dependencies a caller must declare to use the shared constructs project.
|
|
48
52
|
* Lives here so generators can spread it without importing the generator.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/shared-constructs-constants.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport type { DeclaredTsDependency } from './declared-dependencies.js';\nimport type { ITsDepVersion } from './versions.js';\n\nexport const PACKAGES_DIR = 'packages';\nexport const SHARED_CONSTRUCTS_NAME = 'common-constructs';\nexport const SHARED_CONSTRUCTS_DIR = 'common/constructs';\nexport const SHARED_TERRAFORM_NAME = 'terraform';\nexport const SHARED_TERRAFORM_DIR = 'common/terraform';\nexport const SHARED_SHADCN_NAME = 'common-shadcn';\nexport const SHARED_SHADCN_DIR = 'common/shadcn';\nexport const SHARED_INFRA_CONFIG_NAME = 'common-infra-config';\nexport const SHARED_INFRA_CONFIG_DIR = 'common/infra-config';\nexport const SHARED_SCRIPTS_NAME = 'common-scripts';\nexport const SHARED_SCRIPTS_DIR = 'common/scripts';\n\nexport const DYNAMODB_GENERATOR_IDS = ['ts#dynamodb', 'py#dynamodb'];\n\n/**\n * Directory the vended Terraform runtime-config modules aggregate into at apply\n * time, relative to the workspace root. The `entry` module writes leaf files\n * under `entries/<namespace>/`, and the `read` / `appconfig-deployment` modules\n * merge those into one `<namespace>.json` here.\n */\nexport const TERRAFORM_RUNTIME_CONFIG_DIR = `dist/${PACKAGES_DIR}/${SHARED_TERRAFORM_DIR}/runtime-config`;\n\n/**\n * Runtime-config namespace the static website publishes to and reads back, as\n * passed to the `read` module by the vended static-website Terraform module.\n */\nexport const WEBSITE_RUNTIME_CONFIG_NAMESPACE = 'connection';\n\n/**\n * File the Terraform aggregation writes the website's runtime config to,\n * relative to the workspace root.\n */\nexport const TERRAFORM_WEBSITE_RUNTIME_CONFIG_FILE = `${TERRAFORM_RUNTIME_CONFIG_DIR}/${WEBSITE_RUNTIME_CONFIG_NAMESPACE}.json`;\n\n/**\n * What a generator records about the infrastructure it generated.\n *\n * Every generator that creates infrastructure records the `iac` it used, so a\n * predicate can tell a CDK project from a Terraform one at upgrade time. Absent\n * when the generator was run with no infrastructure, so its presence doubles as\n * \"infrastructure was generated\" — which is what gates the packages an infra\n * helper adds.\n */\nexport interface IacMetadata {\n readonly iac?: string;\n}\n\n/**\n * Whether infrastructure was generated at all, so the packages an infra helper\n * adds are only claimed where that helper ran.\n *\n * Reads `iac` rather than the generator's own `infra` option: every generator\n * resolves `iac` only on the infra branch, so one recorded field answers both\n * questions and no generator needs a second one.\n */\nexport const generatedInfrastructure = (m: IacMetadata): boolean =>\n m.iac !== undefined;\n\n/**\n * Whether Terraform infrastructure was generated, for the versions only a `.tf`\n * module pins — a Terraform inline script's `uv run --with` pins, which the CDK\n * branch never writes.\n */\nexport const generatedTerraform = (m: IacMetadata): boolean =>\n m.iac === 'terraform';\n\n/**\n * Dependencies a caller must declare to use the shared constructs project.\n * Lives here so generators can spread it without importing the generator.\n *\n * `constructs` and `aws-cdk-lib` are gated on CDK because\n * `sharedConstructsGenerator` creates the TypeScript constructs project on that\n * branch alone — a Terraform workspace gets the shared Terraform project and\n * never receives them.\n */\nexport const SHARED_CONSTRUCTS_DEPENDENCIES = [\n { name: 'constructs', when: (m: IacMetadata) => m.iac === 'cdk' },\n { name: 'aws-cdk-lib', when: (m: IacMetadata) => m.iac === 'cdk' },\n { name: '@types/node' },\n] as const satisfies readonly DeclaredTsDependency<\n ITsDepVersion,\n IacMetadata\n>[];\n"],"names":["PACKAGES_DIR","SHARED_CONSTRUCTS_NAME","SHARED_CONSTRUCTS_DIR","SHARED_TERRAFORM_NAME","SHARED_TERRAFORM_DIR","SHARED_SHADCN_NAME","SHARED_SHADCN_DIR","SHARED_INFRA_CONFIG_NAME","SHARED_INFRA_CONFIG_DIR","SHARED_SCRIPTS_NAME","SHARED_SCRIPTS_DIR","DYNAMODB_GENERATOR_IDS","TERRAFORM_RUNTIME_CONFIG_DIR","WEBSITE_RUNTIME_CONFIG_NAMESPACE","TERRAFORM_WEBSITE_RUNTIME_CONFIG_FILE","generatedInfrastructure","m","iac","undefined","generatedTerraform","SHARED_CONSTRUCTS_DEPENDENCIES","name","when"],"mappings":"AAAA;;;CAGC,GAID,OAAO,MAAMA,eAAe,WAAW;AACvC,OAAO,MAAMC,yBAAyB,oBAAoB;AAC1D,OAAO,MAAMC,wBAAwB,oBAAoB;AACzD,OAAO,MAAMC,wBAAwB,YAAY;AACjD,OAAO,MAAMC,uBAAuB,mBAAmB;AACvD,OAAO,MAAMC,qBAAqB,gBAAgB;AAClD,OAAO,MAAMC,oBAAoB,gBAAgB;AACjD,OAAO,MAAMC,2BAA2B,sBAAsB;AAC9D,OAAO,MAAMC,0BAA0B,sBAAsB;AAC7D,OAAO,MAAMC,sBAAsB,iBAAiB;AACpD,OAAO,MAAMC,qBAAqB,iBAAiB;AAEnD,OAAO,MAAMC,yBAAyB;IAAC;IAAe;CAAc,CAAC;AAErE;;;;;CAKC,GACD,OAAO,MAAMC,+BAA+B,CAAC,KAAK,EAAEZ,aAAa,CAAC,EAAEI,qBAAqB,eAAe,CAAC,CAAC;AAE1G;;;CAGC,GACD,OAAO,MAAMS,mCAAmC,aAAa;AAE7D;;;CAGC,GACD,OAAO,MAAMC,wCAAwC,GAAGF,6BAA6B,CAAC,EAAEC,iCAAiC,KAAK,CAAC,CAAC;AAehI;;;;;;;CAOC,GACD,OAAO,MAAME,0BAA0B,CAACC,IACtCA,EAAEC,GAAG,KAAKC,UAAU;AAEtB;;;;CAIC,GACD,OAAO,MAAMC,qBAAqB,CAACH,IACjCA,EAAEC,GAAG,KAAK,YAAY;AAExB;;;;;;;;CAQC,GACD,OAAO,
|
|
1
|
+
{"version":3,"sources":["../../../../../packages/nx-plugin/src/utils/shared-constructs-constants.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport type { DeclaredTsDependency } from './declared-dependencies.js';\nimport type { ITsDepVersion } from './versions.js';\n\nexport const PACKAGES_DIR = 'packages';\nexport const SHARED_CONSTRUCTS_NAME = 'common-constructs';\nexport const SHARED_CONSTRUCTS_DIR = 'common/constructs';\nexport const SHARED_TERRAFORM_NAME = 'terraform';\nexport const SHARED_TERRAFORM_DIR = 'common/terraform';\nexport const SHARED_SHADCN_NAME = 'common-shadcn';\nexport const SHARED_SHADCN_DIR = 'common/shadcn';\nexport const SHARED_INFRA_CONFIG_NAME = 'common-infra-config';\nexport const SHARED_INFRA_CONFIG_DIR = 'common/infra-config';\nexport const SHARED_SCRIPTS_NAME = 'common-scripts';\nexport const SHARED_SCRIPTS_DIR = 'common/scripts';\n\nexport const DYNAMODB_GENERATOR_IDS = ['ts#dynamodb', 'py#dynamodb'];\n\n/**\n * Directory the vended Terraform runtime-config modules aggregate into at apply\n * time, relative to the workspace root. The `entry` module writes leaf files\n * under `entries/<namespace>/`, and the `read` / `appconfig-deployment` modules\n * merge those into one `<namespace>.json` here.\n */\nexport const TERRAFORM_RUNTIME_CONFIG_DIR = `dist/${PACKAGES_DIR}/${SHARED_TERRAFORM_DIR}/runtime-config`;\n\n/**\n * Runtime-config namespace the static website publishes to and reads back, as\n * passed to the `read` module by the vended static-website Terraform module.\n */\nexport const WEBSITE_RUNTIME_CONFIG_NAMESPACE = 'connection';\n\n/**\n * File the Terraform aggregation writes the website's runtime config to,\n * relative to the workspace root.\n */\nexport const TERRAFORM_WEBSITE_RUNTIME_CONFIG_FILE = `${TERRAFORM_RUNTIME_CONFIG_DIR}/${WEBSITE_RUNTIME_CONFIG_NAMESPACE}.json`;\n\n/**\n * What a generator records about the infrastructure it generated.\n *\n * Every generator that creates infrastructure records the `iac` it used, so a\n * predicate can tell a CDK project from a Terraform one at upgrade time. Absent\n * when the generator was run with no infrastructure, so its presence doubles as\n * \"infrastructure was generated\" — which is what gates the packages an infra\n * helper adds.\n */\nexport interface IacMetadata {\n readonly iac?: string;\n}\n\n/**\n * Whether infrastructure was generated at all, so the packages an infra helper\n * adds are only claimed where that helper ran.\n *\n * Reads `iac` rather than the generator's own `infra` option: every generator\n * resolves `iac` only on the infra branch, so one recorded field answers both\n * questions and no generator needs a second one.\n */\nexport const generatedInfrastructure = (m: IacMetadata): boolean =>\n m.iac !== undefined;\n\n/**\n * Whether Terraform infrastructure was generated, for the versions only a `.tf`\n * module pins — a Terraform inline script's `uv run --with` pins, which the CDK\n * branch never writes.\n */\nexport const generatedTerraform = (m: IacMetadata): boolean =>\n m.iac === 'terraform';\n\n/**\n * Whether CDK infrastructure was generated, for the packages only a construct\n * imports.\n */\nexport const generatedCdk = (m: IacMetadata): boolean => m.iac === 'cdk';\n\n/**\n * Dependencies a caller must declare to use the shared constructs project.\n * Lives here so generators can spread it without importing the generator.\n *\n * `constructs` and `aws-cdk-lib` are gated on CDK because\n * `sharedConstructsGenerator` creates the TypeScript constructs project on that\n * branch alone — a Terraform workspace gets the shared Terraform project and\n * never receives them.\n */\nexport const SHARED_CONSTRUCTS_DEPENDENCIES = [\n { name: 'constructs', when: (m: IacMetadata) => m.iac === 'cdk' },\n { name: 'aws-cdk-lib', when: (m: IacMetadata) => m.iac === 'cdk' },\n { name: '@types/node' },\n] as const satisfies readonly DeclaredTsDependency<\n ITsDepVersion,\n IacMetadata\n>[];\n"],"names":["PACKAGES_DIR","SHARED_CONSTRUCTS_NAME","SHARED_CONSTRUCTS_DIR","SHARED_TERRAFORM_NAME","SHARED_TERRAFORM_DIR","SHARED_SHADCN_NAME","SHARED_SHADCN_DIR","SHARED_INFRA_CONFIG_NAME","SHARED_INFRA_CONFIG_DIR","SHARED_SCRIPTS_NAME","SHARED_SCRIPTS_DIR","DYNAMODB_GENERATOR_IDS","TERRAFORM_RUNTIME_CONFIG_DIR","WEBSITE_RUNTIME_CONFIG_NAMESPACE","TERRAFORM_WEBSITE_RUNTIME_CONFIG_FILE","generatedInfrastructure","m","iac","undefined","generatedTerraform","generatedCdk","SHARED_CONSTRUCTS_DEPENDENCIES","name","when"],"mappings":"AAAA;;;CAGC,GAID,OAAO,MAAMA,eAAe,WAAW;AACvC,OAAO,MAAMC,yBAAyB,oBAAoB;AAC1D,OAAO,MAAMC,wBAAwB,oBAAoB;AACzD,OAAO,MAAMC,wBAAwB,YAAY;AACjD,OAAO,MAAMC,uBAAuB,mBAAmB;AACvD,OAAO,MAAMC,qBAAqB,gBAAgB;AAClD,OAAO,MAAMC,oBAAoB,gBAAgB;AACjD,OAAO,MAAMC,2BAA2B,sBAAsB;AAC9D,OAAO,MAAMC,0BAA0B,sBAAsB;AAC7D,OAAO,MAAMC,sBAAsB,iBAAiB;AACpD,OAAO,MAAMC,qBAAqB,iBAAiB;AAEnD,OAAO,MAAMC,yBAAyB;IAAC;IAAe;CAAc,CAAC;AAErE;;;;;CAKC,GACD,OAAO,MAAMC,+BAA+B,CAAC,KAAK,EAAEZ,aAAa,CAAC,EAAEI,qBAAqB,eAAe,CAAC,CAAC;AAE1G;;;CAGC,GACD,OAAO,MAAMS,mCAAmC,aAAa;AAE7D;;;CAGC,GACD,OAAO,MAAMC,wCAAwC,GAAGF,6BAA6B,CAAC,EAAEC,iCAAiC,KAAK,CAAC,CAAC;AAehI;;;;;;;CAOC,GACD,OAAO,MAAME,0BAA0B,CAACC,IACtCA,EAAEC,GAAG,KAAKC,UAAU;AAEtB;;;;CAIC,GACD,OAAO,MAAMC,qBAAqB,CAACH,IACjCA,EAAEC,GAAG,KAAK,YAAY;AAExB;;;CAGC,GACD,OAAO,MAAMG,eAAe,CAACJ,IAA4BA,EAAEC,GAAG,KAAK,MAAM;AAEzE;;;;;;;;CAQC,GACD,OAAO,MAAMI,iCAAiC;IAC5C;QAAEC,MAAM;QAAcC,MAAM,CAACP,IAAmBA,EAAEC,GAAG,KAAK;IAAM;IAChE;QAAEK,MAAM;QAAeC,MAAM,CAACP,IAAmBA,EAAEC,GAAG,KAAK;IAAM;IACjE;QAAEK,MAAM;IAAc;CACvB,CAGG"}
|