@aws/nx-plugin 1.0.0-rc.83 → 1.0.0-rc.85
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/generators.json +7 -0
- package/migrations.json +31 -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/internal/test-matrix/generator.js +16 -0
- package/src/internal/test-matrix/generator.js.map +1 -1
- 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/terraform-project-checkov-target-and-bootstrap-destroy/metadata.json +3 -0
- package/src/migrations/latest/terraform-project-checkov-target-and-bootstrap-destroy/migration.d.ts +6 -0
- package/src/migrations/latest/terraform-project-checkov-target-and-bootstrap-destroy/migration.js +146 -0
- package/src/migrations/latest/terraform-project-checkov-target-and-bootstrap-destroy/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/open-api/json-metadata/generator.d.ts +24 -0
- package/src/open-api/json-metadata/generator.js +37 -0
- package/src/open-api/json-metadata/generator.js.map +1 -0
- package/src/open-api/json-metadata/schema.d.js +6 -0
- package/src/open-api/json-metadata/schema.d.js.map +1 -0
- package/src/open-api/json-metadata/schema.d.ts +9 -0
- package/src/open-api/json-metadata/schema.json +20 -0
- package/src/py/agent/__snapshots__/generator.protocols.spec.ts.snap +12 -0
- package/src/py/fast-api/__snapshots__/generator.terraform.spec.ts.snap +1875 -623
- package/src/py/fast-api/generator.js +2 -1
- package/src/py/fast-api/generator.js.map +1 -1
- 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/sdk/open-api.d.ts +2 -0
- package/src/sdk/open-api.js +2 -1
- package/src/sdk/open-api.js.map +1 -1
- package/src/smithy/ts/api/__snapshots__/generator.spec.ts.snap +1756 -457
- package/src/smithy/ts/api/generator.js +2 -1
- package/src/smithy/ts/api/generator.js.map +1 -1
- package/src/terraform/project/files/application/bootstrap/providers.tf.template +11 -0
- package/src/terraform/project/files/application/scripts/bootstrap-destroy.ts.template +111 -0
- package/src/terraform/project/files/application/src/providers.tf.template +6 -0
- package/src/terraform/project/files/checkov/checkov.yml.template +8 -0
- package/src/terraform/project/files/library/src/main.tf.template +9 -0
- package/src/terraform/project/generator.js +47 -4
- package/src/terraform/project/generator.js.map +1 -1
- package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +1848 -614
- package/src/trpc/backend/files-operations/scripts/generate-operations.ts.template +40 -0
- package/src/trpc/backend/generator.js +10 -0
- package/src/trpc/backend/generator.js.map +1 -1
- 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/api-constructs.js +11 -0
- package/src/utils/api-constructs/api-constructs.js.map +1 -1
- package/src/utils/api-constructs/files/terraform/app/apis/http/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +251 -3
- package/src/utils/api-constructs/files/terraform/app/apis/rest/__apiNameKebabCase__/__apiNameKebabCase__.tf.template +437 -2
- package/src/utils/api-constructs/files/terraform/core/api/rest/rest-api/rest-api.tf.template +60 -7
- package/src/utils/api-constructs/open-api-metadata.d.ts +20 -3
- package/src/utils/api-constructs/open-api-metadata.js +64 -8
- package/src/utils/api-constructs/open-api-metadata.js.map +1 -1
- package/src/utils/api-constructs/trpc-operations-metadata.d.ts +21 -0
- package/src/utils/api-constructs/trpc-operations-metadata.js +55 -0
- package/src/utils/api-constructs/trpc-operations-metadata.js.map +1 -0
- 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
|
@@ -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>;
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/ import { joinPathFragments, visitNotIgnoredFiles } from "@nx/devkit";
|
|
5
|
+
import { captureAllGritQL, 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
|
+
import { TERRAFORM_VERSIONS } from "../../../utils/versions.js";
|
|
9
|
+
/**
|
|
10
|
+
* Declare every provider each vended Terraform module uses in its own
|
|
11
|
+
* `required_providers`.
|
|
12
|
+
*
|
|
13
|
+
* A provider a module uses but never declares is resolved by implicit
|
|
14
|
+
* inheritance from the root module, unpinned — so `terraform init` on that
|
|
15
|
+
* module takes whatever the registry serves, bypassing the version pinning the
|
|
16
|
+
* generators vend. Several vended modules referenced `random`, `archive`,
|
|
17
|
+
* `null`, `external` and `aws` without declaring them.
|
|
18
|
+
*
|
|
19
|
+
* These files are generated with `KeepExisting`, so an upgraded workspace keeps
|
|
20
|
+
* the unpinned shape until this runs. Each missing provider is added to the
|
|
21
|
+
* module's existing `required_providers`; a module with no `terraform` block at
|
|
22
|
+
* all is reported via `nextSteps` rather than having one inserted, since where
|
|
23
|
+
* it belongs depends on how the user has arranged the file.
|
|
24
|
+
*/ const TERRAFORM_SRC = joinPathFragments(PACKAGES_DIR, SHARED_TERRAFORM_DIR, 'src');
|
|
25
|
+
const hcl = (pattern)=>`language hcl\n${pattern}`;
|
|
26
|
+
/** Providers built in to Terraform, which have no entry and no version. */ const BUILTIN_TYPES = new Set([
|
|
27
|
+
'terraform_data',
|
|
28
|
+
'terraform_remote_state'
|
|
29
|
+
]);
|
|
30
|
+
/**
|
|
31
|
+
* The provider a resource or data source type resolves to. Terraform derives
|
|
32
|
+
* this from the type's first underscore-delimited word; a type it can't
|
|
33
|
+
* attribute to a provider the plugin vends is not this migration's to touch.
|
|
34
|
+
*/ const providerOf = (type)=>{
|
|
35
|
+
// `null_resource` and `external` are the whole type, not a prefixed one.
|
|
36
|
+
if (type === 'null_resource') {
|
|
37
|
+
return 'null';
|
|
38
|
+
}
|
|
39
|
+
if (type === 'external') {
|
|
40
|
+
return 'external';
|
|
41
|
+
}
|
|
42
|
+
const [prefix] = type.split('_');
|
|
43
|
+
return prefix in TERRAFORM_VERSIONS ? prefix : undefined;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* The providers a module requires, read from its `resource` and `data` blocks.
|
|
47
|
+
*
|
|
48
|
+
* Only declarations are read, because Terraform resolves a resource reference
|
|
49
|
+
* within the module that declares it — so a provider a module references is one
|
|
50
|
+
* it also declares a block for, and the blocks alone are complete. Matching the
|
|
51
|
+
* syntax tree also means a type named in a comment, in string prose or inside a
|
|
52
|
+
* `local-exec` heredoc's embedded Python is not a use, since none of those parse
|
|
53
|
+
* as a block.
|
|
54
|
+
*/ const usedProviders = async (tree, filePath)=>{
|
|
55
|
+
const used = new Set();
|
|
56
|
+
for (const kind of [
|
|
57
|
+
'resource',
|
|
58
|
+
'data'
|
|
59
|
+
]){
|
|
60
|
+
for (const block of (await captureAllGritQL(tree, filePath, hcl(`\`${kind} $type $name { $_ }\``)))){
|
|
61
|
+
// The block's own type, e.g. `resource "random_string" "suffix" {`.
|
|
62
|
+
const type = /"([A-Za-z0-9_]+)"/.exec(block)?.[1];
|
|
63
|
+
if (!type || BUILTIN_TYPES.has(type)) {
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
const provider = providerOf(type);
|
|
67
|
+
if (provider) {
|
|
68
|
+
used.add(provider);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return used;
|
|
73
|
+
};
|
|
74
|
+
/** Every `.tf` file in the workspace's shared terraform library, by directory. */ const terraformModules = (tree)=>{
|
|
75
|
+
const modules = new Map();
|
|
76
|
+
if (!tree.exists(TERRAFORM_SRC)) {
|
|
77
|
+
return modules;
|
|
78
|
+
}
|
|
79
|
+
visitNotIgnoredFiles(tree, TERRAFORM_SRC, (filePath)=>{
|
|
80
|
+
if (!filePath.endsWith('.tf')) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const dir = filePath.slice(0, filePath.lastIndexOf('/'));
|
|
84
|
+
modules.set(dir, [
|
|
85
|
+
...modules.get(dir) ?? [],
|
|
86
|
+
filePath
|
|
87
|
+
]);
|
|
88
|
+
});
|
|
89
|
+
return modules;
|
|
90
|
+
};
|
|
91
|
+
/** The provider entry to vend, at the version this release pins. */ const providerEntry = (provider)=>[
|
|
92
|
+
`${provider} = {`,
|
|
93
|
+
` source = "hashicorp/${provider}"`,
|
|
94
|
+
` version = "${TERRAFORM_VERSIONS[provider]}"`,
|
|
95
|
+
'}'
|
|
96
|
+
].join('\n');
|
|
97
|
+
/**
|
|
98
|
+
* Add a provider to a file's `required_providers`. Appended after the block's
|
|
99
|
+
* existing body, so an entry the user has customised is left as it is.
|
|
100
|
+
*/ const declareProvider = (tree, filePath, provider)=>insertViaGritQL(tree, filePath, hcl(`\`required_providers { $body }\` => \`required_providers {\n $body\n\n ${GRIT_INSERT_PLACEHOLDER}\n}\`` + ` where { $body <: not contains \`${provider} = { $_ }\` }`), providerEntry(provider));
|
|
101
|
+
export default async function migration(tree) {
|
|
102
|
+
const nextSteps = [];
|
|
103
|
+
for (const [dir, filePaths] of terraformModules(tree)){
|
|
104
|
+
const used = new Set();
|
|
105
|
+
// The file holding the module's `required_providers`, which is where the
|
|
106
|
+
// missing declarations are added — Terraform merges every `.tf` in a
|
|
107
|
+
// directory, so one block covers the module.
|
|
108
|
+
let blockFile;
|
|
109
|
+
const declared = new Set();
|
|
110
|
+
for (const filePath of filePaths){
|
|
111
|
+
for (const provider of (await usedProviders(tree, filePath))){
|
|
112
|
+
used.add(provider);
|
|
113
|
+
}
|
|
114
|
+
const contents = tree.read(filePath, 'utf-8') ?? '';
|
|
115
|
+
if (!contents.includes('required_providers')) {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
blockFile ??= filePath;
|
|
119
|
+
for (const provider of Object.keys(TERRAFORM_VERSIONS)){
|
|
120
|
+
if (await matchGritQL(tree, filePath, hcl(`\`required_providers { $body }\` where { $body <: contains \`${provider} = { $_ }\` }`))) {
|
|
121
|
+
declared.add(provider);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const missing = [
|
|
126
|
+
...used
|
|
127
|
+
].filter((p)=>!declared.has(p)).sort();
|
|
128
|
+
if (missing.length === 0) {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (!blockFile) {
|
|
132
|
+
nextSteps.push(`${dir}: has no terraform required_providers block - left untouched. Add one declaring ${missing.join(', ')}, so the module pins the providers it uses rather than inheriting them unpinned from the root module.`);
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
for (const provider of missing){
|
|
136
|
+
if (!await declareProvider(tree, blockFile, provider)) {
|
|
137
|
+
nextSteps.push(`${blockFile}: its required_providers block has diverged from the generated shape - left untouched. Add a ${provider} entry to it, sourced from hashicorp/${provider}.`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
await formatFilesInSubtree(tree);
|
|
142
|
+
return {
|
|
143
|
+
nextSteps
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
//# sourceMappingURL=migration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../packages/nx-plugin/src/migrations/latest/terraform-declare-used-providers/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 visitNotIgnoredFiles,\n} from '@nx/devkit';\nimport {\n captureAllGritQL,\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';\nimport { TERRAFORM_VERSIONS } from '../../../utils/versions.js';\n\n/**\n * Declare every provider each vended Terraform module uses in its own\n * `required_providers`.\n *\n * A provider a module uses but never declares is resolved by implicit\n * inheritance from the root module, unpinned — so `terraform init` on that\n * module takes whatever the registry serves, bypassing the version pinning the\n * generators vend. Several vended modules referenced `random`, `archive`,\n * `null`, `external` and `aws` without declaring them.\n *\n * These files are generated with `KeepExisting`, so an upgraded workspace keeps\n * the unpinned shape until this runs. Each missing provider is added to the\n * module's existing `required_providers`; a module with no `terraform` block at\n * all is reported via `nextSteps` rather than having one inserted, since where\n * it belongs depends on how the user has arranged the file.\n */\n\nconst TERRAFORM_SRC = joinPathFragments(\n PACKAGES_DIR,\n SHARED_TERRAFORM_DIR,\n 'src',\n);\n\nconst hcl = (pattern: string) => `language hcl\\n${pattern}`;\n\n/** Providers built in to Terraform, which have no entry and no version. */\nconst BUILTIN_TYPES = new Set(['terraform_data', 'terraform_remote_state']);\n\n/**\n * The provider a resource or data source type resolves to. Terraform derives\n * this from the type's first underscore-delimited word; a type it can't\n * attribute to a provider the plugin vends is not this migration's to touch.\n */\nconst providerOf = (type: string): string | undefined => {\n // `null_resource` and `external` are the whole type, not a prefixed one.\n if (type === 'null_resource') {\n return 'null';\n }\n if (type === 'external') {\n return 'external';\n }\n const [prefix] = type.split('_');\n return prefix in TERRAFORM_VERSIONS ? prefix : undefined;\n};\n\n/**\n * The providers a module requires, read from its `resource` and `data` blocks.\n *\n * Only declarations are read, because Terraform resolves a resource reference\n * within the module that declares it — so a provider a module references is one\n * it also declares a block for, and the blocks alone are complete. Matching the\n * syntax tree also means a type named in a comment, in string prose or inside a\n * `local-exec` heredoc's embedded Python is not a use, since none of those parse\n * as a block.\n */\nconst usedProviders = async (\n tree: Tree,\n filePath: string,\n): Promise<Set<string>> => {\n const used = new Set<string>();\n for (const kind of ['resource', 'data']) {\n for (const block of await captureAllGritQL(\n tree,\n filePath,\n hcl(`\\`${kind} $type $name { $_ }\\``),\n )) {\n // The block's own type, e.g. `resource \"random_string\" \"suffix\" {`.\n const type = /\"([A-Za-z0-9_]+)\"/.exec(block)?.[1];\n if (!type || BUILTIN_TYPES.has(type)) {\n continue;\n }\n const provider = providerOf(type);\n if (provider) {\n used.add(provider);\n }\n }\n }\n return used;\n};\n\n/** Every `.tf` file in the workspace's shared terraform library, by directory. */\nconst terraformModules = (tree: Tree): Map<string, string[]> => {\n const modules = new Map<string, string[]>();\n if (!tree.exists(TERRAFORM_SRC)) {\n return modules;\n }\n visitNotIgnoredFiles(tree, TERRAFORM_SRC, (filePath) => {\n if (!filePath.endsWith('.tf')) {\n return;\n }\n const dir = filePath.slice(0, filePath.lastIndexOf('/'));\n modules.set(dir, [...(modules.get(dir) ?? []), filePath]);\n });\n return modules;\n};\n\n/** The provider entry to vend, at the version this release pins. */\nconst providerEntry = (provider: string) =>\n [\n `${provider} = {`,\n ` source = \"hashicorp/${provider}\"`,\n ` version = \"${TERRAFORM_VERSIONS[provider as keyof typeof TERRAFORM_VERSIONS]}\"`,\n '}',\n ].join('\\n');\n\n/**\n * Add a provider to a file's `required_providers`. Appended after the block's\n * existing body, so an entry the user has customised is left as it is.\n */\nconst declareProvider = (tree: Tree, filePath: string, provider: string) =>\n insertViaGritQL(\n tree,\n filePath,\n hcl(\n `\\`required_providers { $body }\\` => \\`required_providers {\\n $body\\n\\n ${GRIT_INSERT_PLACEHOLDER}\\n}\\`` +\n ` where { $body <: not contains \\`${provider} = { $_ }\\` }`,\n ),\n providerEntry(provider),\n );\n\nexport default async function migration(\n tree: Tree,\n): Promise<MigrationReturnObject> {\n const nextSteps: string[] = [];\n\n for (const [dir, filePaths] of terraformModules(tree)) {\n const used = new Set<string>();\n // The file holding the module's `required_providers`, which is where the\n // missing declarations are added — Terraform merges every `.tf` in a\n // directory, so one block covers the module.\n let blockFile: string | undefined;\n const declared = new Set<string>();\n\n for (const filePath of filePaths) {\n for (const provider of await usedProviders(tree, filePath)) {\n used.add(provider);\n }\n const contents = tree.read(filePath, 'utf-8') ?? '';\n if (!contents.includes('required_providers')) {\n continue;\n }\n blockFile ??= filePath;\n for (const provider of Object.keys(TERRAFORM_VERSIONS)) {\n if (\n await matchGritQL(\n tree,\n filePath,\n hcl(\n `\\`required_providers { $body }\\` where { $body <: contains \\`${provider} = { $_ }\\` }`,\n ),\n )\n ) {\n declared.add(provider);\n }\n }\n }\n\n const missing = [...used].filter((p) => !declared.has(p)).sort();\n if (missing.length === 0) {\n continue;\n }\n\n if (!blockFile) {\n nextSteps.push(\n `${dir}: has no terraform required_providers block - left untouched. Add one declaring ${missing.join(', ')}, so the module pins the providers it uses rather than inheriting them unpinned from the root module.`,\n );\n continue;\n }\n\n for (const provider of missing) {\n if (!(await declareProvider(tree, blockFile, provider))) {\n nextSteps.push(\n `${blockFile}: its required_providers block has diverged from the generated shape - left untouched. Add a ${provider} entry to it, sourced from hashicorp/${provider}.`,\n );\n }\n }\n }\n\n await formatFilesInSubtree(tree);\n\n return { nextSteps };\n}\n"],"names":["joinPathFragments","visitNotIgnoredFiles","captureAllGritQL","GRIT_INSERT_PLACEHOLDER","insertViaGritQL","matchGritQL","formatFilesInSubtree","PACKAGES_DIR","SHARED_TERRAFORM_DIR","TERRAFORM_VERSIONS","TERRAFORM_SRC","hcl","pattern","BUILTIN_TYPES","Set","providerOf","type","prefix","split","undefined","usedProviders","tree","filePath","used","kind","block","exec","has","provider","add","terraformModules","modules","Map","exists","endsWith","dir","slice","lastIndexOf","set","get","providerEntry","join","declareProvider","migration","nextSteps","filePaths","blockFile","declared","contents","read","includes","Object","keys","missing","filter","p","sort","length","push"],"mappings":"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"}
|