@aws/nx-plugin 1.0.0-rc.83 → 1.0.0-rc.84
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 +26 -1
- package/package.json +1 -1
- package/src/agentcore-gateway/__snapshots__/generator.spec.ts.snap +51 -2
- package/src/agentcore-harness/__snapshots__/generator.spec.ts.snap +4 -5
- package/src/agentcore-harness/files/project/README.md.template +4 -5
- package/src/migrations/latest/agentcore-harness-no-tools-by-default/__snapshots__/migration.spec.ts.snap +79 -0
- package/src/migrations/latest/agentcore-harness-no-tools-by-default/metadata.json +3 -0
- package/src/migrations/latest/agentcore-harness-no-tools-by-default/migration.d.ts +6 -0
- package/src/migrations/latest/agentcore-harness-no-tools-by-default/migration.js +87 -0
- package/src/migrations/latest/agentcore-harness-no-tools-by-default/migration.js.map +1 -0
- package/src/migrations/latest/rdb-terraform-aurora-app-module-defaults/__snapshots__/migration.spec.ts.snap +54 -0
- package/src/migrations/latest/rdb-terraform-aurora-app-module-defaults/metadata.json +3 -0
- package/src/migrations/latest/rdb-terraform-aurora-app-module-defaults/migration.d.ts +6 -0
- package/src/migrations/latest/rdb-terraform-aurora-app-module-defaults/migration.js +86 -0
- package/src/migrations/latest/rdb-terraform-aurora-app-module-defaults/migration.js.map +1 -0
- package/src/migrations/latest/terraform-declare-used-providers/metadata.json +3 -0
- package/src/migrations/latest/terraform-declare-used-providers/migration.d.ts +6 -0
- package/src/migrations/latest/terraform-declare-used-providers/migration.js +147 -0
- package/src/migrations/latest/terraform-declare-used-providers/migration.js.map +1 -0
- package/src/migrations/latest/terraform-harness-vpc-role-and-memory-grant/__snapshots__/migration.spec.ts.snap +521 -0
- package/src/migrations/latest/terraform-harness-vpc-role-and-memory-grant/metadata.json +3 -0
- package/src/migrations/latest/terraform-harness-vpc-role-and-memory-grant/migration.d.ts +6 -0
- package/src/migrations/latest/terraform-harness-vpc-role-and-memory-grant/migration.js +504 -0
- package/src/migrations/latest/terraform-harness-vpc-role-and-memory-grant/migration.js.map +1 -0
- package/src/migrations/latest/waf-log-group-cmk-encryption/__snapshots__/migration.spec.ts.snap +286 -0
- package/src/migrations/latest/waf-log-group-cmk-encryption/metadata.json +3 -0
- package/src/migrations/latest/waf-log-group-cmk-encryption/migration.d.ts +6 -0
- package/src/migrations/latest/waf-log-group-cmk-encryption/migration.js +238 -0
- package/src/migrations/latest/waf-log-group-cmk-encryption/migration.js.map +1 -0
- package/src/py/agent/__snapshots__/generator.protocols.spec.ts.snap +12 -0
- package/src/py/fast-api/__snapshots__/generator.terraform.spec.ts.snap +231 -24
- package/src/py/lambda-function/__snapshots__/generator.spec.ts.snap +8 -0
- package/src/py/mcp-server/__snapshots__/generator.spec.ts.snap +4 -0
- package/src/py/rdb/__snapshots__/generator.spec.ts.snap +31 -2
- package/src/smithy/ts/api/__snapshots__/generator.spec.ts.snap +216 -25
- package/src/terraform/project/files/application/bootstrap/providers.tf.template +9 -0
- package/src/terraform/project/files/application/src/providers.tf.template +4 -0
- package/src/terraform/project/files/library/src/main.tf.template +9 -0
- package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +231 -24
- package/src/ts/agent/__snapshots__/generator.spec.ts.snap +8 -0
- package/src/ts/dcr-proxy/__snapshots__/generator.spec.ts.snap +4 -0
- package/src/ts/lambda-function/__snapshots__/generator.spec.ts.snap +8 -0
- package/src/ts/mcp-server/__snapshots__/generator.spec.ts.snap +4 -0
- package/src/ts/rdb/__snapshots__/generator.spec.ts.snap +62 -4
- package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +4 -0
- package/src/ts/react-website/cognito-auth/__snapshots__/generator.spec.ts.snap +35 -8
- package/src/ts/react-website/cognito-auth/__snapshots__/generator.terraform.spec.ts.snap +4 -0
- package/src/utils/agent-core-constructs/files/cdk/app/agentcore-harness/__nameKebabCase__/__nameKebabCase__.ts.template +39 -1
- package/src/utils/agent-core-constructs/files/terraform/app/agent-core/__nameKebabCase__/__nameKebabCase__.tf.template +8 -1
- package/src/utils/agent-core-constructs/files/terraform/app/agentcore-gateway/__nameKebabCase__/__nameKebabCase__.tf.template +57 -2
- package/src/utils/agent-core-constructs/files/terraform/app/agentcore-harness/__nameKebabCase__/__nameKebabCase__.tf.template +258 -24
- package/src/utils/agent-core-constructs/files/terraform/core/agent-core/runtime.tf.template +4 -0
- package/src/utils/api-constructs/files/terraform/app/apis/http/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +8 -0
- package/src/utils/api-constructs/files/terraform/app/apis/rest/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +9 -1
- package/src/utils/api-constructs/files/terraform/core/api/rest/rest-api/rest-api.tf.template +60 -7
- package/src/utils/dcr-proxy-constructs/files/terraform/app/dcr-proxies/__nameKebabCase__/__nameKebabCase__.tf.template +4 -0
- package/src/utils/files/terraform/src/metrics/providers.tf.template +12 -0
- package/src/utils/function-constructs/files/terraform/app/lambda-functions/__nameKebabCase__/__nameKebabCase__.tf.template +4 -0
- package/src/utils/identity-constructs/files/cdk/core/user-identity.ts.template +33 -8
- package/src/utils/identity-constructs/files/terraform/core/user-identity/add-callback-url/add-callback-url.tf.template +4 -0
- package/src/utils/identity-constructs/files/terraform/core/user-identity/identity/identity.tf.template +51 -2
- package/src/utils/rdb-constructs/files/cdk/core/rdb/aurora.ts.template +18 -0
- package/src/utils/rdb-constructs/files/terraform/app/dbs/__nameKebabCase__/__nameKebabCase__.tf.template +15 -4
- package/src/utils/rdb-constructs/files/terraform/core/rdb/aurora/aurora.tf.template +2 -2
- package/src/utils/rdb-constructs/rdb-constructs.d.ts +12 -0
- package/src/utils/rdb-constructs/rdb-constructs.js +24 -3
- package/src/utils/rdb-constructs/rdb-constructs.js.map +1 -1
- package/src/utils/website-constructs/files/terraform/core/static-website/static-website.tf.template +4 -0
package/migrations.json
CHANGED
|
@@ -47,6 +47,31 @@
|
|
|
47
47
|
"description": "Declare ejs at the workspace root so the Terraform gateway's Cedar render script resolves it",
|
|
48
48
|
"implementation": "./src/migrations/latest/terraform-gateway-cedar-render-root-ejs/migration"
|
|
49
49
|
},
|
|
50
|
+
"latest-rdb-terraform-aurora-app-module-defaults": {
|
|
51
|
+
"version": "1.0.0-rc.84",
|
|
52
|
+
"description": "Align the vended Terraform Aurora app module variable defaults with the core module, enabling CloudWatch engine log export and exposing enable_key_rotation",
|
|
53
|
+
"implementation": "./src/migrations/latest/rdb-terraform-aurora-app-module-defaults/migration"
|
|
54
|
+
},
|
|
55
|
+
"latest-agentcore-harness-no-tools-by-default": {
|
|
56
|
+
"version": "1.0.0-rc.84",
|
|
57
|
+
"description": "Pin the vended AgentCore Harness construct/module to no tools by default, since AgentCore treats an absent allowedTools as every tool",
|
|
58
|
+
"implementation": "./src/migrations/latest/agentcore-harness-no-tools-by-default/migration"
|
|
59
|
+
},
|
|
60
|
+
"latest-terraform-declare-used-providers": {
|
|
61
|
+
"version": "1.0.0-rc.84",
|
|
62
|
+
"description": "Declare every provider each vended Terraform module uses in its own required_providers",
|
|
63
|
+
"implementation": "./src/migrations/latest/terraform-declare-used-providers/migration"
|
|
64
|
+
},
|
|
65
|
+
"latest-waf-log-group-cmk-encryption": {
|
|
66
|
+
"version": "1.0.0-rc.84",
|
|
67
|
+
"description": "Encrypt vended WAF log groups with a customer-managed KMS key",
|
|
68
|
+
"implementation": "./src/migrations/latest/waf-log-group-cmk-encryption/migration"
|
|
69
|
+
},
|
|
70
|
+
"latest-terraform-harness-vpc-role-and-memory-grant": {
|
|
71
|
+
"version": "1.0.0-rc.84",
|
|
72
|
+
"description": "Add VPC, execution role and native field support to the vended Terraform AgentCore Harness module, and scope its managed-memory grant to the service-assigned ARN",
|
|
73
|
+
"implementation": "./src/migrations/latest/terraform-harness-vpc-role-and-memory-grant/migration"
|
|
74
|
+
},
|
|
50
75
|
"v1.0.0-rc.50-0001-modernize-function-props-cast": {
|
|
51
76
|
"version": "1.0.0-rc.50",
|
|
52
77
|
"description": "Replace the legacy angle-bracket FunctionProps type assertion with the modern as syntax in generated API constructs",
|
|
@@ -188,7 +213,7 @@
|
|
|
188
213
|
"implementation": "./src/migrations/v1.0.0-rc.75/0001-ts-agent-session-id-middleware-extraction/migration"
|
|
189
214
|
},
|
|
190
215
|
"sync-vended-versions": {
|
|
191
|
-
"version": "1.0.0-rc.
|
|
216
|
+
"version": "1.0.0-rc.84",
|
|
192
217
|
"description": "Sync vended dependency versions and the tracked plugin version to those vended by this release",
|
|
193
218
|
"implementation": "./src/utils/version-upgrade-migration/migration"
|
|
194
219
|
}
|
package/package.json
CHANGED
|
@@ -43,6 +43,8 @@ data "aws_region" "current" {}
|
|
|
43
43
|
locals {
|
|
44
44
|
aws_account_id = data.aws_caller_identity.current.account_id
|
|
45
45
|
aws_region = data.aws_region.current.id
|
|
46
|
+
|
|
47
|
+
gateway_waf_log_group_name = var.enable_waf ? "aws-waf-logs-my-gateway-\${random_id.unique_suffix.hex}" : null
|
|
46
48
|
}
|
|
47
49
|
|
|
48
50
|
resource "random_id" "unique_suffix" {
|
|
@@ -205,14 +207,61 @@ resource "aws_wafv2_web_acl_association" "gateway_waf" {
|
|
|
205
207
|
web_acl_arn = aws_wafv2_web_acl.gateway_waf[0].arn
|
|
206
208
|
}
|
|
207
209
|
|
|
210
|
+
# KMS key for encrypting WAF request logs at rest
|
|
211
|
+
resource "aws_kms_key" "gateway_waf_logs" {
|
|
212
|
+
count = var.enable_waf ? 1 : 0
|
|
213
|
+
|
|
214
|
+
description = "MyGateway gateway WAF log encryption"
|
|
215
|
+
deletion_window_in_days = 7
|
|
216
|
+
enable_key_rotation = true
|
|
217
|
+
|
|
218
|
+
policy = jsonencode({
|
|
219
|
+
Version = "2012-10-17"
|
|
220
|
+
Statement = [
|
|
221
|
+
{
|
|
222
|
+
Sid = "Enable IAM User Permissions"
|
|
223
|
+
Effect = "Allow"
|
|
224
|
+
Principal = { AWS = "arn:aws:iam::\${local.aws_account_id}:root" }
|
|
225
|
+
Action = "kms:*"
|
|
226
|
+
Resource = "*"
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
Sid = "Allow CloudWatch Logs"
|
|
230
|
+
Effect = "Allow"
|
|
231
|
+
Principal = { Service = "logs.\${local.aws_region}.amazonaws.com" }
|
|
232
|
+
Action = [
|
|
233
|
+
"kms:Encrypt",
|
|
234
|
+
"kms:Decrypt",
|
|
235
|
+
"kms:ReEncrypt*",
|
|
236
|
+
"kms:GenerateDataKey*",
|
|
237
|
+
"kms:DescribeKey"
|
|
238
|
+
]
|
|
239
|
+
Resource = "*"
|
|
240
|
+
Condition = {
|
|
241
|
+
ArnEquals = {
|
|
242
|
+
"kms:EncryptionContext:aws:logs:arn" = "arn:aws:logs:\${local.aws_region}:\${local.aws_account_id}:log-group:\${local.gateway_waf_log_group_name}"
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
]
|
|
247
|
+
})
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
resource "aws_kms_alias" "gateway_waf_logs" {
|
|
251
|
+
count = var.enable_waf ? 1 : 0
|
|
252
|
+
|
|
253
|
+
name = "alias/my-gateway-\${random_id.unique_suffix.hex}-waf-logs"
|
|
254
|
+
target_key_id = aws_kms_key.gateway_waf_logs[0].key_id
|
|
255
|
+
}
|
|
256
|
+
|
|
208
257
|
# WAF request logs. WAFv2 requires the \`aws-waf-logs-\` name prefix.
|
|
209
258
|
resource "aws_cloudwatch_log_group" "gateway_waf_logs" {
|
|
210
|
-
#checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
|
|
211
259
|
#checkov:skip=CKV_AWS_338:Log retention set to one year which is sufficient for WAF logs
|
|
212
260
|
count = var.enable_waf ? 1 : 0
|
|
213
261
|
|
|
214
|
-
name =
|
|
262
|
+
name = local.gateway_waf_log_group_name
|
|
215
263
|
retention_in_days = 365
|
|
264
|
+
kms_key_id = aws_kms_key.gateway_waf_logs[0].arn
|
|
216
265
|
}
|
|
217
266
|
|
|
218
267
|
resource "aws_wafv2_web_acl_logging_configuration" "gateway_waf_logging" {
|
|
@@ -62,14 +62,13 @@ construct's \`grantInvokeAccess\` grants exactly those two actions.
|
|
|
62
62
|
## Customizing your Harness
|
|
63
63
|
|
|
64
64
|
Edit \`src/PROMPT.md\` for the system prompt. Everything else is configured
|
|
65
|
-
where you instantiate the infrastructure — including tools, which
|
|
66
|
-
|
|
65
|
+
where you instantiate the infrastructure — including tools, which default
|
|
66
|
+
to none:
|
|
67
67
|
|
|
68
68
|
- CDK construct props, for example
|
|
69
69
|
\`new MyHarness(this, 'MyHarness', { allowedTools: ['@builtin'] })\`
|
|
70
|
-
- Terraform, by setting
|
|
71
|
-
\`
|
|
72
|
-
variable if you would rather set it as a module argument
|
|
70
|
+
- Terraform, by setting the module's \`allowed_tools\` variable, for example
|
|
71
|
+
\`allowed_tools = ["@builtin"]\`
|
|
73
72
|
|
|
74
73
|
The generated infrastructure is also yours to edit directly:
|
|
75
74
|
|
|
@@ -59,14 +59,13 @@ construct's `grantInvokeAccess` grants exactly those two actions.
|
|
|
59
59
|
## Customizing your Harness
|
|
60
60
|
|
|
61
61
|
Edit `src/PROMPT.md` for the system prompt. Everything else is configured
|
|
62
|
-
where you instantiate the infrastructure — including tools, which
|
|
63
|
-
|
|
62
|
+
where you instantiate the infrastructure — including tools, which default
|
|
63
|
+
to none:
|
|
64
64
|
|
|
65
65
|
- CDK construct props, for example
|
|
66
66
|
`new <%- nameClassName %>(this, '<%- nameClassName %>', { allowedTools: ['@builtin'] })`
|
|
67
|
-
- Terraform, by setting
|
|
68
|
-
`
|
|
69
|
-
variable if you would rather set it as a module argument
|
|
67
|
+
- Terraform, by setting the module's `allowed_tools` variable, for example
|
|
68
|
+
`allowed_tools = ["@builtin"]`
|
|
70
69
|
|
|
71
70
|
The generated infrastructure is also yours to edit directly:
|
|
72
71
|
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`agentcore-harness-no-tools-by-default migration > cdk > defaults allowedTools to none and passes it explicitly 1`] = `
|
|
4
|
+
"import * as agentcore from 'aws-cdk-lib/aws-bedrockagentcore';
|
|
5
|
+
import { Construct } from 'constructs';
|
|
6
|
+
|
|
7
|
+
export class MyHarness extends Construct {
|
|
8
|
+
public readonly harness: agentcore.CfnHarness;
|
|
9
|
+
|
|
10
|
+
constructor(scope: Construct, id: string, props?: MyHarnessProps) {
|
|
11
|
+
super(scope, id);
|
|
12
|
+
|
|
13
|
+
const stack = Stack.of(this);
|
|
14
|
+
const {
|
|
15
|
+
// The service treats an absent allowedTools as every tool, so this
|
|
16
|
+
// defaults to none and is always passed explicitly.
|
|
17
|
+
allowedTools = [],
|
|
18
|
+
executionRole,
|
|
19
|
+
modelResourceArns = [
|
|
20
|
+
\`arn:\${stack.partition}:bedrock:*::foundation-model/*\`,
|
|
21
|
+
],
|
|
22
|
+
vpc,
|
|
23
|
+
vpcSubnets,
|
|
24
|
+
securityGroups,
|
|
25
|
+
...harnessProps
|
|
26
|
+
} = props ?? {};
|
|
27
|
+
|
|
28
|
+
this.harness = new agentcore.CfnHarness(this, 'Harness', {
|
|
29
|
+
model: {
|
|
30
|
+
bedrockModelConfig: {
|
|
31
|
+
modelId: 'global.anthropic.claude-sonnet-4-6',
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
systemPrompt: [{ text: systemPrompt }],
|
|
35
|
+
...harnessProps,
|
|
36
|
+
allowedTools,
|
|
37
|
+
// Set after harnessProps so the deployed name always matches the
|
|
38
|
+
// execution role's workload-identity resource pattern.
|
|
39
|
+
harnessName,
|
|
40
|
+
executionRoleArn: this.executionRole.roleArn,
|
|
41
|
+
environment,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
"
|
|
46
|
+
`;
|
|
47
|
+
|
|
48
|
+
exports[`agentcore-harness-no-tools-by-default migration > terraform > declares allowed_tools defaulting to none and assigns it 1`] = `
|
|
49
|
+
"variable "model_id" {
|
|
50
|
+
description = "Amazon Bedrock model or inference profile used by default."
|
|
51
|
+
type = string
|
|
52
|
+
default = "global.anthropic.claude-sonnet-4-6"
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
variable "allowed_tools" {
|
|
56
|
+
description = "Tools the Harness may use. Defaults to none; set [\\"@builtin\\"] for every built-in tool, or name individual tools. Always sent explicitly, since the service treats an absent value as every tool."
|
|
57
|
+
type = list(string)
|
|
58
|
+
default = []
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
variable "model_resource_arns" {
|
|
62
|
+
description = "Bedrock model and inference-profile ARNs the execution role may invoke."
|
|
63
|
+
type = set(string)
|
|
64
|
+
default = null
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
resource "aws_bedrockagentcore_harness" "this" {
|
|
68
|
+
harness_name = local.harness_name
|
|
69
|
+
execution_role_arn = aws_iam_role.execution_role.arn
|
|
70
|
+
allowed_tools = var.allowed_tools
|
|
71
|
+
|
|
72
|
+
model {
|
|
73
|
+
bedrock_model_config {
|
|
74
|
+
model_id = var.model_id
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
"
|
|
79
|
+
`;
|
|
@@ -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,87 @@
|
|
|
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 { applyGritQL, GRIT_INSERT_PLACEHOLDER, insertViaGritQL, matchGritQL } from "../../../utils/ast.js";
|
|
6
|
+
import { formatFilesInSubtree } from "../../../utils/format.js";
|
|
7
|
+
import { PACKAGES_DIR, SHARED_CONSTRUCTS_DIR, SHARED_TERRAFORM_DIR } from "../../../utils/shared-constructs-constants.js";
|
|
8
|
+
/**
|
|
9
|
+
* Pin each vended Harness to no tools by default.
|
|
10
|
+
*
|
|
11
|
+
* AgentCore treats an absent `allowedTools` as every tool, so a Harness that
|
|
12
|
+
* never set it deployed with `allowedTools: ["*"]` — shell execution and file
|
|
13
|
+
* read/write included. Both providers now send the field explicitly, defaulting
|
|
14
|
+
* to none.
|
|
15
|
+
*
|
|
16
|
+
* These files are generated with `KeepExisting`, so an upgraded workspace keeps
|
|
17
|
+
* the implicit every-tool default until this runs. Diverged files are left
|
|
18
|
+
* untouched and reported via `nextSteps`.
|
|
19
|
+
*/ const CDK_HARNESSES_DIR = `${PACKAGES_DIR}/${SHARED_CONSTRUCTS_DIR}/src/app/harnesses`;
|
|
20
|
+
const TERRAFORM_HARNESSES_DIR = `${PACKAGES_DIR}/${SHARED_TERRAFORM_DIR}/src/app/harnesses`;
|
|
21
|
+
const hcl = (pattern)=>`language hcl\n${pattern}`;
|
|
22
|
+
const ALLOWED_TOOLS_VARIABLE = [
|
|
23
|
+
'variable "allowed_tools" {',
|
|
24
|
+
' description = "Tools the Harness may use. Defaults to none; set [\\"@builtin\\"] for every built-in tool, or name individual tools. Always sent explicitly, since the service treats an absent value as every tool."',
|
|
25
|
+
' type = list(string)',
|
|
26
|
+
' default = []',
|
|
27
|
+
'}'
|
|
28
|
+
].join('\n');
|
|
29
|
+
const divergedMessage = (filePath, remedy)=>`${filePath}: has diverged from the generated shape - left untouched. AgentCore treats an absent allowedTools as every tool, so this Harness deploys with all built-in tools (including shell and file access). ${remedy}`;
|
|
30
|
+
/**
|
|
31
|
+
* Default the construct's `allowedTools` to none and pass it to the resource
|
|
32
|
+
* after the props spread, so an undefined caller value cannot reinstate the
|
|
33
|
+
* service's every-tool default.
|
|
34
|
+
*/ const migrateCdkConstruct = async (tree, filePath)=>{
|
|
35
|
+
const destructured = await insertViaGritQL(tree, filePath, `\`const { $fields } = props ?? {};\` => \`const {\n ${GRIT_INSERT_PLACEHOLDER}\n $fields\n } = props ?? {};\``, [
|
|
36
|
+
'// The service treats an absent allowedTools as every tool, so this',
|
|
37
|
+
'// defaults to none and is always passed explicitly.',
|
|
38
|
+
'allowedTools = [],'
|
|
39
|
+
].join('\n '));
|
|
40
|
+
if (!destructured) return false;
|
|
41
|
+
return await applyGritQL(tree, filePath, '`new agentcore.CfnHarness($scope, $id, { $props })` where {' + ' $props <: contains spread_element() as $spread,' + ' $spread => `$spread,\n allowedTools`' + ' }');
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Declare `allowed_tools` and assign it to the Harness resource, so the module
|
|
45
|
+
* always sends the field.
|
|
46
|
+
*/ const migrateTerraformModule = async (tree, filePath)=>{
|
|
47
|
+
const declared = await insertViaGritQL(tree, filePath, hcl(`\`variable "model_resource_arns" { $props }\` => \`${GRIT_INSERT_PLACEHOLDER}\n\nvariable "model_resource_arns" {\n $props\n}\``), ALLOWED_TOOLS_VARIABLE);
|
|
48
|
+
if (!declared) return false;
|
|
49
|
+
// Appended after the existing arguments so their alignment is preserved;
|
|
50
|
+
// `terraform fmt` re-aligns the block.
|
|
51
|
+
return await applyGritQL(tree, filePath, hcl('`execution_role_arn = aws_iam_role.execution_role.arn` => `execution_role_arn = aws_iam_role.execution_role.arn\n allowed_tools = var.allowed_tools`'));
|
|
52
|
+
};
|
|
53
|
+
export default async function migration(tree) {
|
|
54
|
+
const nextSteps = [];
|
|
55
|
+
for (const dirName of tree.exists(CDK_HARNESSES_DIR) ? tree.children(CDK_HARNESSES_DIR) : []){
|
|
56
|
+
const filePath = joinPathFragments(CDK_HARNESSES_DIR, dirName, `${dirName}.ts`);
|
|
57
|
+
if (!tree.exists(filePath)) {
|
|
58
|
+
continue; // Not a Harness construct directory.
|
|
59
|
+
}
|
|
60
|
+
// Already pinned, by this migration or by hand.
|
|
61
|
+
if (tree.read(filePath, 'utf-8')?.includes('allowedTools = [],')) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (!await migrateCdkConstruct(tree, filePath)) {
|
|
65
|
+
nextSteps.push(divergedMessage(filePath, 'Default `allowedTools` to `[]` when destructuring props, and pass `allowedTools` to the CfnHarness after the `...harnessProps` spread.'));
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
for (const dirName of tree.exists(TERRAFORM_HARNESSES_DIR) ? tree.children(TERRAFORM_HARNESSES_DIR) : []){
|
|
69
|
+
const filePath = joinPathFragments(TERRAFORM_HARNESSES_DIR, dirName, `${dirName}.tf`);
|
|
70
|
+
if (!tree.exists(filePath)) {
|
|
71
|
+
continue; // Not a Harness module directory.
|
|
72
|
+
}
|
|
73
|
+
// Already assigned, by this migration or by hand.
|
|
74
|
+
if (await matchGritQL(tree, filePath, hcl('`allowed_tools = $_`'))) {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (!await migrateTerraformModule(tree, filePath)) {
|
|
78
|
+
nextSteps.push(divergedMessage(filePath, 'Declare an `allowed_tools` variable (list(string), default []) and assign `allowed_tools = var.allowed_tools` on the `aws_bedrockagentcore_harness` resource.'));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
await formatFilesInSubtree(tree);
|
|
82
|
+
return {
|
|
83
|
+
nextSteps
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
//# sourceMappingURL=migration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/latest/agentcore-harness-no-tools-by-default/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 applyGritQL,\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_CONSTRUCTS_DIR,\n SHARED_TERRAFORM_DIR,\n} from '../../../utils/shared-constructs-constants.js';\n\n/**\n * Pin each vended Harness to no tools by default.\n *\n * AgentCore treats an absent `allowedTools` as every tool, so a Harness that\n * never set it deployed with `allowedTools: [\"*\"]` — shell execution and file\n * read/write included. Both providers now send the field explicitly, defaulting\n * to none.\n *\n * These files are generated with `KeepExisting`, so an upgraded workspace keeps\n * the implicit every-tool default until this runs. Diverged files are left\n * untouched and reported via `nextSteps`.\n */\n\nconst CDK_HARNESSES_DIR = `${PACKAGES_DIR}/${SHARED_CONSTRUCTS_DIR}/src/app/harnesses`;\nconst TERRAFORM_HARNESSES_DIR = `${PACKAGES_DIR}/${SHARED_TERRAFORM_DIR}/src/app/harnesses`;\n\nconst hcl = (pattern: string) => `language hcl\\n${pattern}`;\n\nconst ALLOWED_TOOLS_VARIABLE = [\n 'variable \"allowed_tools\" {',\n ' description = \"Tools the Harness may use. Defaults to none; set [\\\\\"@builtin\\\\\"] for every built-in tool, or name individual tools. Always sent explicitly, since the service treats an absent value as every tool.\"',\n ' type = list(string)',\n ' default = []',\n '}',\n].join('\\n');\n\nconst divergedMessage = (filePath: string, remedy: string) =>\n `${filePath}: has diverged from the generated shape - left untouched. AgentCore treats an absent allowedTools as every tool, so this Harness deploys with all built-in tools (including shell and file access). ${remedy}`;\n\n/**\n * Default the construct's `allowedTools` to none and pass it to the resource\n * after the props spread, so an undefined caller value cannot reinstate the\n * service's every-tool default.\n */\nconst migrateCdkConstruct = async (\n tree: Tree,\n filePath: string,\n): Promise<boolean> => {\n const destructured = await insertViaGritQL(\n tree,\n filePath,\n `\\`const { $fields } = props ?? {};\\` => \\`const {\\n ${GRIT_INSERT_PLACEHOLDER}\\n $fields\\n } = props ?? {};\\``,\n [\n '// The service treats an absent allowedTools as every tool, so this',\n '// defaults to none and is always passed explicitly.',\n 'allowedTools = [],',\n ].join('\\n '),\n );\n if (!destructured) return false;\n\n return await applyGritQL(\n tree,\n filePath,\n '`new agentcore.CfnHarness($scope, $id, { $props })` where {' +\n ' $props <: contains spread_element() as $spread,' +\n ' $spread => `$spread,\\n allowedTools`' +\n ' }',\n );\n};\n\n/**\n * Declare `allowed_tools` and assign it to the Harness resource, so the module\n * always sends the field.\n */\nconst migrateTerraformModule = async (\n tree: Tree,\n filePath: string,\n): Promise<boolean> => {\n const declared = await insertViaGritQL(\n tree,\n filePath,\n hcl(\n `\\`variable \"model_resource_arns\" { $props }\\` => \\`${GRIT_INSERT_PLACEHOLDER}\\n\\nvariable \"model_resource_arns\" {\\n $props\\n}\\``,\n ),\n ALLOWED_TOOLS_VARIABLE,\n );\n if (!declared) return false;\n\n // Appended after the existing arguments so their alignment is preserved;\n // `terraform fmt` re-aligns the block.\n return await applyGritQL(\n tree,\n filePath,\n hcl(\n '`execution_role_arn = aws_iam_role.execution_role.arn` => `execution_role_arn = aws_iam_role.execution_role.arn\\n allowed_tools = var.allowed_tools`',\n ),\n );\n};\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n for (const dirName of tree.exists(CDK_HARNESSES_DIR)\n ? tree.children(CDK_HARNESSES_DIR)\n : []) {\n const filePath = joinPathFragments(\n CDK_HARNESSES_DIR,\n dirName,\n `${dirName}.ts`,\n );\n if (!tree.exists(filePath)) {\n continue; // Not a Harness construct directory.\n }\n\n // Already pinned, by this migration or by hand.\n if (tree.read(filePath, 'utf-8')?.includes('allowedTools = [],')) {\n continue;\n }\n\n if (!(await migrateCdkConstruct(tree, filePath))) {\n nextSteps.push(\n divergedMessage(\n filePath,\n 'Default `allowedTools` to `[]` when destructuring props, and pass `allowedTools` to the CfnHarness after the `...harnessProps` spread.',\n ),\n );\n }\n }\n\n for (const dirName of tree.exists(TERRAFORM_HARNESSES_DIR)\n ? tree.children(TERRAFORM_HARNESSES_DIR)\n : []) {\n const filePath = joinPathFragments(\n TERRAFORM_HARNESSES_DIR,\n dirName,\n `${dirName}.tf`,\n );\n if (!tree.exists(filePath)) {\n continue; // Not a Harness module directory.\n }\n\n // Already assigned, by this migration or by hand.\n if (await matchGritQL(tree, filePath, hcl('`allowed_tools = $_`'))) {\n continue;\n }\n\n if (!(await migrateTerraformModule(tree, filePath))) {\n nextSteps.push(\n divergedMessage(\n filePath,\n 'Declare an `allowed_tools` variable (list(string), default []) and assign `allowed_tools = var.allowed_tools` on the `aws_bedrockagentcore_harness` resource.',\n ),\n );\n }\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["joinPathFragments","applyGritQL","GRIT_INSERT_PLACEHOLDER","insertViaGritQL","matchGritQL","formatFilesInSubtree","PACKAGES_DIR","SHARED_CONSTRUCTS_DIR","SHARED_TERRAFORM_DIR","CDK_HARNESSES_DIR","TERRAFORM_HARNESSES_DIR","hcl","pattern","ALLOWED_TOOLS_VARIABLE","join","divergedMessage","filePath","remedy","migrateCdkConstruct","tree","destructured","migrateTerraformModule","declared","migration","nextSteps","dirName","exists","children","read","includes","push"],"mappings":"AAAA;;;CAGC,GACD,SACEA,iBAAiB,QAGZ,aAAa;AACpB,SACEC,WAAW,EACXC,uBAAuB,EACvBC,eAAe,EACfC,WAAW,QACN,wBAAwB;AAC/B,SAASC,oBAAoB,QAAQ,2BAA2B;AAChE,SACEC,YAAY,EACZC,qBAAqB,EACrBC,oBAAoB,QACf,gDAAgD;AAEvD;;;;;;;;;;;CAWC,GAED,MAAMC,oBAAoB,GAAGH,aAAa,CAAC,EAAEC,sBAAsB,kBAAkB,CAAC;AACtF,MAAMG,0BAA0B,GAAGJ,aAAa,CAAC,EAAEE,qBAAqB,kBAAkB,CAAC;AAE3F,MAAMG,MAAM,CAACC,UAAoB,CAAC,cAAc,EAAEA,SAAS;AAE3D,MAAMC,yBAAyB;IAC7B;IACA;IACA;IACA;IACA;CACD,CAACC,IAAI,CAAC;AAEP,MAAMC,kBAAkB,CAACC,UAAkBC,SACzC,GAAGD,SAAS,oMAAoM,EAAEC,QAAQ;AAE5N;;;;CAIC,GACD,MAAMC,sBAAsB,OAC1BC,MACAH;IAEA,MAAMI,eAAe,MAAMjB,gBACzBgB,MACAH,UACA,CAAC,yDAAyD,EAAEd,wBAAwB,uCAAuC,CAAC,EAC5H;QACE;QACA;QACA;KACD,CAACY,IAAI,CAAC;IAET,IAAI,CAACM,cAAc,OAAO;IAE1B,OAAO,MAAMnB,YACXkB,MACAH,UACA,gEACE,qDACA,+CACA;AAEN;AAEA;;;CAGC,GACD,MAAMK,yBAAyB,OAC7BF,MACAH;IAEA,MAAMM,WAAW,MAAMnB,gBACrBgB,MACAH,UACAL,IACE,CAAC,mDAAmD,EAAET,wBAAwB,mDAAmD,CAAC,GAEpIW;IAEF,IAAI,CAACS,UAAU,OAAO;IAEtB,yEAAyE;IACzE,uCAAuC;IACvC,OAAO,MAAMrB,YACXkB,MACAH,UACAL,IACE;AAGN;AAEA,eAAe,eAAeY,UAC5BJ,IAAU;IAEV,MAAMK,YAAsB,EAAE;IAE9B,KAAK,MAAMC,WAAWN,KAAKO,MAAM,CAACjB,qBAC9BU,KAAKQ,QAAQ,CAAClB,qBACd,EAAE,CAAE;QACN,MAAMO,WAAWhB,kBACfS,mBACAgB,SACA,GAAGA,QAAQ,GAAG,CAAC;QAEjB,IAAI,CAACN,KAAKO,MAAM,CAACV,WAAW;YAC1B,UAAU,qCAAqC;QACjD;QAEA,gDAAgD;QAChD,IAAIG,KAAKS,IAAI,CAACZ,UAAU,UAAUa,SAAS,uBAAuB;YAChE;QACF;QAEA,IAAI,CAAE,MAAMX,oBAAoBC,MAAMH,WAAY;YAChDQ,UAAUM,IAAI,CACZf,gBACEC,UACA;QAGN;IACF;IAEA,KAAK,MAAMS,WAAWN,KAAKO,MAAM,CAAChB,2BAC9BS,KAAKQ,QAAQ,CAACjB,2BACd,EAAE,CAAE;QACN,MAAMM,WAAWhB,kBACfU,yBACAe,SACA,GAAGA,QAAQ,GAAG,CAAC;QAEjB,IAAI,CAACN,KAAKO,MAAM,CAACV,WAAW;YAC1B,UAAU,kCAAkC;QAC9C;QAEA,kDAAkD;QAClD,IAAI,MAAMZ,YAAYe,MAAMH,UAAUL,IAAI,0BAA0B;YAClE;QACF;QAEA,IAAI,CAAE,MAAMU,uBAAuBF,MAAMH,WAAY;YACnDQ,UAAUM,IAAI,CACZf,gBACEC,UACA;QAGN;IACF;IAEA,MAAMX,qBAAqBc;IAE3B,OAAO;QAAEK;IAAU;AACrB"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
|
2
|
+
|
|
3
|
+
exports[`rdb-terraform-aurora-app-module-defaults migration > should align the app module defaults with the core module 1`] = `
|
|
4
|
+
"variable "enable_credential_rotation" {
|
|
5
|
+
description = "Whether to enable automatic credential rotation for the admin secret."
|
|
6
|
+
type = bool
|
|
7
|
+
default = true
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
variable "enable_cloudwatch_logs" {
|
|
11
|
+
description = "Whether to export Aurora engine logs to CloudWatch. PostgreSQL logs DDL statements only (log_statement=ddl); MySQL enables Advanced Auditing scoped to connections and DDL (server_audit_events=CONNECT,QUERY_DDL). Neither logs statement parameter values, to avoid leaking PII into log data."
|
|
12
|
+
type = bool
|
|
13
|
+
default = true
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
variable "enable_performance_insights" {
|
|
17
|
+
description = "Whether to enable Performance Insights on Aurora cluster instances."
|
|
18
|
+
type = bool
|
|
19
|
+
default = true
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
variable "enable_backup" {
|
|
23
|
+
description = "Whether to provision an AWS Backup plan for the Aurora cluster."
|
|
24
|
+
type = bool
|
|
25
|
+
default = false
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
variable "enable_key_rotation" {
|
|
29
|
+
description = "Whether to enable automatic key rotation on the KMS key used to encrypt the Aurora cluster and its credentials secret."
|
|
30
|
+
type = bool
|
|
31
|
+
default = true
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
variable "tags" {
|
|
35
|
+
description = "Tags to apply to all resources."
|
|
36
|
+
type = map(string)
|
|
37
|
+
default = {}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
module "aurora" {
|
|
41
|
+
source = "../../../core/rdb/aurora"
|
|
42
|
+
|
|
43
|
+
name = "my-db"
|
|
44
|
+
engine = "aurora-postgresql"
|
|
45
|
+
enable_credential_rotation = var.enable_credential_rotation
|
|
46
|
+
enable_cloudwatch_logs = var.enable_cloudwatch_logs
|
|
47
|
+
enable_performance_insights = var.enable_performance_insights
|
|
48
|
+
enable_backup = var.enable_backup
|
|
49
|
+
tags = var.tags
|
|
50
|
+
|
|
51
|
+
enable_key_rotation = var.enable_key_rotation
|
|
52
|
+
}
|
|
53
|
+
"
|
|
54
|
+
`;
|
|
@@ -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,86 @@
|
|
|
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 { applyGritQL, 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
|
+
* Align each vended per-database Terraform app module
|
|
10
|
+
* (`app/dbs/<name>/<name>.tf`) with the core Aurora module it wraps.
|
|
11
|
+
*
|
|
12
|
+
* The app module is what a root configuration instantiates and it forwards its
|
|
13
|
+
* own value down, so its default is the one that takes effect:
|
|
14
|
+
*
|
|
15
|
+
* - `enable_cloudwatch_logs` defaulted to `false` against the core module's
|
|
16
|
+
* `true`, so Aurora exported no engine logs and the cluster parameter group
|
|
17
|
+
* that configures them (`log_statement=ddl` on PostgreSQL,
|
|
18
|
+
* `server_audit_events=CONNECT,QUERY_DDL` on MySQL) was never created —
|
|
19
|
+
* the CDK construct enabled both.
|
|
20
|
+
* - `enable_key_rotation` was never declared, leaving the core module's
|
|
21
|
+
* variable unreachable from a root configuration.
|
|
22
|
+
*
|
|
23
|
+
* These files are generated with `KeepExisting`, so an upgraded workspace keeps
|
|
24
|
+
* the diverged defaults until this runs. Diverged files are left untouched and
|
|
25
|
+
* reported via `nextSteps`.
|
|
26
|
+
*/ const TERRAFORM_DBS_APP_DIR = `${PACKAGES_DIR}/${SHARED_TERRAFORM_DIR}/src/app/dbs`;
|
|
27
|
+
const hcl = (pattern)=>`language hcl\n${pattern}`;
|
|
28
|
+
const KEY_ROTATION_VARIABLE = [
|
|
29
|
+
'variable "enable_key_rotation" {',
|
|
30
|
+
' description = "Whether to enable automatic key rotation on the KMS key used to encrypt the Aurora cluster and its credentials secret."',
|
|
31
|
+
' type = bool',
|
|
32
|
+
' default = true',
|
|
33
|
+
'}'
|
|
34
|
+
].join('\n');
|
|
35
|
+
const divergedMessage = (filePath)=>`${filePath}: has diverged from the generated shape - left untouched. To export Aurora engine logs to CloudWatch as the CDK construct and the core Terraform module do, default \`enable_cloudwatch_logs\` to true here, and declare an \`enable_key_rotation\` variable (bool, default true) forwarded to the aurora module (see the ts#rdb generator's dbs app template).`;
|
|
36
|
+
const OLD_LOGS_DESCRIPTION = 'Whether to export Aurora engine logs to CloudWatch. PostgreSQL also enables verbose statement logging.';
|
|
37
|
+
const NEW_LOGS_DESCRIPTION = 'Whether to export Aurora engine logs to CloudWatch. PostgreSQL logs DDL statements only (log_statement=ddl); MySQL enables Advanced Auditing scoped to connections and DDL (server_audit_events=CONNECT,QUERY_DDL). Neither logs statement parameter values, to avoid leaking PII into log data.';
|
|
38
|
+
/**
|
|
39
|
+
* Flip the app module's `enable_cloudwatch_logs` default to match the core
|
|
40
|
+
* module, and replace the description that documented the old behaviour.
|
|
41
|
+
*
|
|
42
|
+
* Keyed on that description, which is the only thing distinguishing the vended
|
|
43
|
+
* `default = false` from a user who deliberately turned log export off.
|
|
44
|
+
*/ const migrateCloudwatchLogsDefault = (tree, filePath)=>applyGritQL(tree, filePath, hcl(`\`variable "enable_cloudwatch_logs" { $props }\` where {` + ` $props <: contains \`description = "${OLD_LOGS_DESCRIPTION}"\` => \`description = "${NEW_LOGS_DESCRIPTION}"\`,` + ` $props <: contains \`default = false\` => \`default = true\`` + ` }`));
|
|
45
|
+
/**
|
|
46
|
+
* Declare `enable_key_rotation` and forward it to the core aurora module, so a
|
|
47
|
+
* root configuration can reach the variable the core module already exposes.
|
|
48
|
+
*/ const migrateKeyRotationVariable = async (tree, filePath)=>{
|
|
49
|
+
if (await matchGritQL(tree, filePath, hcl('`variable "enable_key_rotation" { $_ }`'))) {
|
|
50
|
+
return; // Already declared.
|
|
51
|
+
}
|
|
52
|
+
const declared = await insertViaGritQL(tree, filePath, hcl(`\`variable "enable_backup" { $props }\` => \`variable "enable_backup" {\n $props\n}\n\n${GRIT_INSERT_PLACEHOLDER}\``), KEY_ROTATION_VARIABLE);
|
|
53
|
+
if (!declared) return;
|
|
54
|
+
// Appended after the existing arguments so their alignment is preserved;
|
|
55
|
+
// `terraform fmt` re-aligns the block.
|
|
56
|
+
await applyGritQL(tree, filePath, hcl(`\`module "aurora" { $props }\` => \`module "aurora" {\n $props\n\n enable_key_rotation = var.enable_key_rotation\n}\``));
|
|
57
|
+
};
|
|
58
|
+
export default async function migration(tree) {
|
|
59
|
+
const nextSteps = [];
|
|
60
|
+
if (!tree.exists(TERRAFORM_DBS_APP_DIR)) {
|
|
61
|
+
return {
|
|
62
|
+
nextSteps
|
|
63
|
+
}; // This workspace has no Terraform database modules.
|
|
64
|
+
}
|
|
65
|
+
for (const dirName of tree.children(TERRAFORM_DBS_APP_DIR)){
|
|
66
|
+
const filePath = joinPathFragments(TERRAFORM_DBS_APP_DIR, dirName, `${dirName}.tf`);
|
|
67
|
+
if (!tree.exists(filePath)) {
|
|
68
|
+
continue; // Not a database app module directory.
|
|
69
|
+
}
|
|
70
|
+
// Both edits hang off the shape the generator produces: the two variables
|
|
71
|
+
// and the module call that forwards them.
|
|
72
|
+
const recognised = await matchGritQL(tree, filePath, hcl('`variable "enable_cloudwatch_logs" { $_ }`')) && await matchGritQL(tree, filePath, hcl('`variable "enable_backup" { $_ }`')) && await matchGritQL(tree, filePath, hcl('`module "aurora" { $props }` where { $props <: contains `enable_cloudwatch_logs = var.enable_cloudwatch_logs` }'));
|
|
73
|
+
if (!recognised) {
|
|
74
|
+
nextSteps.push(divergedMessage(filePath));
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
await migrateCloudwatchLogsDefault(tree, filePath);
|
|
78
|
+
await migrateKeyRotationVariable(tree, filePath);
|
|
79
|
+
}
|
|
80
|
+
await formatFilesInSubtree(tree);
|
|
81
|
+
return {
|
|
82
|
+
nextSteps
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
//# sourceMappingURL=migration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/latest/rdb-terraform-aurora-app-module-defaults/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 applyGritQL,\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 * Align each vended per-database Terraform app module\n * (`app/dbs/<name>/<name>.tf`) with the core Aurora module it wraps.\n *\n * The app module is what a root configuration instantiates and it forwards its\n * own value down, so its default is the one that takes effect:\n *\n * - `enable_cloudwatch_logs` defaulted to `false` against the core module's\n * `true`, so Aurora exported no engine logs and the cluster parameter group\n * that configures them (`log_statement=ddl` on PostgreSQL,\n * `server_audit_events=CONNECT,QUERY_DDL` on MySQL) was never created —\n * the CDK construct enabled both.\n * - `enable_key_rotation` was never declared, leaving the core module's\n * variable unreachable from a root configuration.\n *\n * These files are generated with `KeepExisting`, so an upgraded workspace keeps\n * the diverged defaults until this runs. Diverged files are left untouched and\n * reported via `nextSteps`.\n */\n\nconst TERRAFORM_DBS_APP_DIR = `${PACKAGES_DIR}/${SHARED_TERRAFORM_DIR}/src/app/dbs`;\n\nconst hcl = (pattern: string) => `language hcl\\n${pattern}`;\n\nconst KEY_ROTATION_VARIABLE = [\n 'variable \"enable_key_rotation\" {',\n ' description = \"Whether to enable automatic key rotation on the KMS key used to encrypt the Aurora cluster and its credentials secret.\"',\n ' type = bool',\n ' default = true',\n '}',\n].join('\\n');\n\nconst divergedMessage = (filePath: string) =>\n `${filePath}: has diverged from the generated shape - left untouched. To export Aurora engine logs to CloudWatch as the CDK construct and the core Terraform module do, default \\`enable_cloudwatch_logs\\` to true here, and declare an \\`enable_key_rotation\\` variable (bool, default true) forwarded to the aurora module (see the ts#rdb generator's dbs app template).`;\n\nconst OLD_LOGS_DESCRIPTION =\n 'Whether to export Aurora engine logs to CloudWatch. PostgreSQL also enables verbose statement logging.';\nconst NEW_LOGS_DESCRIPTION =\n 'Whether to export Aurora engine logs to CloudWatch. PostgreSQL logs DDL statements only (log_statement=ddl); MySQL enables Advanced Auditing scoped to connections and DDL (server_audit_events=CONNECT,QUERY_DDL). Neither logs statement parameter values, to avoid leaking PII into log data.';\n\n/**\n * Flip the app module's `enable_cloudwatch_logs` default to match the core\n * module, and replace the description that documented the old behaviour.\n *\n * Keyed on that description, which is the only thing distinguishing the vended\n * `default = false` from a user who deliberately turned log export off.\n */\nconst migrateCloudwatchLogsDefault = (tree: Tree, filePath: string) =>\n applyGritQL(\n tree,\n filePath,\n hcl(\n `\\`variable \"enable_cloudwatch_logs\" { $props }\\` where {` +\n ` $props <: contains \\`description = \"${OLD_LOGS_DESCRIPTION}\"\\` => \\`description = \"${NEW_LOGS_DESCRIPTION}\"\\`,` +\n ` $props <: contains \\`default = false\\` => \\`default = true\\`` +\n ` }`,\n ),\n );\n\n/**\n * Declare `enable_key_rotation` and forward it to the core aurora module, so a\n * root configuration can reach the variable the core module already exposes.\n */\nconst migrateKeyRotationVariable = async (\n tree: Tree,\n filePath: string,\n): Promise<void> => {\n if (\n await matchGritQL(\n tree,\n filePath,\n hcl('`variable \"enable_key_rotation\" { $_ }`'),\n )\n ) {\n return; // Already declared.\n }\n\n const declared = await insertViaGritQL(\n tree,\n filePath,\n hcl(\n `\\`variable \"enable_backup\" { $props }\\` => \\`variable \"enable_backup\" {\\n $props\\n}\\n\\n${GRIT_INSERT_PLACEHOLDER}\\``,\n ),\n KEY_ROTATION_VARIABLE,\n );\n if (!declared) return;\n\n // Appended after the existing arguments so their alignment is preserved;\n // `terraform fmt` re-aligns the block.\n await applyGritQL(\n tree,\n filePath,\n hcl(\n `\\`module \"aurora\" { $props }\\` => \\`module \"aurora\" {\\n $props\\n\\n enable_key_rotation = var.enable_key_rotation\\n}\\``,\n ),\n );\n};\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n if (!tree.exists(TERRAFORM_DBS_APP_DIR)) {\n return { nextSteps }; // This workspace has no Terraform database modules.\n }\n\n for (const dirName of tree.children(TERRAFORM_DBS_APP_DIR)) {\n const filePath = joinPathFragments(\n TERRAFORM_DBS_APP_DIR,\n dirName,\n `${dirName}.tf`,\n );\n if (!tree.exists(filePath)) {\n continue; // Not a database app module directory.\n }\n\n // Both edits hang off the shape the generator produces: the two variables\n // and the module call that forwards them.\n const recognised =\n (await matchGritQL(\n tree,\n filePath,\n hcl('`variable \"enable_cloudwatch_logs\" { $_ }`'),\n )) &&\n (await matchGritQL(\n tree,\n filePath,\n hcl('`variable \"enable_backup\" { $_ }`'),\n )) &&\n (await matchGritQL(\n tree,\n filePath,\n hcl(\n '`module \"aurora\" { $props }` where { $props <: contains `enable_cloudwatch_logs = var.enable_cloudwatch_logs` }',\n ),\n ));\n\n if (!recognised) {\n nextSteps.push(divergedMessage(filePath));\n continue;\n }\n\n await migrateCloudwatchLogsDefault(tree, filePath);\n await migrateKeyRotationVariable(tree, filePath);\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["joinPathFragments","applyGritQL","GRIT_INSERT_PLACEHOLDER","insertViaGritQL","matchGritQL","formatFilesInSubtree","PACKAGES_DIR","SHARED_TERRAFORM_DIR","TERRAFORM_DBS_APP_DIR","hcl","pattern","KEY_ROTATION_VARIABLE","join","divergedMessage","filePath","OLD_LOGS_DESCRIPTION","NEW_LOGS_DESCRIPTION","migrateCloudwatchLogsDefault","tree","migrateKeyRotationVariable","declared","migration","nextSteps","exists","dirName","children","recognised","push"],"mappings":"AAAA;;;CAGC,GACD,SACEA,iBAAiB,QAGZ,aAAa;AACpB,SACEC,WAAW,EACXC,uBAAuB,EACvBC,eAAe,EACfC,WAAW,QACN,wBAAwB;AAC/B,SAASC,oBAAoB,QAAQ,2BAA2B;AAChE,SACEC,YAAY,EACZC,oBAAoB,QACf,gDAAgD;AAEvD;;;;;;;;;;;;;;;;;;CAkBC,GAED,MAAMC,wBAAwB,GAAGF,aAAa,CAAC,EAAEC,qBAAqB,YAAY,CAAC;AAEnF,MAAME,MAAM,CAACC,UAAoB,CAAC,cAAc,EAAEA,SAAS;AAE3D,MAAMC,wBAAwB;IAC5B;IACA;IACA;IACA;IACA;CACD,CAACC,IAAI,CAAC;AAEP,MAAMC,kBAAkB,CAACC,WACvB,GAAGA,SAAS,+VAA+V,CAAC;AAE9W,MAAMC,uBACJ;AACF,MAAMC,uBACJ;AAEF;;;;;;CAMC,GACD,MAAMC,+BAA+B,CAACC,MAAYJ,WAChDb,YACEiB,MACAJ,UACAL,IACE,CAAC,wDAAwD,CAAC,GACxD,CAAC,qCAAqC,EAAEM,qBAAqB,wBAAwB,EAAEC,qBAAqB,IAAI,CAAC,GACjH,CAAC,6DAA6D,CAAC,GAC/D,CAAC,EAAE,CAAC;AAIZ;;;CAGC,GACD,MAAMG,6BAA6B,OACjCD,MACAJ;IAEA,IACE,MAAMV,YACJc,MACAJ,UACAL,IAAI,6CAEN;QACA,QAAQ,oBAAoB;IAC9B;IAEA,MAAMW,WAAW,MAAMjB,gBACrBe,MACAJ,UACAL,IACE,CAAC,wFAAwF,EAAEP,wBAAwB,EAAE,CAAC,GAExHS;IAEF,IAAI,CAACS,UAAU;IAEf,yEAAyE;IACzE,uCAAuC;IACvC,MAAMnB,YACJiB,MACAJ,UACAL,IACE,CAAC,uHAAuH,CAAC;AAG/H;AAEA,eAAe,eAAeY,UAC5BH,IAAU;IAEV,MAAMI,YAAsB,EAAE;IAE9B,IAAI,CAACJ,KAAKK,MAAM,CAACf,wBAAwB;QACvC,OAAO;YAAEc;QAAU,GAAG,oDAAoD;IAC5E;IAEA,KAAK,MAAME,WAAWN,KAAKO,QAAQ,CAACjB,uBAAwB;QAC1D,MAAMM,WAAWd,kBACfQ,uBACAgB,SACA,GAAGA,QAAQ,GAAG,CAAC;QAEjB,IAAI,CAACN,KAAKK,MAAM,CAACT,WAAW;YAC1B,UAAU,uCAAuC;QACnD;QAEA,0EAA0E;QAC1E,0CAA0C;QAC1C,MAAMY,aACJ,AAAC,MAAMtB,YACLc,MACAJ,UACAL,IAAI,kDAEL,MAAML,YACLc,MACAJ,UACAL,IAAI,yCAEL,MAAML,YACLc,MACAJ,UACAL,IACE;QAIN,IAAI,CAACiB,YAAY;YACfJ,UAAUK,IAAI,CAACd,gBAAgBC;YAC/B;QACF;QAEA,MAAMG,6BAA6BC,MAAMJ;QACzC,MAAMK,2BAA2BD,MAAMJ;IACzC;IAEA,MAAMT,qBAAqBa;IAE3B,OAAO;QAAEI;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>;
|