@aws/nx-plugin 1.0.0-rc.26 → 1.0.0-rc.28
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/package.json +1 -1
- package/src/preset/generator.js +1 -1
- package/src/preset/generator.js.map +1 -1
- package/src/ts/rdb/__snapshots__/generator.spec.ts.snap +38 -76
- package/src/ts/rdb/files/src/create-db-user-handler.ts.template +7 -9
- package/src/ts/rdb/files/src/migration-handler.ts.template +1 -28
- package/src/ts/rdb/generator.js +2 -2
- package/src/ts/rdb/generator.js.map +1 -1
- package/src/ts/react-website/app/__snapshots__/generator.spec.ts.snap +4 -0
- package/src/utils/agent-core-constructs/files/cdk/app/agentcore-gateway/__nameKebabCase__/__nameKebabCase__.ts.template +12 -2
- package/src/utils/agent-core-constructs/files/cdk/core/agentcore-gateway/agentcore-gateway.ts.template +112 -0
- package/src/utils/agent-core-constructs/files/terraform/app/agentcore-gateway/__nameKebabCase__/__nameKebabCase__.tf.template +115 -1
- package/src/utils/files/common/scripts/src/rdb/shared/start-container.ts.template +2 -2
- package/src/utils/rdb-constructs/files/cdk/core/rdb/aurora.ts.template +5 -15
- package/src/utils/rdb-constructs/files/terraform/app/dbs/__nameKebabCase__/__nameKebabCase__.tf.template +0 -28
- package/src/utils/website-constructs/files/cdk/core/static-website.ts.template +1 -0
- package/src/utils/website-constructs/files/terraform/core/static-website/static-website.tf.template +1 -0
package/package.json
CHANGED
package/src/preset/generator.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*/ import { addDependenciesToPackageJson, detectPackageManager, generateFiles, joinPathFragments, OverwriteStrategy, readNxJson, updateJson, updateNxJson } from "@nx/devkit";
|
|
5
5
|
import { initGenerator } from "@nx/js";
|
|
6
6
|
import { execSync } from "child_process";
|
|
7
|
-
import
|
|
7
|
+
import enquirer from "enquirer";
|
|
8
8
|
import { readFileSync } from "fs";
|
|
9
9
|
import yaml from "js-yaml";
|
|
10
10
|
import { readModulePackageJson } from "nx/src/utils/package-json";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../packages/nx-plugin/src/preset/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n addDependenciesToPackageJson,\n detectPackageManager,\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n readNxJson,\n type Tree,\n updateJson,\n updateNxJson,\n} from '@nx/devkit';\nimport { initGenerator } from '@nx/js';\nimport { execSync } from 'child_process';\nimport * as enquirer from 'enquirer';\nimport { readFileSync } from 'fs';\nimport yaml from 'js-yaml';\nimport { readModulePackageJson } from 'nx/src/utils/package-json';\nimport GeneratorsJson from '../../generators.json' with { type: 'json' };\nimport { SYNC_GENERATOR_NAME as TS_SYNC_GENERATOR_NAME } from '../ts/sync/generator';\nimport {\n ensureAwsNxPluginConfig,\n updateAwsNxPluginConfig,\n} from '../utils/config/utils';\nimport { inferContainers } from '../utils/containers';\nimport { DEFAULT_BIOME_CONFIG, formatFilesInSubtree } from '../utils/format';\nimport { installDependencies } from '../utils/install';\nimport { configureMcpServers } from '../utils/mcp';\nimport { addGeneratorMetricsIfApplicable } from '../utils/metrics';\nimport { getNpmScope } from '../utils/npm-scope';\nimport { getGeneratorInfo, type NxGeneratorInfo } from '../utils/nx';\nimport { getPackageManagerDisplayCommands } from '../utils/pkg-manager';\nimport { withVersions } from '../utils/versions';\nimport type { PresetGeneratorSchema } from './schema';\n\nconst WORKSPACES = ['packages/*'];\nconst NX_TYPESCRIPT_SYNC_GENERATOR = '@nx/js:typescript-sync';\n\n// Built dependencies whose install scripts the generated workspace trusts.\n// `onlyBuiltDependencies` is the pnpm 10 key (silently ignored by pnpm 11);\n// pnpm 11 reads `allowBuilds` instead. Any dep NOT in this allowlist will\n// have its install scripts skipped with a warning — matching pnpm 10's\n// default behaviour. The user can opt-in later via `pnpm approve-builds`.\nconst PNPM_BUILT_DEPENDENCIES = ['@swc/core', 'esbuild', 'nx', 'sharp'];\n\nexport const PRESET_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\nconst setUpWorkspaces = (tree: Tree) => {\n if (detectPackageManager() === 'pnpm') {\n tree.write(\n 'pnpm-workspace.yaml',\n yaml.dump(\n {\n packages: WORKSPACES,\n allowBuilds: Object.fromEntries(\n PNPM_BUILT_DEPENDENCIES.map((dep) => [dep, true]),\n ),\n onlyBuiltDependencies: PNPM_BUILT_DEPENDENCIES,\n },\n { quotingType: \"'\" },\n ),\n );\n } else {\n updateJson(tree, 'package.json', (json) => {\n json.workspaces = WORKSPACES;\n return json;\n });\n }\n};\n\n/**\n * Determines if the current user is an Amazon employee based on their git configuration.\n *\n * This function checks the git user email configuration to identify Amazon employees\n * by looking for email addresses with Amazon domains (e.g., @amazon.com, @amazon.co.uk).\n *\n * @returns {boolean} True if the user's git email has an Amazon domain, false otherwise\n *\n * @example\n * // Returns true for Amazon employee emails\n * // git config user.email = \"john.doe@amazon.com\"\n * isAmazonian(); // true\n *\n * @example\n * // Returns false for non-Amazon emails\n * // git config user.email = \"user@example.com\"\n * isAmazonian(); // false\n *\n * @example\n * // Returns false when git config is not available or throws an error\n * isAmazonian(); // false\n */\nexport function isAmazonian(): boolean {\n try {\n // Execute git command to retrieve the user's configured email address\n const gitEmail = execSync('git config user.email', {\n encoding: 'utf8',\n }).trim();\n\n // Return false if no email is configured\n if (!gitEmail) {\n return false;\n }\n\n // Split email address to extract domain part\n const emailParts = gitEmail.split('@');\n if (emailParts.length < 2) {\n return false;\n }\n\n // Extract domain and normalize to lowercase for comparison\n const domain = emailParts[1].toLowerCase();\n\n // Check if domain starts with 'amazon.' (covers amazon.com, amazon.co.uk, etc.)\n return domain.startsWith('amazon.');\n } catch (error) {\n // Return false if git command fails or any other error occurs\n // This handles cases where git is not installed or configured\n return false;\n }\n}\n\nconst setUpGitSecrets = (tree: Tree) => {\n const gitSecretsDir = joinPathFragments(\n import.meta.dirname,\n 'git-secrets-files',\n 'git-secrets-dir',\n );\n const huskyDir = joinPathFragments(\n import.meta.dirname,\n 'git-secrets-files',\n 'husky-dir',\n );\n\n tree.write(\n '.git-secrets/git-secrets',\n readFileSync(joinPathFragments(gitSecretsDir, 'git-secrets'), 'utf-8'),\n );\n tree.write(\n '.husky/pre-commit',\n readFileSync(joinPathFragments(huskyDir, 'pre-commit'), 'utf-8'),\n );\n tree.write('.gitallowed', '\\\\.git-secrets/git-secrets:\\n');\n\n updateJson(tree, 'package.json', (json) => ({\n ...json,\n scripts: {\n ...json.scripts,\n prepare: 'husky',\n },\n }));\n\n addDependenciesToPackageJson(tree, {}, withVersions(['husky']));\n};\n\nexport const presetGenerator = async (\n tree: Tree,\n {\n iac,\n gitSecrets,\n mcp,\n containers,\n preferInstallDependencies,\n }: PresetGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const resolvedContainers =\n !containers || containers === 'infer' ? inferContainers() : containers;\n if (\n isAmazonian() &&\n !process.env.VITEST &&\n !process.env.CI &&\n process.env.NX_DRY_RUN !== 'true' &&\n process.env.NX_INTERACTIVE !== 'false'\n ) {\n const { engagementId } = await enquirer.prompt<{ engagementId?: string }>([\n {\n name: 'engagementId',\n message: 'Please enter your engagementId (if known)',\n type: 'input',\n initial: 'None',\n },\n ]);\n\n if (engagementId != 'None') {\n await ensureAwsNxPluginConfig(tree);\n await updateAwsNxPluginConfig(tree, { tags: [engagementId] });\n }\n }\n\n // Write IaC provider and container engine to plugin config\n await ensureAwsNxPluginConfig(tree);\n await updateAwsNxPluginConfig(tree, {\n iac: { provider: iac },\n containers: { engine: resolvedContainers },\n });\n\n await initGenerator(tree, {\n formatter: 'none',\n addTsPlugin: true,\n });\n\n tree.delete('apps/.gitkeep');\n tree.delete('libs/.gitkeep');\n tree.write('packages/.gitkeep', '');\n\n setUpWorkspaces(tree);\n\n const nxJson = readNxJson(tree);\n updateNxJson(tree, {\n ...nxJson,\n analytics: false,\n targetDefaults: {\n ...nxJson.targetDefaults,\n compile: {\n ...nxJson.targetDefaults?.compile,\n syncGenerators: [\n ...(nxJson.targetDefaults?.compile?.syncGenerators ?? []).filter(\n (g) =>\n ![TS_SYNC_GENERATOR_NAME, NX_TYPESCRIPT_SYNC_GENERATOR].includes(\n g,\n ),\n ),\n NX_TYPESCRIPT_SYNC_GENERATOR,\n TS_SYNC_GENERATOR_NAME,\n ],\n },\n },\n });\n\n updateJson(tree, 'package.json', (packageJson) => ({\n ...packageJson,\n type: 'module',\n scripts: {\n ...packageJson.scripts,\n dev: 'nx run-many --target dev',\n build: 'nx run-many --target build',\n lint: 'nx run-many --target lint --configuration=fix',\n test: 'nx run-many --target test --all',\n 'build:skip-lint': 'nx run-many --target build --configuration=skip-lint',\n 'build:all': 'nx run-many --target build --all',\n 'affected:all': 'nx affected --target build',\n },\n }));\n\n addDependenciesToPackageJson(\n tree,\n {},\n {\n '@nx/workspace': readModulePackageJson('@nx/js').packageJson.version,\n ...withVersions(['typescript', '@biomejs/biome']),\n },\n );\n\n // Write biome.json for formatting and linting\n if (!tree.exists('biome.json')) {\n tree.write('biome.json', JSON.stringify(DEFAULT_BIOME_CONFIG, null, 2));\n }\n\n generateFiles(\n tree, // the virtual file system\n joinPathFragments(import.meta.dirname, 'files'),\n '.',\n {\n projectName: getNpmScope(tree),\n generators: Object.entries(GeneratorsJson.generators)\n .filter(([_, v]) => !v['hidden'])\n .map(([k, v]) => ({ name: k, description: v.description })),\n ...(() => {\n const cmds = getPackageManagerDisplayCommands();\n return {\n pkgMgrCmd: cmds.exec,\n buildCmd: `${cmds.run} build`,\n lintCmd: `${cmds.run} lint`,\n };\n })(),\n },\n {\n overwriteStrategy: OverwriteStrategy.Overwrite,\n },\n );\n\n if (gitSecrets !== false) {\n setUpGitSecrets(tree);\n }\n\n if (mcp !== false) {\n configureMcpServers(tree);\n }\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, preferInstallDependencies, {\n languages: ['typescript'],\n });\n};\n\nexport default presetGenerator;\n"],"names":["addDependenciesToPackageJson","detectPackageManager","generateFiles","joinPathFragments","OverwriteStrategy","readNxJson","updateJson","updateNxJson","initGenerator","execSync","enquirer","readFileSync","yaml","readModulePackageJson","GeneratorsJson","type","SYNC_GENERATOR_NAME","TS_SYNC_GENERATOR_NAME","ensureAwsNxPluginConfig","updateAwsNxPluginConfig","inferContainers","DEFAULT_BIOME_CONFIG","formatFilesInSubtree","installDependencies","configureMcpServers","getNpmScope","getGeneratorInfo","getPackageManagerDisplayCommands","withVersions","WORKSPACES","NX_TYPESCRIPT_SYNC_GENERATOR","PNPM_BUILT_DEPENDENCIES","PRESET_GENERATOR_INFO","filename","setUpWorkspaces","tree","write","dump","packages","allowBuilds","Object","fromEntries","map","dep","onlyBuiltDependencies","quotingType","json","workspaces","isAmazonian","gitEmail","encoding","trim","emailParts","split","length","domain","toLowerCase","startsWith","error","setUpGitSecrets","gitSecretsDir","dirname","huskyDir","scripts","prepare","presetGenerator","iac","gitSecrets","mcp","containers","preferInstallDependencies","resolvedContainers","process","env","VITEST","CI","NX_DRY_RUN","NX_INTERACTIVE","engagementId","prompt","name","message","initial","tags","provider","engine","formatter","addTsPlugin","delete","nxJson","analytics","targetDefaults","compile","syncGenerators","filter","g","includes","packageJson","dev","build","lint","test","version","exists","JSON","stringify","projectName","generators","entries","_","v","k","description","cmds","pkgMgrCmd","exec","buildCmd","run","lintCmd","overwriteStrategy","Overwrite","languages"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../packages/nx-plugin/src/preset/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport {\n addDependenciesToPackageJson,\n detectPackageManager,\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n OverwriteStrategy,\n readNxJson,\n type Tree,\n updateJson,\n updateNxJson,\n} from '@nx/devkit';\nimport { initGenerator } from '@nx/js';\nimport { execSync } from 'child_process';\nimport enquirer from 'enquirer';\nimport { readFileSync } from 'fs';\nimport yaml from 'js-yaml';\nimport { readModulePackageJson } from 'nx/src/utils/package-json';\nimport GeneratorsJson from '../../generators.json' with { type: 'json' };\nimport { SYNC_GENERATOR_NAME as TS_SYNC_GENERATOR_NAME } from '../ts/sync/generator';\nimport {\n ensureAwsNxPluginConfig,\n updateAwsNxPluginConfig,\n} from '../utils/config/utils';\nimport { inferContainers } from '../utils/containers';\nimport { DEFAULT_BIOME_CONFIG, formatFilesInSubtree } from '../utils/format';\nimport { installDependencies } from '../utils/install';\nimport { configureMcpServers } from '../utils/mcp';\nimport { addGeneratorMetricsIfApplicable } from '../utils/metrics';\nimport { getNpmScope } from '../utils/npm-scope';\nimport { getGeneratorInfo, type NxGeneratorInfo } from '../utils/nx';\nimport { getPackageManagerDisplayCommands } from '../utils/pkg-manager';\nimport { withVersions } from '../utils/versions';\nimport type { PresetGeneratorSchema } from './schema';\n\nconst WORKSPACES = ['packages/*'];\nconst NX_TYPESCRIPT_SYNC_GENERATOR = '@nx/js:typescript-sync';\n\n// Built dependencies whose install scripts the generated workspace trusts.\n// `onlyBuiltDependencies` is the pnpm 10 key (silently ignored by pnpm 11);\n// pnpm 11 reads `allowBuilds` instead. Any dep NOT in this allowlist will\n// have its install scripts skipped with a warning — matching pnpm 10's\n// default behaviour. The user can opt-in later via `pnpm approve-builds`.\nconst PNPM_BUILT_DEPENDENCIES = ['@swc/core', 'esbuild', 'nx', 'sharp'];\n\nexport const PRESET_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\nconst setUpWorkspaces = (tree: Tree) => {\n if (detectPackageManager() === 'pnpm') {\n tree.write(\n 'pnpm-workspace.yaml',\n yaml.dump(\n {\n packages: WORKSPACES,\n allowBuilds: Object.fromEntries(\n PNPM_BUILT_DEPENDENCIES.map((dep) => [dep, true]),\n ),\n onlyBuiltDependencies: PNPM_BUILT_DEPENDENCIES,\n },\n { quotingType: \"'\" },\n ),\n );\n } else {\n updateJson(tree, 'package.json', (json) => {\n json.workspaces = WORKSPACES;\n return json;\n });\n }\n};\n\n/**\n * Determines if the current user is an Amazon employee based on their git configuration.\n *\n * This function checks the git user email configuration to identify Amazon employees\n * by looking for email addresses with Amazon domains (e.g., @amazon.com, @amazon.co.uk).\n *\n * @returns {boolean} True if the user's git email has an Amazon domain, false otherwise\n *\n * @example\n * // Returns true for Amazon employee emails\n * // git config user.email = \"john.doe@amazon.com\"\n * isAmazonian(); // true\n *\n * @example\n * // Returns false for non-Amazon emails\n * // git config user.email = \"user@example.com\"\n * isAmazonian(); // false\n *\n * @example\n * // Returns false when git config is not available or throws an error\n * isAmazonian(); // false\n */\nexport function isAmazonian(): boolean {\n try {\n // Execute git command to retrieve the user's configured email address\n const gitEmail = execSync('git config user.email', {\n encoding: 'utf8',\n }).trim();\n\n // Return false if no email is configured\n if (!gitEmail) {\n return false;\n }\n\n // Split email address to extract domain part\n const emailParts = gitEmail.split('@');\n if (emailParts.length < 2) {\n return false;\n }\n\n // Extract domain and normalize to lowercase for comparison\n const domain = emailParts[1].toLowerCase();\n\n // Check if domain starts with 'amazon.' (covers amazon.com, amazon.co.uk, etc.)\n return domain.startsWith('amazon.');\n } catch (error) {\n // Return false if git command fails or any other error occurs\n // This handles cases where git is not installed or configured\n return false;\n }\n}\n\nconst setUpGitSecrets = (tree: Tree) => {\n const gitSecretsDir = joinPathFragments(\n import.meta.dirname,\n 'git-secrets-files',\n 'git-secrets-dir',\n );\n const huskyDir = joinPathFragments(\n import.meta.dirname,\n 'git-secrets-files',\n 'husky-dir',\n );\n\n tree.write(\n '.git-secrets/git-secrets',\n readFileSync(joinPathFragments(gitSecretsDir, 'git-secrets'), 'utf-8'),\n );\n tree.write(\n '.husky/pre-commit',\n readFileSync(joinPathFragments(huskyDir, 'pre-commit'), 'utf-8'),\n );\n tree.write('.gitallowed', '\\\\.git-secrets/git-secrets:\\n');\n\n updateJson(tree, 'package.json', (json) => ({\n ...json,\n scripts: {\n ...json.scripts,\n prepare: 'husky',\n },\n }));\n\n addDependenciesToPackageJson(tree, {}, withVersions(['husky']));\n};\n\nexport const presetGenerator = async (\n tree: Tree,\n {\n iac,\n gitSecrets,\n mcp,\n containers,\n preferInstallDependencies,\n }: PresetGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const resolvedContainers =\n !containers || containers === 'infer' ? inferContainers() : containers;\n if (\n isAmazonian() &&\n !process.env.VITEST &&\n !process.env.CI &&\n process.env.NX_DRY_RUN !== 'true' &&\n process.env.NX_INTERACTIVE !== 'false'\n ) {\n const { engagementId } = await enquirer.prompt<{ engagementId?: string }>([\n {\n name: 'engagementId',\n message: 'Please enter your engagementId (if known)',\n type: 'input',\n initial: 'None',\n },\n ]);\n\n if (engagementId != 'None') {\n await ensureAwsNxPluginConfig(tree);\n await updateAwsNxPluginConfig(tree, { tags: [engagementId] });\n }\n }\n\n // Write IaC provider and container engine to plugin config\n await ensureAwsNxPluginConfig(tree);\n await updateAwsNxPluginConfig(tree, {\n iac: { provider: iac },\n containers: { engine: resolvedContainers },\n });\n\n await initGenerator(tree, {\n formatter: 'none',\n addTsPlugin: true,\n });\n\n tree.delete('apps/.gitkeep');\n tree.delete('libs/.gitkeep');\n tree.write('packages/.gitkeep', '');\n\n setUpWorkspaces(tree);\n\n const nxJson = readNxJson(tree);\n updateNxJson(tree, {\n ...nxJson,\n analytics: false,\n targetDefaults: {\n ...nxJson.targetDefaults,\n compile: {\n ...nxJson.targetDefaults?.compile,\n syncGenerators: [\n ...(nxJson.targetDefaults?.compile?.syncGenerators ?? []).filter(\n (g) =>\n ![TS_SYNC_GENERATOR_NAME, NX_TYPESCRIPT_SYNC_GENERATOR].includes(\n g,\n ),\n ),\n NX_TYPESCRIPT_SYNC_GENERATOR,\n TS_SYNC_GENERATOR_NAME,\n ],\n },\n },\n });\n\n updateJson(tree, 'package.json', (packageJson) => ({\n ...packageJson,\n type: 'module',\n scripts: {\n ...packageJson.scripts,\n dev: 'nx run-many --target dev',\n build: 'nx run-many --target build',\n lint: 'nx run-many --target lint --configuration=fix',\n test: 'nx run-many --target test --all',\n 'build:skip-lint': 'nx run-many --target build --configuration=skip-lint',\n 'build:all': 'nx run-many --target build --all',\n 'affected:all': 'nx affected --target build',\n },\n }));\n\n addDependenciesToPackageJson(\n tree,\n {},\n {\n '@nx/workspace': readModulePackageJson('@nx/js').packageJson.version,\n ...withVersions(['typescript', '@biomejs/biome']),\n },\n );\n\n // Write biome.json for formatting and linting\n if (!tree.exists('biome.json')) {\n tree.write('biome.json', JSON.stringify(DEFAULT_BIOME_CONFIG, null, 2));\n }\n\n generateFiles(\n tree, // the virtual file system\n joinPathFragments(import.meta.dirname, 'files'),\n '.',\n {\n projectName: getNpmScope(tree),\n generators: Object.entries(GeneratorsJson.generators)\n .filter(([_, v]) => !v['hidden'])\n .map(([k, v]) => ({ name: k, description: v.description })),\n ...(() => {\n const cmds = getPackageManagerDisplayCommands();\n return {\n pkgMgrCmd: cmds.exec,\n buildCmd: `${cmds.run} build`,\n lintCmd: `${cmds.run} lint`,\n };\n })(),\n },\n {\n overwriteStrategy: OverwriteStrategy.Overwrite,\n },\n );\n\n if (gitSecrets !== false) {\n setUpGitSecrets(tree);\n }\n\n if (mcp !== false) {\n configureMcpServers(tree);\n }\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, preferInstallDependencies, {\n languages: ['typescript'],\n });\n};\n\nexport default presetGenerator;\n"],"names":["addDependenciesToPackageJson","detectPackageManager","generateFiles","joinPathFragments","OverwriteStrategy","readNxJson","updateJson","updateNxJson","initGenerator","execSync","enquirer","readFileSync","yaml","readModulePackageJson","GeneratorsJson","type","SYNC_GENERATOR_NAME","TS_SYNC_GENERATOR_NAME","ensureAwsNxPluginConfig","updateAwsNxPluginConfig","inferContainers","DEFAULT_BIOME_CONFIG","formatFilesInSubtree","installDependencies","configureMcpServers","getNpmScope","getGeneratorInfo","getPackageManagerDisplayCommands","withVersions","WORKSPACES","NX_TYPESCRIPT_SYNC_GENERATOR","PNPM_BUILT_DEPENDENCIES","PRESET_GENERATOR_INFO","filename","setUpWorkspaces","tree","write","dump","packages","allowBuilds","Object","fromEntries","map","dep","onlyBuiltDependencies","quotingType","json","workspaces","isAmazonian","gitEmail","encoding","trim","emailParts","split","length","domain","toLowerCase","startsWith","error","setUpGitSecrets","gitSecretsDir","dirname","huskyDir","scripts","prepare","presetGenerator","iac","gitSecrets","mcp","containers","preferInstallDependencies","resolvedContainers","process","env","VITEST","CI","NX_DRY_RUN","NX_INTERACTIVE","engagementId","prompt","name","message","initial","tags","provider","engine","formatter","addTsPlugin","delete","nxJson","analytics","targetDefaults","compile","syncGenerators","filter","g","includes","packageJson","dev","build","lint","test","version","exists","JSON","stringify","projectName","generators","entries","_","v","k","description","cmds","pkgMgrCmd","exec","buildCmd","run","lintCmd","overwriteStrategy","Overwrite","languages"],"mappings":"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"}
|
|
@@ -68,7 +68,7 @@ const ensureDatabaseUser = async (dbUser: string): Promise<void> => {
|
|
|
68
68
|
[
|
|
69
69
|
\`CREATE USER IF NOT EXISTS \${quotedUser}@\${quotedHost} IDENTIFIED WITH AWSAuthenticationPlugin AS 'RDS'\`,
|
|
70
70
|
\`ALTER USER \${quotedUser}@\${quotedHost} IDENTIFIED WITH AWSAuthenticationPlugin AS 'RDS' REQUIRE SSL\`,
|
|
71
|
-
\`GRANT
|
|
71
|
+
\`GRANT SELECT, INSERT, UPDATE, DELETE ON \${quotedDbName}.* TO \${quotedUser}@\${quotedHost}\`,
|
|
72
72
|
].join(';\\n'),
|
|
73
73
|
);
|
|
74
74
|
} finally {
|
|
@@ -706,32 +706,19 @@ export abstract class AuroraDatabase extends Construct {
|
|
|
706
706
|
timeout: Duration.minutes(5),
|
|
707
707
|
tracing: Tracing.ACTIVE,
|
|
708
708
|
vpc,
|
|
709
|
-
environment:
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
DATABASE_SECRET_ARN: this.cluster.secret!.secretArn,
|
|
713
|
-
}
|
|
714
|
-
: {
|
|
715
|
-
HOSTNAME: databaseHostname,
|
|
716
|
-
DATABASE: databaseName,
|
|
717
|
-
PORT: databasePort.toString(),
|
|
718
|
-
DBUSER: this.dbUser,
|
|
719
|
-
},
|
|
709
|
+
environment: {
|
|
710
|
+
DATABASE_SECRET_ARN: this.cluster.secret!.secretArn,
|
|
711
|
+
},
|
|
720
712
|
architecture: Architecture.ARM_64,
|
|
721
713
|
});
|
|
722
714
|
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
this.grantSecretRead(migrationHandler);
|
|
726
|
-
} else {
|
|
727
|
-
this.allowDefaultPortFrom(migrationHandler);
|
|
728
|
-
this.grantConnect(migrationHandler);
|
|
729
|
-
}
|
|
715
|
+
this.cluster.connections.allowDefaultPortFrom(migrationHandler);
|
|
716
|
+
this.grantSecretRead(migrationHandler);
|
|
730
717
|
|
|
731
|
-
const
|
|
718
|
+
const migrationTrigger = new Trigger(this, 'MigrationTrigger', {
|
|
732
719
|
handler: migrationHandler,
|
|
733
720
|
});
|
|
734
|
-
|
|
721
|
+
migrationTrigger.node.addDependency(createDbUserResource);
|
|
735
722
|
|
|
736
723
|
new CfnOutput(this, 'ClusterEndpoint', {
|
|
737
724
|
value: this.cluster.clusterEndpoint.hostname,
|
|
@@ -1909,11 +1896,16 @@ resource "aws_iam_role_policy" "migration_handler_access" {
|
|
|
1909
1896
|
{
|
|
1910
1897
|
Effect = "Allow"
|
|
1911
1898
|
Action = [
|
|
1912
|
-
"
|
|
1899
|
+
"secretsmanager:GetSecretValue"
|
|
1913
1900
|
]
|
|
1914
|
-
Resource = [
|
|
1915
|
-
|
|
1901
|
+
Resource = [module.aurora.secret_arn]
|
|
1902
|
+
},
|
|
1903
|
+
{
|
|
1904
|
+
Effect = "Allow"
|
|
1905
|
+
Action = [
|
|
1906
|
+
"kms:Decrypt"
|
|
1916
1907
|
]
|
|
1908
|
+
Resource = [module.aurora.kms_key_arn]
|
|
1917
1909
|
}
|
|
1918
1910
|
]
|
|
1919
1911
|
})
|
|
@@ -2002,7 +1994,7 @@ resource "aws_security_group" "migration_handler" {
|
|
|
2002
1994
|
|
|
2003
1995
|
resource "aws_vpc_security_group_egress_rule" "migration_handler_to_database" {
|
|
2004
1996
|
security_group_id = aws_security_group.migration_handler.id
|
|
2005
|
-
referenced_security_group_id = module.aurora.
|
|
1997
|
+
referenced_security_group_id = module.aurora.database_security_group_id
|
|
2006
1998
|
from_port = module.aurora.cluster_port
|
|
2007
1999
|
to_port = module.aurora.cluster_port
|
|
2008
2000
|
ip_protocol = "tcp"
|
|
@@ -2044,7 +2036,7 @@ resource "aws_vpc_security_group_egress_rule" "create_db_user_https" {
|
|
|
2044
2036
|
}
|
|
2045
2037
|
|
|
2046
2038
|
resource "aws_vpc_security_group_ingress_rule" "migration_handler_to_database" {
|
|
2047
|
-
security_group_id = module.aurora.
|
|
2039
|
+
security_group_id = module.aurora.database_security_group_id
|
|
2048
2040
|
referenced_security_group_id = aws_security_group.migration_handler.id
|
|
2049
2041
|
from_port = module.aurora.cluster_port
|
|
2050
2042
|
to_port = module.aurora.cluster_port
|
|
@@ -2165,10 +2157,7 @@ resource "aws_lambda_function" "migration_handler" {
|
|
|
2165
2157
|
|
|
2166
2158
|
environment {
|
|
2167
2159
|
variables = {
|
|
2168
|
-
|
|
2169
|
-
DATABASE = module.aurora.database_name
|
|
2170
|
-
PORT = tostring(module.aurora.cluster_port)
|
|
2171
|
-
DBUSER = local.database_runtime_user
|
|
2160
|
+
DATABASE_SECRET_ARN = module.aurora.secret_arn
|
|
2172
2161
|
}
|
|
2173
2162
|
}
|
|
2174
2163
|
|
|
@@ -3841,14 +3830,12 @@ const ensureDatabaseUser = async (dbUser: string): Promise<void> => {
|
|
|
3841
3830
|
|
|
3842
3831
|
await client.query(
|
|
3843
3832
|
\`ALTER ROLE \${quotedDbUser} WITH LOGIN;
|
|
3844
|
-
GRANT
|
|
3845
|
-
GRANT USAGE
|
|
3846
|
-
GRANT
|
|
3847
|
-
GRANT
|
|
3848
|
-
|
|
3849
|
-
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT
|
|
3850
|
-
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON SEQUENCES TO \${quotedDbUser};
|
|
3851
|
-
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON FUNCTIONS TO \${quotedDbUser};
|
|
3833
|
+
GRANT CONNECT ON DATABASE \${quotedDbName} TO \${quotedDbUser};
|
|
3834
|
+
GRANT USAGE ON SCHEMA public TO \${quotedDbUser};
|
|
3835
|
+
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO \${quotedDbUser};
|
|
3836
|
+
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO \${quotedDbUser};
|
|
3837
|
+
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO \${quotedDbUser};
|
|
3838
|
+
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT USAGE, SELECT ON SEQUENCES TO \${quotedDbUser};
|
|
3852
3839
|
GRANT rds_iam TO \${quotedDbUser};\`,
|
|
3853
3840
|
);
|
|
3854
3841
|
|
|
@@ -3890,28 +3877,16 @@ exports[`ts#rdb generator > should generate the aurora shared construct > packag
|
|
|
3890
3877
|
exports[`ts#rdb generator > should generate the aurora shared construct > packages/db/src/migration-handler.ts 1`] = `
|
|
3891
3878
|
"import { execFile } from 'node:child_process';
|
|
3892
3879
|
import { promisify } from 'node:util';
|
|
3893
|
-
import {
|
|
3894
|
-
import { withConnectionRetry } from './utils.js';
|
|
3880
|
+
import { getDatabaseSecret, withConnectionRetry } from './utils.js';
|
|
3895
3881
|
|
|
3896
3882
|
const buildDatabaseUrl = async (): Promise<string> => {
|
|
3897
|
-
const
|
|
3898
|
-
const port = process.env.PORT!;
|
|
3899
|
-
const database = process.env.DATABASE!;
|
|
3900
|
-
const dbUser = process.env.DBUSER!;
|
|
3901
|
-
const region = process.env.AWS_REGION!;
|
|
3902
|
-
|
|
3903
|
-
const iamAuthToken = await new Signer({
|
|
3904
|
-
hostname,
|
|
3905
|
-
port: Number(port),
|
|
3906
|
-
region,
|
|
3907
|
-
username: dbUser,
|
|
3908
|
-
}).getAuthToken();
|
|
3883
|
+
const { host, port, dbname, username, password } = await getDatabaseSecret();
|
|
3909
3884
|
|
|
3910
3885
|
return (
|
|
3911
|
-
\`postgresql://\${encodeURIComponent(
|
|
3912
|
-
\`:\${encodeURIComponent(
|
|
3913
|
-
\`@\${
|
|
3914
|
-
\`?sslaccept=strict\`
|
|
3886
|
+
\`postgresql://\${encodeURIComponent(username)}\` +
|
|
3887
|
+
\`:\${encodeURIComponent(password)}\` +
|
|
3888
|
+
\`@\${host}:\${port}/\${dbname}\` +
|
|
3889
|
+
\`?sslaccept=strict\`
|
|
3915
3890
|
);
|
|
3916
3891
|
};
|
|
3917
3892
|
|
|
@@ -4515,32 +4490,19 @@ export abstract class AuroraDatabase extends Construct {
|
|
|
4515
4490
|
timeout: Duration.minutes(5),
|
|
4516
4491
|
tracing: Tracing.ACTIVE,
|
|
4517
4492
|
vpc,
|
|
4518
|
-
environment:
|
|
4519
|
-
|
|
4520
|
-
|
|
4521
|
-
DATABASE_SECRET_ARN: this.cluster.secret!.secretArn,
|
|
4522
|
-
}
|
|
4523
|
-
: {
|
|
4524
|
-
HOSTNAME: databaseHostname,
|
|
4525
|
-
DATABASE: databaseName,
|
|
4526
|
-
PORT: databasePort.toString(),
|
|
4527
|
-
DBUSER: this.dbUser,
|
|
4528
|
-
},
|
|
4493
|
+
environment: {
|
|
4494
|
+
DATABASE_SECRET_ARN: this.cluster.secret!.secretArn,
|
|
4495
|
+
},
|
|
4529
4496
|
architecture: Architecture.ARM_64,
|
|
4530
4497
|
});
|
|
4531
4498
|
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
this.grantSecretRead(migrationHandler);
|
|
4535
|
-
} else {
|
|
4536
|
-
this.allowDefaultPortFrom(migrationHandler);
|
|
4537
|
-
this.grantConnect(migrationHandler);
|
|
4538
|
-
}
|
|
4499
|
+
this.cluster.connections.allowDefaultPortFrom(migrationHandler);
|
|
4500
|
+
this.grantSecretRead(migrationHandler);
|
|
4539
4501
|
|
|
4540
|
-
const
|
|
4502
|
+
const migrationTrigger = new Trigger(this, 'MigrationTrigger', {
|
|
4541
4503
|
handler: migrationHandler,
|
|
4542
4504
|
});
|
|
4543
|
-
|
|
4505
|
+
migrationTrigger.node.addDependency(createDbUserResource);
|
|
4544
4506
|
|
|
4545
4507
|
new CfnOutput(this, 'ClusterEndpoint', {
|
|
4546
4508
|
value: this.cluster.clusterEndpoint.hostname,
|
|
@@ -49,7 +49,7 @@ const ensureDatabaseUser = async (dbUser: string): Promise<void> => {
|
|
|
49
49
|
[
|
|
50
50
|
`CREATE USER IF NOT EXISTS ${quotedUser}@${quotedHost} IDENTIFIED WITH AWSAuthenticationPlugin AS 'RDS'`,
|
|
51
51
|
`ALTER USER ${quotedUser}@${quotedHost} IDENTIFIED WITH AWSAuthenticationPlugin AS 'RDS' REQUIRE SSL`,
|
|
52
|
-
`GRANT
|
|
52
|
+
`GRANT SELECT, INSERT, UPDATE, DELETE ON ${quotedDbName}.* TO ${quotedUser}@${quotedHost}`,
|
|
53
53
|
].join(';\n'),
|
|
54
54
|
);
|
|
55
55
|
} finally {
|
|
@@ -87,14 +87,12 @@ const ensureDatabaseUser = async (dbUser: string): Promise<void> => {
|
|
|
87
87
|
|
|
88
88
|
await client.query(
|
|
89
89
|
`ALTER ROLE ${quotedDbUser} WITH LOGIN;
|
|
90
|
-
GRANT
|
|
91
|
-
GRANT USAGE
|
|
92
|
-
GRANT
|
|
93
|
-
GRANT
|
|
94
|
-
|
|
95
|
-
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT
|
|
96
|
-
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON SEQUENCES TO ${quotedDbUser};
|
|
97
|
-
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT ALL PRIVILEGES ON FUNCTIONS TO ${quotedDbUser};
|
|
90
|
+
GRANT CONNECT ON DATABASE ${quotedDbName} TO ${quotedDbUser};
|
|
91
|
+
GRANT USAGE ON SCHEMA public TO ${quotedDbUser};
|
|
92
|
+
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO ${quotedDbUser};
|
|
93
|
+
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO ${quotedDbUser};
|
|
94
|
+
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO ${quotedDbUser};
|
|
95
|
+
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT USAGE, SELECT ON SEQUENCES TO ${quotedDbUser};
|
|
98
96
|
GRANT rds_iam TO ${quotedDbUser};`,
|
|
99
97
|
);
|
|
100
98
|
|
|
@@ -1,43 +1,16 @@
|
|
|
1
1
|
import { execFile } from 'node:child_process';
|
|
2
2
|
import { promisify } from 'node:util';
|
|
3
|
-
<%_ if (engine === 'mysql') { _%>
|
|
4
3
|
import { getDatabaseSecret, withConnectionRetry } from './utils.js';
|
|
5
|
-
<%_ } else { _%>
|
|
6
|
-
import { Signer } from '@aws-sdk/rds-signer';
|
|
7
|
-
import { withConnectionRetry } from './utils.js';
|
|
8
|
-
<%_ } _%>
|
|
9
4
|
|
|
10
5
|
const buildDatabaseUrl = async (): Promise<string> => {
|
|
11
|
-
<%_ if (engine === 'mysql') { _%>
|
|
12
6
|
const { host, port, dbname, username, password } = await getDatabaseSecret();
|
|
13
7
|
|
|
14
8
|
return (
|
|
15
|
-
|
|
9
|
+
`<%= engine === 'mysql' ? 'mysql' : 'postgresql' %>://${encodeURIComponent(username)}` +
|
|
16
10
|
`:${encodeURIComponent(password)}` +
|
|
17
11
|
`@${host}:${port}/${dbname}` +
|
|
18
12
|
`?sslaccept=strict`
|
|
19
13
|
);
|
|
20
|
-
<%_ } else { _%>
|
|
21
|
-
const hostname = process.env.HOSTNAME!;
|
|
22
|
-
const port = process.env.PORT!;
|
|
23
|
-
const database = process.env.DATABASE!;
|
|
24
|
-
const dbUser = process.env.DBUSER!;
|
|
25
|
-
const region = process.env.AWS_REGION!;
|
|
26
|
-
|
|
27
|
-
const iamAuthToken = await new Signer({
|
|
28
|
-
hostname,
|
|
29
|
-
port: Number(port),
|
|
30
|
-
region,
|
|
31
|
-
username: dbUser,
|
|
32
|
-
}).getAuthToken();
|
|
33
|
-
|
|
34
|
-
return (
|
|
35
|
-
`postgresql://${encodeURIComponent(dbUser)}` +
|
|
36
|
-
`:${encodeURIComponent(iamAuthToken)}` +
|
|
37
|
-
`@${hostname}:${port}/${database}` +
|
|
38
|
-
`?sslaccept=strict` // `sslaccept` is the correct parameter here for postgresql. The Prisma CLI Rust engine does not use the standard libpq `sslmode` option.
|
|
39
|
-
);
|
|
40
|
-
<%_ } _%>
|
|
41
14
|
};
|
|
42
15
|
|
|
43
16
|
export const handler = async () => {
|
package/src/ts/rdb/generator.js
CHANGED
|
@@ -85,7 +85,7 @@ export const tsRdbGenerator = async (tree, options)=>{
|
|
|
85
85
|
...patterns,
|
|
86
86
|
'generated/prisma'
|
|
87
87
|
]);
|
|
88
|
-
await sharedRdbScriptsGenerator(tree, options.engine
|
|
88
|
+
await sharedRdbScriptsGenerator(tree, options.engine);
|
|
89
89
|
const waitForDbScript = options.engine === 'mysql' ? 'wait-for-mysql-db.ts' : 'wait-for-postgres-db.ts';
|
|
90
90
|
const scriptsDir = relative(dir, joinPathFragments(PACKAGES_DIR, SHARED_SCRIPTS_DIR, 'src', 'rdb'));
|
|
91
91
|
const relativePathToRoot = getRelativePathToRootByDirectory(projectConfig.root);
|
|
@@ -207,7 +207,7 @@ export const tsRdbGenerator = async (tree, options)=>{
|
|
|
207
207
|
databasePackageAlias: toScopeAlias(fullyQualifiedName),
|
|
208
208
|
databaseName,
|
|
209
209
|
adminUser: databaseUser,
|
|
210
|
-
engine: options.engine
|
|
210
|
+
engine: options.engine,
|
|
211
211
|
migrationBundleDir,
|
|
212
212
|
createDbUserBundleDir: joinPathFragments('dist', projectConfig.root, 'bundle', 'create-db-user'),
|
|
213
213
|
dockerImageTag,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../packages/nx-plugin/src/ts/rdb/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { relative } from 'node:path';\nimport {\n addDependenciesToPackageJson,\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n readProjectConfiguration,\n type Tree,\n updateJson,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { addTypeScriptBundleTarget } from '../../utils/bundle/bundle';\nimport { resolveContainers } from '../../utils/containers';\nimport { formatFilesInSubtree } from '../../utils/format';\nimport { FsCommands } from '../../utils/fs';\nimport { updateGitIgnore } from '../../utils/git';\nimport { resolveIac } from '../../utils/iac';\nimport { installDependencies } from '../../utils/install';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics';\nimport { kebabCase, snakeCase, toClassName } from '../../utils/names';\nimport { getNpmScope, toScopeAlias } from '../../utils/npm-scope';\nimport {\n addDependencyToTargetIfNotPresent,\n addGeneratorMetadata,\n getGeneratorInfo,\n type NxGeneratorInfo,\n} from '../../utils/nx';\nimport { getRelativePathToRootByDirectory } from '../../utils/paths';\nimport { registerPnpmBuiltDependencies } from '../../utils/pnpm-workspace';\nimport { assignPort } from '../../utils/port';\nimport { addRdbInfra } from '../../utils/rdb-constructs/rdb-constructs';\nimport { sharedConstructsGenerator } from '../../utils/shared-constructs';\nimport {\n PACKAGES_DIR,\n SHARED_SCRIPTS_DIR,\n} from '../../utils/shared-constructs-constants';\nimport { sharedRdbScriptsGenerator } from '../../utils/shared-rdb-scripts';\nimport { TS_VERSIONS, withVersions } from '../../utils/versions';\nimport tsProjectGenerator, { getTsLibDetails } from '../lib/generator';\nimport type { TsRdbGeneratorSchema } from './schema';\n\nexport const TS_RDB_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\nexport const tsRdbGenerator = async (\n tree: Tree,\n options: TsRdbGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const nameKebabCase = kebabCase(options.name);\n const nameClassName = toClassName(options.name);\n const databaseUser = options.databaseUser ?? 'dbadmin';\n const databaseName = snakeCase(options.databaseName ?? options.name);\n const containerEngine = await resolveContainers(tree, 'inherit');\n const { fullyQualifiedName, dir } = getTsLibDetails(tree, {\n name: options.name,\n directory: options.directory,\n subDirectory: options.subDirectory,\n });\n\n let projectExists: boolean;\n try {\n readProjectConfiguration(tree, fullyQualifiedName);\n projectExists = true;\n } catch {\n projectExists = false;\n }\n\n if (!projectExists) {\n await tsProjectGenerator(tree, {\n name: options.name,\n directory: options.directory,\n preferInstallDependencies: false,\n });\n }\n\n updateJson(tree, joinPathFragments(dir, 'tsconfig.lib.json'), (tsConfig) => ({\n ...tsConfig,\n include: ['src/**/*.ts', 'generated/prisma/**/*.ts'],\n }));\n\n const projectConfig = readProjectConfiguration(tree, fullyQualifiedName);\n const localDbPort = assignPort(\n tree,\n projectConfig,\n options.engine === 'mysql' ? 3306 : 5432,\n );\n const localDbHost = 'localhost';\n const localDbUser = options.engine === 'mysql' ? 'root' : 'dbadmin';\n const localDbPassword = 'password';\n const containerName = `${getNpmScope(tree)}-${databaseName}`;\n const dockerImage =\n options.engine === 'mysql'\n ? 'public.ecr.aws/docker/library/mysql:8.0.44'\n : 'public.ecr.aws/docker/library/postgres:17.7';\n\n const templateOptions = {\n engine: options.engine,\n runtimeConfigKey: nameClassName,\n databasePackageAlias: toScopeAlias(fullyQualifiedName),\n databaseProvider: options.engine === 'mysql' ? 'mysql' : 'postgresql',\n prismaVersion: TS_VERSIONS.prisma,\n prismaAdapterPackage:\n options.engine === 'mysql'\n ? '@prisma/adapter-mariadb'\n : '@prisma/adapter-pg',\n prismaAdapterClassName:\n options.engine === 'mysql' ? 'PrismaMariaDb' : 'PrismaPg',\n localDbPort,\n localDbHost,\n localDbName: databaseName,\n localDbUser,\n localDbPassword,\n containerEngine,\n containerName,\n dockerImage,\n };\n\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files'),\n dir,\n templateOptions,\n );\n updateGitIgnore(tree, dir, (patterns) => [...patterns, 'generated/prisma']);\n await sharedRdbScriptsGenerator(\n tree,\n options.engine === 'mysql' ? 'mysql' : 'postgres',\n );\n const waitForDbScript =\n options.engine === 'mysql'\n ? 'wait-for-mysql-db.ts'\n : 'wait-for-postgres-db.ts';\n const scriptsDir = relative(\n dir,\n joinPathFragments(PACKAGES_DIR, SHARED_SCRIPTS_DIR, 'src', 'rdb'),\n );\n const relativePathToRoot = getRelativePathToRootByDirectory(\n projectConfig.root,\n );\n const fs = new FsCommands(tree);\n const migrationBundleDir = joinPathFragments(\n 'dist',\n projectConfig.root,\n 'bundle',\n 'migration',\n );\n const dockerImageTag = `${getNpmScope(tree)}-${kebabCase(options.name)}-migration:latest`;\n\n if (options.infra !== 'none') {\n await addTypeScriptBundleTarget(tree, projectConfig, {\n targetFilePath: 'src/migration-handler.ts',\n bundleOutputDir: 'migration',\n });\n await addTypeScriptBundleTarget(tree, projectConfig, {\n targetFilePath: 'src/create-db-user-handler.ts',\n bundleOutputDir: 'create-db-user',\n });\n const bundleTarget = projectConfig.targets['bundle'];\n // The bundle target starts with a single rolldown `command`. Wrap it with\n // the migration asset copy steps, unless it has already been transformed\n // into a `commands` array on a previous run.\n if (!bundleTarget.options.commands) {\n const rolldownCommand = bundleTarget.options.command;\n delete bundleTarget.options.command;\n bundleTarget.options = {\n ...bundleTarget.options,\n commands: [\n fs.rm(`${relativePathToRoot}dist/{projectRoot}/bundle/migration`),\n fs.mkdir(`${relativePathToRoot}dist/{projectRoot}/bundle/migration`),\n fs.cp(\n 'prisma',\n `${relativePathToRoot}dist/{projectRoot}/bundle/migration/prisma`,\n ),\n fs.cp(\n 'prisma.config.ts',\n `${relativePathToRoot}dist/{projectRoot}/bundle/migration/prisma.config.ts`,\n ),\n fs.cp(\n 'Dockerfile',\n `${relativePathToRoot}dist/{projectRoot}/bundle/migration/Dockerfile`,\n ),\n rolldownCommand,\n ],\n parallel: false,\n };\n }\n }\n\n projectConfig.targets.generate = {\n executor: 'nx:run-commands',\n outputs: ['{projectRoot}/generated/prisma'],\n options: {\n command: 'prisma generate',\n cwd: '{projectRoot}',\n },\n };\n projectConfig.targets['pull-image'] = {\n executor: 'nx:run-commands',\n options: {\n command: `tsx ${scriptsDir}/pull-image.ts`,\n cwd: '{projectRoot}',\n },\n };\n projectConfig.targets['dev'] = {\n executor: 'nx:run-commands',\n options: {\n command: `tsx ${scriptsDir}/start-container.ts`,\n cwd: '{projectRoot}',\n },\n continuous: true,\n };\n projectConfig.targets['wait-for-db'] = {\n executor: 'nx:run-commands',\n dependsOn: ['dev'],\n options: {\n command: `tsx ${scriptsDir}/${waitForDbScript}`,\n cwd: '{projectRoot}',\n },\n };\n projectConfig.targets.prisma = {\n executor: 'nx:run-commands',\n dependsOn: ['dev', 'wait-for-db'],\n options: {\n cwd: '{projectRoot}',\n command: 'prisma',\n env: {\n LOCAL_DEV: 'true',\n },\n },\n };\n if (options.infra !== 'none') {\n const iac = await resolveIac(tree, options.iac);\n if (iac === 'terraform') {\n projectConfig.targets['docker'] = {\n cache: true,\n executor: 'nx:run-commands',\n options: {\n command: `${containerEngine} build --platform linux/arm64 --provenance=false -t ${dockerImageTag} ${migrationBundleDir}`,\n },\n dependsOn: ['bundle'],\n };\n addDependencyToTargetIfNotPresent(projectConfig, 'build', 'docker');\n }\n addDependencyToTargetIfNotPresent(projectConfig, 'build', 'bundle');\n }\n addDependencyToTargetIfNotPresent(projectConfig, 'compile', 'generate');\n updateProjectConfiguration(tree, fullyQualifiedName, projectConfig);\n addGeneratorMetadata(tree, fullyQualifiedName, TS_RDB_GENERATOR_INFO, {\n engine: options.engine,\n });\n\n if (options.infra !== 'none') {\n const iac = await resolveIac(tree, options.iac);\n await sharedConstructsGenerator(tree, { iac });\n await addRdbInfra(tree, {\n iac,\n projectName: fullyQualifiedName,\n projectRoot: dir,\n nameClassName,\n nameKebabCase,\n databasePackageAlias: toScopeAlias(fullyQualifiedName),\n databaseName,\n adminUser: databaseUser,\n engine: options.engine === 'mysql' ? 'mysql' : 'postgres',\n migrationBundleDir,\n createDbUserBundleDir: joinPathFragments(\n 'dist',\n projectConfig.root,\n 'bundle',\n 'create-db-user',\n ),\n dockerImageTag,\n containerEngine,\n });\n }\n\n addDependenciesToPackageJson(\n tree,\n withVersions([\n '@aws-lambda-powertools/parameters',\n '@aws-sdk/client-appconfigdata',\n '@aws-sdk/client-secrets-manager',\n '@aws-sdk/rds-signer',\n '@prisma/client',\n ...(options.engine === 'mysql'\n ? (['@prisma/adapter-mariadb', 'mariadb'] as const)\n : (['@prisma/adapter-pg', 'pg'] as const)),\n ]),\n withVersions([\n 'prisma',\n 'tsx',\n '@types/aws-lambda',\n ...(options.engine === 'mysql'\n ? ([] as const)\n : (['@types/pg'] as const)),\n ]),\n );\n\n registerPnpmBuiltDependencies(tree, {\n '@prisma/engines': false,\n prisma: false,\n });\n\n await addGeneratorMetricsIfApplicable(tree, [TS_RDB_GENERATOR_INFO]);\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript'],\n });\n};\n\nexport default tsRdbGenerator;\n"],"names":["relative","addDependenciesToPackageJson","generateFiles","joinPathFragments","readProjectConfiguration","updateJson","updateProjectConfiguration","addTypeScriptBundleTarget","resolveContainers","formatFilesInSubtree","FsCommands","updateGitIgnore","resolveIac","installDependencies","addGeneratorMetricsIfApplicable","kebabCase","snakeCase","toClassName","getNpmScope","toScopeAlias","addDependencyToTargetIfNotPresent","addGeneratorMetadata","getGeneratorInfo","getRelativePathToRootByDirectory","registerPnpmBuiltDependencies","assignPort","addRdbInfra","sharedConstructsGenerator","PACKAGES_DIR","SHARED_SCRIPTS_DIR","sharedRdbScriptsGenerator","TS_VERSIONS","withVersions","tsProjectGenerator","getTsLibDetails","TS_RDB_GENERATOR_INFO","filename","tsRdbGenerator","tree","options","nameKebabCase","name","nameClassName","databaseUser","databaseName","containerEngine","fullyQualifiedName","dir","directory","subDirectory","projectExists","preferInstallDependencies","tsConfig","include","projectConfig","localDbPort","engine","localDbHost","localDbUser","localDbPassword","containerName","dockerImage","templateOptions","runtimeConfigKey","databasePackageAlias","databaseProvider","prismaVersion","prisma","prismaAdapterPackage","prismaAdapterClassName","localDbName","dirname","patterns","waitForDbScript","scriptsDir","relativePathToRoot","root","fs","migrationBundleDir","dockerImageTag","infra","targetFilePath","bundleOutputDir","bundleTarget","targets","commands","rolldownCommand","command","rm","mkdir","cp","parallel","generate","executor","outputs","cwd","continuous","dependsOn","env","LOCAL_DEV","iac","cache","projectName","projectRoot","adminUser","createDbUserBundleDir","languages"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../../../packages/nx-plugin/src/ts/rdb/generator.ts"],"sourcesContent":["/**\n * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n * SPDX-License-Identifier: Apache-2.0\n */\nimport { relative } from 'node:path';\nimport {\n addDependenciesToPackageJson,\n type GeneratorCallback,\n generateFiles,\n joinPathFragments,\n readProjectConfiguration,\n type Tree,\n updateJson,\n updateProjectConfiguration,\n} from '@nx/devkit';\nimport { addTypeScriptBundleTarget } from '../../utils/bundle/bundle';\nimport { resolveContainers } from '../../utils/containers';\nimport { formatFilesInSubtree } from '../../utils/format';\nimport { FsCommands } from '../../utils/fs';\nimport { updateGitIgnore } from '../../utils/git';\nimport { resolveIac } from '../../utils/iac';\nimport { installDependencies } from '../../utils/install';\nimport { addGeneratorMetricsIfApplicable } from '../../utils/metrics';\nimport { kebabCase, snakeCase, toClassName } from '../../utils/names';\nimport { getNpmScope, toScopeAlias } from '../../utils/npm-scope';\nimport {\n addDependencyToTargetIfNotPresent,\n addGeneratorMetadata,\n getGeneratorInfo,\n type NxGeneratorInfo,\n} from '../../utils/nx';\nimport { getRelativePathToRootByDirectory } from '../../utils/paths';\nimport { registerPnpmBuiltDependencies } from '../../utils/pnpm-workspace';\nimport { assignPort } from '../../utils/port';\nimport { addRdbInfra } from '../../utils/rdb-constructs/rdb-constructs';\nimport { sharedConstructsGenerator } from '../../utils/shared-constructs';\nimport {\n PACKAGES_DIR,\n SHARED_SCRIPTS_DIR,\n} from '../../utils/shared-constructs-constants';\nimport { sharedRdbScriptsGenerator } from '../../utils/shared-rdb-scripts';\nimport { TS_VERSIONS, withVersions } from '../../utils/versions';\nimport tsProjectGenerator, { getTsLibDetails } from '../lib/generator';\nimport type { TsRdbGeneratorSchema } from './schema';\n\nexport const TS_RDB_GENERATOR_INFO: NxGeneratorInfo = getGeneratorInfo(\n import.meta.filename,\n);\n\nexport const tsRdbGenerator = async (\n tree: Tree,\n options: TsRdbGeneratorSchema,\n): Promise<GeneratorCallback> => {\n const nameKebabCase = kebabCase(options.name);\n const nameClassName = toClassName(options.name);\n const databaseUser = options.databaseUser ?? 'dbadmin';\n const databaseName = snakeCase(options.databaseName ?? options.name);\n const containerEngine = await resolveContainers(tree, 'inherit');\n const { fullyQualifiedName, dir } = getTsLibDetails(tree, {\n name: options.name,\n directory: options.directory,\n subDirectory: options.subDirectory,\n });\n\n let projectExists: boolean;\n try {\n readProjectConfiguration(tree, fullyQualifiedName);\n projectExists = true;\n } catch {\n projectExists = false;\n }\n\n if (!projectExists) {\n await tsProjectGenerator(tree, {\n name: options.name,\n directory: options.directory,\n preferInstallDependencies: false,\n });\n }\n\n updateJson(tree, joinPathFragments(dir, 'tsconfig.lib.json'), (tsConfig) => ({\n ...tsConfig,\n include: ['src/**/*.ts', 'generated/prisma/**/*.ts'],\n }));\n\n const projectConfig = readProjectConfiguration(tree, fullyQualifiedName);\n const localDbPort = assignPort(\n tree,\n projectConfig,\n options.engine === 'mysql' ? 3306 : 5432,\n );\n const localDbHost = 'localhost';\n const localDbUser = options.engine === 'mysql' ? 'root' : 'dbadmin';\n const localDbPassword = 'password';\n const containerName = `${getNpmScope(tree)}-${databaseName}`;\n const dockerImage =\n options.engine === 'mysql'\n ? 'public.ecr.aws/docker/library/mysql:8.0.44'\n : 'public.ecr.aws/docker/library/postgres:17.7';\n\n const templateOptions = {\n engine: options.engine,\n runtimeConfigKey: nameClassName,\n databasePackageAlias: toScopeAlias(fullyQualifiedName),\n databaseProvider: options.engine === 'mysql' ? 'mysql' : 'postgresql',\n prismaVersion: TS_VERSIONS.prisma,\n prismaAdapterPackage:\n options.engine === 'mysql'\n ? '@prisma/adapter-mariadb'\n : '@prisma/adapter-pg',\n prismaAdapterClassName:\n options.engine === 'mysql' ? 'PrismaMariaDb' : 'PrismaPg',\n localDbPort,\n localDbHost,\n localDbName: databaseName,\n localDbUser,\n localDbPassword,\n containerEngine,\n containerName,\n dockerImage,\n };\n\n generateFiles(\n tree,\n joinPathFragments(import.meta.dirname, 'files'),\n dir,\n templateOptions,\n );\n updateGitIgnore(tree, dir, (patterns) => [...patterns, 'generated/prisma']);\n await sharedRdbScriptsGenerator(tree, options.engine);\n const waitForDbScript =\n options.engine === 'mysql'\n ? 'wait-for-mysql-db.ts'\n : 'wait-for-postgres-db.ts';\n const scriptsDir = relative(\n dir,\n joinPathFragments(PACKAGES_DIR, SHARED_SCRIPTS_DIR, 'src', 'rdb'),\n );\n const relativePathToRoot = getRelativePathToRootByDirectory(\n projectConfig.root,\n );\n const fs = new FsCommands(tree);\n const migrationBundleDir = joinPathFragments(\n 'dist',\n projectConfig.root,\n 'bundle',\n 'migration',\n );\n const dockerImageTag = `${getNpmScope(tree)}-${kebabCase(options.name)}-migration:latest`;\n\n if (options.infra !== 'none') {\n await addTypeScriptBundleTarget(tree, projectConfig, {\n targetFilePath: 'src/migration-handler.ts',\n bundleOutputDir: 'migration',\n });\n await addTypeScriptBundleTarget(tree, projectConfig, {\n targetFilePath: 'src/create-db-user-handler.ts',\n bundleOutputDir: 'create-db-user',\n });\n const bundleTarget = projectConfig.targets['bundle'];\n // The bundle target starts with a single rolldown `command`. Wrap it with\n // the migration asset copy steps, unless it has already been transformed\n // into a `commands` array on a previous run.\n if (!bundleTarget.options.commands) {\n const rolldownCommand = bundleTarget.options.command;\n delete bundleTarget.options.command;\n bundleTarget.options = {\n ...bundleTarget.options,\n commands: [\n fs.rm(`${relativePathToRoot}dist/{projectRoot}/bundle/migration`),\n fs.mkdir(`${relativePathToRoot}dist/{projectRoot}/bundle/migration`),\n fs.cp(\n 'prisma',\n `${relativePathToRoot}dist/{projectRoot}/bundle/migration/prisma`,\n ),\n fs.cp(\n 'prisma.config.ts',\n `${relativePathToRoot}dist/{projectRoot}/bundle/migration/prisma.config.ts`,\n ),\n fs.cp(\n 'Dockerfile',\n `${relativePathToRoot}dist/{projectRoot}/bundle/migration/Dockerfile`,\n ),\n rolldownCommand,\n ],\n parallel: false,\n };\n }\n }\n\n projectConfig.targets.generate = {\n executor: 'nx:run-commands',\n outputs: ['{projectRoot}/generated/prisma'],\n options: {\n command: 'prisma generate',\n cwd: '{projectRoot}',\n },\n };\n projectConfig.targets['pull-image'] = {\n executor: 'nx:run-commands',\n options: {\n command: `tsx ${scriptsDir}/pull-image.ts`,\n cwd: '{projectRoot}',\n },\n };\n projectConfig.targets['dev'] = {\n executor: 'nx:run-commands',\n options: {\n command: `tsx ${scriptsDir}/start-container.ts`,\n cwd: '{projectRoot}',\n },\n continuous: true,\n };\n projectConfig.targets['wait-for-db'] = {\n executor: 'nx:run-commands',\n dependsOn: ['dev'],\n options: {\n command: `tsx ${scriptsDir}/${waitForDbScript}`,\n cwd: '{projectRoot}',\n },\n };\n projectConfig.targets.prisma = {\n executor: 'nx:run-commands',\n dependsOn: ['dev', 'wait-for-db'],\n options: {\n cwd: '{projectRoot}',\n command: 'prisma',\n env: {\n LOCAL_DEV: 'true',\n },\n },\n };\n if (options.infra !== 'none') {\n const iac = await resolveIac(tree, options.iac);\n if (iac === 'terraform') {\n projectConfig.targets['docker'] = {\n cache: true,\n executor: 'nx:run-commands',\n options: {\n command: `${containerEngine} build --platform linux/arm64 --provenance=false -t ${dockerImageTag} ${migrationBundleDir}`,\n },\n dependsOn: ['bundle'],\n };\n addDependencyToTargetIfNotPresent(projectConfig, 'build', 'docker');\n }\n addDependencyToTargetIfNotPresent(projectConfig, 'build', 'bundle');\n }\n addDependencyToTargetIfNotPresent(projectConfig, 'compile', 'generate');\n updateProjectConfiguration(tree, fullyQualifiedName, projectConfig);\n addGeneratorMetadata(tree, fullyQualifiedName, TS_RDB_GENERATOR_INFO, {\n engine: options.engine,\n });\n\n if (options.infra !== 'none') {\n const iac = await resolveIac(tree, options.iac);\n await sharedConstructsGenerator(tree, { iac });\n await addRdbInfra(tree, {\n iac,\n projectName: fullyQualifiedName,\n projectRoot: dir,\n nameClassName,\n nameKebabCase,\n databasePackageAlias: toScopeAlias(fullyQualifiedName),\n databaseName,\n adminUser: databaseUser,\n engine: options.engine,\n migrationBundleDir,\n createDbUserBundleDir: joinPathFragments(\n 'dist',\n projectConfig.root,\n 'bundle',\n 'create-db-user',\n ),\n dockerImageTag,\n containerEngine,\n });\n }\n\n addDependenciesToPackageJson(\n tree,\n withVersions([\n '@aws-lambda-powertools/parameters',\n '@aws-sdk/client-appconfigdata',\n '@aws-sdk/client-secrets-manager',\n '@aws-sdk/rds-signer',\n '@prisma/client',\n ...(options.engine === 'mysql'\n ? (['@prisma/adapter-mariadb', 'mariadb'] as const)\n : (['@prisma/adapter-pg', 'pg'] as const)),\n ]),\n withVersions([\n 'prisma',\n 'tsx',\n '@types/aws-lambda',\n ...(options.engine === 'mysql'\n ? ([] as const)\n : (['@types/pg'] as const)),\n ]),\n );\n\n registerPnpmBuiltDependencies(tree, {\n '@prisma/engines': false,\n prisma: false,\n });\n\n await addGeneratorMetricsIfApplicable(tree, [TS_RDB_GENERATOR_INFO]);\n\n await formatFilesInSubtree(tree);\n return () =>\n installDependencies(tree, options.preferInstallDependencies, {\n languages: ['typescript'],\n });\n};\n\nexport default tsRdbGenerator;\n"],"names":["relative","addDependenciesToPackageJson","generateFiles","joinPathFragments","readProjectConfiguration","updateJson","updateProjectConfiguration","addTypeScriptBundleTarget","resolveContainers","formatFilesInSubtree","FsCommands","updateGitIgnore","resolveIac","installDependencies","addGeneratorMetricsIfApplicable","kebabCase","snakeCase","toClassName","getNpmScope","toScopeAlias","addDependencyToTargetIfNotPresent","addGeneratorMetadata","getGeneratorInfo","getRelativePathToRootByDirectory","registerPnpmBuiltDependencies","assignPort","addRdbInfra","sharedConstructsGenerator","PACKAGES_DIR","SHARED_SCRIPTS_DIR","sharedRdbScriptsGenerator","TS_VERSIONS","withVersions","tsProjectGenerator","getTsLibDetails","TS_RDB_GENERATOR_INFO","filename","tsRdbGenerator","tree","options","nameKebabCase","name","nameClassName","databaseUser","databaseName","containerEngine","fullyQualifiedName","dir","directory","subDirectory","projectExists","preferInstallDependencies","tsConfig","include","projectConfig","localDbPort","engine","localDbHost","localDbUser","localDbPassword","containerName","dockerImage","templateOptions","runtimeConfigKey","databasePackageAlias","databaseProvider","prismaVersion","prisma","prismaAdapterPackage","prismaAdapterClassName","localDbName","dirname","patterns","waitForDbScript","scriptsDir","relativePathToRoot","root","fs","migrationBundleDir","dockerImageTag","infra","targetFilePath","bundleOutputDir","bundleTarget","targets","commands","rolldownCommand","command","rm","mkdir","cp","parallel","generate","executor","outputs","cwd","continuous","dependsOn","env","LOCAL_DEV","iac","cache","projectName","projectRoot","adminUser","createDbUserBundleDir","languages"],"mappings":"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"}
|
|
@@ -552,6 +552,7 @@ resource "aws_cloudfront_response_headers_policy" "website" {
|
|
|
552
552
|
|
|
553
553
|
# CloudFront Distribution
|
|
554
554
|
resource "aws_cloudfront_distribution" "website" {
|
|
555
|
+
# See https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/DownloadDistValuesGeneral.html
|
|
555
556
|
#checkov:skip=CKV_AWS_174:Using CloudFront default certificate which does not support TLS v1.2
|
|
556
557
|
#checkov:skip=CKV_AWS_310:Origin failover not required for single S3 origin static website
|
|
557
558
|
#checkov:skip=CKV_AWS_374:Geo restrictions not required for global web application
|
|
@@ -1731,6 +1732,7 @@ export class StaticWebsite extends Construct {
|
|
|
1731
1732
|
],
|
|
1732
1733
|
},
|
|
1733
1734
|
);
|
|
1735
|
+
// See https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/DownloadDistValuesGeneral.html
|
|
1734
1736
|
suppressRules(
|
|
1735
1737
|
this.cloudFrontDistribution,
|
|
1736
1738
|
['CKV_AWS_174'],
|
|
@@ -3306,6 +3308,7 @@ export class StaticWebsite extends Construct {
|
|
|
3306
3308
|
],
|
|
3307
3309
|
},
|
|
3308
3310
|
);
|
|
3311
|
+
// See https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/DownloadDistValuesGeneral.html
|
|
3309
3312
|
suppressRules(
|
|
3310
3313
|
this.cloudFrontDistribution,
|
|
3311
3314
|
['CKV_AWS_174'],
|
|
@@ -4808,6 +4811,7 @@ export class StaticWebsite extends Construct {
|
|
|
4808
4811
|
],
|
|
4809
4812
|
},
|
|
4810
4813
|
);
|
|
4814
|
+
// See https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/DownloadDistValuesGeneral.html
|
|
4811
4815
|
suppressRules(
|
|
4812
4816
|
this.cloudFrontDistribution,
|
|
4813
4817
|
['CKV_AWS_174'],
|
|
@@ -3,12 +3,21 @@ import { Construct } from 'constructs';
|
|
|
3
3
|
import * as path from 'node:path';
|
|
4
4
|
import * as url from 'node:url';
|
|
5
5
|
<%_ } _%>
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
AgentCoreGateway,
|
|
8
|
+
AgentCoreGatewayProps,
|
|
9
|
+
} from '../../../core/agentcore-gateway/agentcore-gateway.js';
|
|
7
10
|
import { RuntimeConfig } from '../../../core/runtime-config.js';
|
|
8
11
|
<%_ if (cedarPolicy) { _%>
|
|
9
12
|
import { findWorkspaceRoot } from '../../../core/workspace.js';
|
|
10
13
|
<%_ } _%>
|
|
11
14
|
|
|
15
|
+
<%_ if (cedarPolicy) { _%>
|
|
16
|
+
export type <%- nameClassName %>Props = Omit<AgentCoreGatewayProps, 'cedarPolicyPath'>;
|
|
17
|
+
<%_ } else { _%>
|
|
18
|
+
export type <%- nameClassName %>Props = AgentCoreGatewayProps;
|
|
19
|
+
<%_ } _%>
|
|
20
|
+
|
|
12
21
|
/**
|
|
13
22
|
* AgentCore Gateway wired for MCP protocol with IAM inbound auth.
|
|
14
23
|
<%_ if (cedarPolicy) { _%>
|
|
@@ -21,7 +30,7 @@ export class <%- nameClassName %> extends AgentCoreGateway {
|
|
|
21
30
|
/** Default Gateway target name when added to another Gateway. */
|
|
22
31
|
public readonly gatewayName = '<%- nameKebabCase %>';
|
|
23
32
|
|
|
24
|
-
constructor(scope: Construct, id: string) {
|
|
33
|
+
constructor(scope: Construct, id: string, props?: <%- nameClassName %>Props) {
|
|
25
34
|
super(scope, id, {
|
|
26
35
|
<%_ if (cedarPolicy) { _%>
|
|
27
36
|
cedarPolicyPath: path.join(
|
|
@@ -29,6 +38,7 @@ export class <%- nameClassName %> extends AgentCoreGateway {
|
|
|
29
38
|
'<%- projectDirectory %>/policies',
|
|
30
39
|
),
|
|
31
40
|
<%_ } _%>
|
|
41
|
+
...props,
|
|
32
42
|
});
|
|
33
43
|
|
|
34
44
|
const rc = RuntimeConfig.ensure(this);
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import * as cdk from 'aws-cdk-lib';
|
|
2
2
|
import * as agentcore from 'aws-cdk-lib/aws-bedrockagentcore';
|
|
3
3
|
import * as iam from 'aws-cdk-lib/aws-iam';
|
|
4
|
+
import * as kms from 'aws-cdk-lib/aws-kms';
|
|
4
5
|
import * as lambda from 'aws-cdk-lib/aws-lambda';
|
|
6
|
+
import * as logs from 'aws-cdk-lib/aws-logs';
|
|
5
7
|
import * as triggers from 'aws-cdk-lib/triggers';
|
|
8
|
+
import * as wafv2 from 'aws-cdk-lib/aws-wafv2';
|
|
6
9
|
import { Construct } from 'constructs';
|
|
7
10
|
import ejs from 'ejs';
|
|
8
11
|
import * as fs from 'node:fs';
|
|
@@ -24,6 +27,13 @@ export interface AgentCoreGatewayProps {
|
|
|
24
27
|
* Additional variables available to the Cedar policy EJS templates.
|
|
25
28
|
*/
|
|
26
29
|
readonly cedarPolicyVariables?: Record<string, string>;
|
|
30
|
+
/**
|
|
31
|
+
* Associate a regional WAFv2 web ACL (default AWS managed rule groups) with
|
|
32
|
+
* the gateway to inspect inbound requests.
|
|
33
|
+
*
|
|
34
|
+
* @default true
|
|
35
|
+
*/
|
|
36
|
+
readonly enableWaf?: boolean;
|
|
27
37
|
}
|
|
28
38
|
|
|
29
39
|
/**
|
|
@@ -33,6 +43,8 @@ export interface AgentCoreGatewayProps {
|
|
|
33
43
|
export class AgentCoreGateway extends Construct implements iam.IGrantable {
|
|
34
44
|
public readonly gateway: agentcore.Gateway;
|
|
35
45
|
public readonly policyEngine?: agentcore.CfnPolicyEngine;
|
|
46
|
+
/** The WAFv2 web ACL associated with the gateway, if WAF is enabled. */
|
|
47
|
+
public readonly webAcl?: wafv2.CfnWebACL;
|
|
36
48
|
private readonly policies: agentcore.CfnPolicy[] = [];
|
|
37
49
|
private targetReadinessProbe?: triggers.TriggerFunction;
|
|
38
50
|
private readonly targetRuntimeArns: string[] = [];
|
|
@@ -41,6 +53,9 @@ export class AgentCoreGateway extends Construct implements iam.IGrantable {
|
|
|
41
53
|
super(scope, id);
|
|
42
54
|
|
|
43
55
|
this.gateway = new agentcore.Gateway(this, 'Gateway', {
|
|
56
|
+
// Cap at 39 chars so the 11-char service suffix keeps the gateway id
|
|
57
|
+
// within its 50-char limit.
|
|
58
|
+
gatewayName: cdk.Names.uniqueResourceName(this, { maxLength: 39 }),
|
|
44
59
|
protocolConfiguration: new agentcore.McpProtocolConfiguration({
|
|
45
60
|
searchType: agentcore.McpGatewaySearchType.SEMANTIC,
|
|
46
61
|
supportedVersions: [agentcore.MCPProtocolVersion.MCP_2025_03_26],
|
|
@@ -128,6 +143,103 @@ export class AgentCoreGateway extends Construct implements iam.IGrantable {
|
|
|
128
143
|
}
|
|
129
144
|
}
|
|
130
145
|
}
|
|
146
|
+
|
|
147
|
+
if (props?.enableWaf ?? true) {
|
|
148
|
+
this.webAcl = this.createWebAcl();
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Create a regional WAFv2 web ACL with the default AWS managed rule groups,
|
|
154
|
+
* associate it with the gateway, and log requests to CloudWatch.
|
|
155
|
+
*/
|
|
156
|
+
private createWebAcl(): wafv2.CfnWebACL {
|
|
157
|
+
const metricPrefix = cdk.Names.uniqueResourceName(this, { maxLength: 40 });
|
|
158
|
+
|
|
159
|
+
const webAcl = new wafv2.CfnWebACL(this, 'WebAcl', {
|
|
160
|
+
defaultAction: { allow: {} },
|
|
161
|
+
// AgentCore Gateway requires a REGIONAL web ACL; CloudFront (global) is
|
|
162
|
+
// not supported.
|
|
163
|
+
scope: 'REGIONAL',
|
|
164
|
+
visibilityConfig: {
|
|
165
|
+
cloudWatchMetricsEnabled: true,
|
|
166
|
+
metricName: `${metricPrefix}WebAcl`,
|
|
167
|
+
sampledRequestsEnabled: true,
|
|
168
|
+
},
|
|
169
|
+
rules: [
|
|
170
|
+
{
|
|
171
|
+
name: 'CRSRule',
|
|
172
|
+
priority: 0,
|
|
173
|
+
statement: {
|
|
174
|
+
managedRuleGroupStatement: {
|
|
175
|
+
name: 'AWSManagedRulesCommonRuleSet',
|
|
176
|
+
vendorName: 'AWS',
|
|
177
|
+
// Count instead of Block: the CRS 8 KB body limit is too
|
|
178
|
+
// restrictive for typical MCP tool payloads.
|
|
179
|
+
ruleActionOverrides: [
|
|
180
|
+
{
|
|
181
|
+
name: 'SizeRestrictions_BODY',
|
|
182
|
+
actionToUse: { count: {} },
|
|
183
|
+
},
|
|
184
|
+
],
|
|
185
|
+
},
|
|
186
|
+
},
|
|
187
|
+
visibilityConfig: {
|
|
188
|
+
cloudWatchMetricsEnabled: true,
|
|
189
|
+
metricName: `${metricPrefix}WebAcl-CRS`,
|
|
190
|
+
sampledRequestsEnabled: true,
|
|
191
|
+
},
|
|
192
|
+
overrideAction: {
|
|
193
|
+
none: {},
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
name: 'KnownBadInputsRule',
|
|
198
|
+
priority: 1,
|
|
199
|
+
statement: {
|
|
200
|
+
managedRuleGroupStatement: {
|
|
201
|
+
name: 'AWSManagedRulesKnownBadInputsRuleSet',
|
|
202
|
+
vendorName: 'AWS',
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
visibilityConfig: {
|
|
206
|
+
cloudWatchMetricsEnabled: true,
|
|
207
|
+
metricName: `${metricPrefix}WebAcl-KnownBadInputs`,
|
|
208
|
+
sampledRequestsEnabled: true,
|
|
209
|
+
},
|
|
210
|
+
overrideAction: {
|
|
211
|
+
none: {},
|
|
212
|
+
},
|
|
213
|
+
},
|
|
214
|
+
],
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
new wafv2.CfnWebACLAssociation(this, 'WebAclAssociation', {
|
|
218
|
+
resourceArn: this.gateway.gatewayArn,
|
|
219
|
+
webAclArn: webAcl.attrArn,
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
// WAFv2 logging destination requires the `aws-waf-logs-` name prefix.
|
|
223
|
+
const logsKey = new kms.Key(this, 'WebAclLogsKey', {
|
|
224
|
+
enableKeyRotation: true,
|
|
225
|
+
});
|
|
226
|
+
logsKey.grantEncryptDecrypt(
|
|
227
|
+
new iam.ServicePrincipal(
|
|
228
|
+
`logs.${cdk.Stack.of(this).region}.amazonaws.com`,
|
|
229
|
+
),
|
|
230
|
+
);
|
|
231
|
+
const wafLogGroup = new logs.LogGroup(this, 'WebAclLogs', {
|
|
232
|
+
logGroupName: `aws-waf-logs-${metricPrefix}-${this.node.addr.slice(-8)}`,
|
|
233
|
+
retention: logs.RetentionDays.ONE_YEAR,
|
|
234
|
+
encryptionKey: logsKey,
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
new wafv2.CfnLoggingConfiguration(this, 'WebAclLoggingConfig', {
|
|
238
|
+
resourceArn: webAcl.attrArn,
|
|
239
|
+
logDestinationConfigs: [wafLogGroup.logGroupArn],
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
return webAcl;
|
|
131
243
|
}
|
|
132
244
|
|
|
133
245
|
/**
|
|
@@ -34,6 +34,12 @@ variable "tool_dependencies" {
|
|
|
34
34
|
type = list(string)
|
|
35
35
|
default = []
|
|
36
36
|
}
|
|
37
|
+
|
|
38
|
+
variable "enable_waf" {
|
|
39
|
+
description = "Associate a regional WAFv2 web ACL (default AWS managed rule groups) with the gateway to inspect inbound requests."
|
|
40
|
+
type = bool
|
|
41
|
+
default = true
|
|
42
|
+
}
|
|
37
43
|
<%_ if (cedarPolicy) { _%>
|
|
38
44
|
|
|
39
45
|
variable "policy_dependencies" {
|
|
@@ -141,7 +147,9 @@ resource "aws_bedrockagentcore_policy_engine" "this" {
|
|
|
141
147
|
<%_ } _%>
|
|
142
148
|
|
|
143
149
|
resource "aws_bedrockagentcore_gateway" "this" {
|
|
144
|
-
name
|
|
150
|
+
# Cap the name so the 11-char service suffix keeps the gateway id within its
|
|
151
|
+
# 50-char limit (30 prefix + "-<8 hex>" + 11 = 50).
|
|
152
|
+
name = "${substr("<%- nameClassName %>", 0, 30)}-${random_id.unique_suffix.hex}"
|
|
145
153
|
description = "AgentCore Gateway for <%- nameClassName %>"
|
|
146
154
|
role_arn = aws_iam_role.gateway_role.arn
|
|
147
155
|
|
|
@@ -164,6 +172,107 @@ resource "aws_bedrockagentcore_gateway" "this" {
|
|
|
164
172
|
depends_on = [aws_iam_role_policy.gateway_role_policy]
|
|
165
173
|
<%_ } _%>
|
|
166
174
|
}
|
|
175
|
+
|
|
176
|
+
# WAFv2 protection for the gateway. AgentCore Gateway requires a REGIONAL web
|
|
177
|
+
# ACL; CloudFront (global) is not supported.
|
|
178
|
+
resource "aws_wafv2_web_acl" "gateway_waf" {
|
|
179
|
+
#checkov:skip=CKV2_AWS_31:Logging configuration is defined below in aws_wafv2_web_acl_logging_configuration.gateway_waf_logging; Checkov does not resolve the separate resource
|
|
180
|
+
count = var.enable_waf ? 1 : 0
|
|
181
|
+
|
|
182
|
+
name = "<%- nameClassName %>-waf-${random_id.unique_suffix.hex}"
|
|
183
|
+
scope = "REGIONAL"
|
|
184
|
+
|
|
185
|
+
default_action {
|
|
186
|
+
allow {}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
rule {
|
|
190
|
+
name = "CRSRule"
|
|
191
|
+
priority = 0
|
|
192
|
+
|
|
193
|
+
override_action {
|
|
194
|
+
none {}
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
statement {
|
|
198
|
+
managed_rule_group_statement {
|
|
199
|
+
name = "AWSManagedRulesCommonRuleSet"
|
|
200
|
+
vendor_name = "AWS"
|
|
201
|
+
|
|
202
|
+
# Count instead of Block: the CRS 8 KB body limit is too restrictive
|
|
203
|
+
# for typical MCP tool payloads.
|
|
204
|
+
rule_action_override {
|
|
205
|
+
name = "SizeRestrictions_BODY"
|
|
206
|
+
action_to_use {
|
|
207
|
+
count {}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
visibility_config {
|
|
214
|
+
cloudwatch_metrics_enabled = true
|
|
215
|
+
metric_name = "<%- nameClassName %>WebAcl-CRS"
|
|
216
|
+
sampled_requests_enabled = true
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
rule {
|
|
221
|
+
name = "KnownBadInputsRule"
|
|
222
|
+
priority = 1
|
|
223
|
+
|
|
224
|
+
override_action {
|
|
225
|
+
none {}
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
statement {
|
|
229
|
+
managed_rule_group_statement {
|
|
230
|
+
name = "AWSManagedRulesKnownBadInputsRuleSet"
|
|
231
|
+
vendor_name = "AWS"
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
visibility_config {
|
|
236
|
+
cloudwatch_metrics_enabled = true
|
|
237
|
+
metric_name = "<%- nameClassName %>WebAcl-KnownBadInputs"
|
|
238
|
+
sampled_requests_enabled = true
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
visibility_config {
|
|
243
|
+
cloudwatch_metrics_enabled = true
|
|
244
|
+
metric_name = "<%- nameClassName %>WebAcl"
|
|
245
|
+
sampled_requests_enabled = true
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
lifecycle {
|
|
249
|
+
create_before_destroy = true
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
resource "aws_wafv2_web_acl_association" "gateway_waf" {
|
|
254
|
+
count = var.enable_waf ? 1 : 0
|
|
255
|
+
|
|
256
|
+
resource_arn = aws_bedrockagentcore_gateway.this.gateway_arn
|
|
257
|
+
web_acl_arn = aws_wafv2_web_acl.gateway_waf[0].arn
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
# WAF request logs. WAFv2 requires the `aws-waf-logs-` name prefix.
|
|
261
|
+
resource "aws_cloudwatch_log_group" "gateway_waf_logs" {
|
|
262
|
+
#checkov:skip=CKV_AWS_158:Using default CloudWatch log encryption
|
|
263
|
+
#checkov:skip=CKV_AWS_338:Log retention set to one year which is sufficient for WAF logs
|
|
264
|
+
count = var.enable_waf ? 1 : 0
|
|
265
|
+
|
|
266
|
+
name = "aws-waf-logs-<%- nameKebabCase %>-${random_id.unique_suffix.hex}"
|
|
267
|
+
retention_in_days = 365
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
resource "aws_wafv2_web_acl_logging_configuration" "gateway_waf_logging" {
|
|
271
|
+
count = var.enable_waf ? 1 : 0
|
|
272
|
+
|
|
273
|
+
log_destination_configs = [aws_cloudwatch_log_group.gateway_waf_logs[0].arn]
|
|
274
|
+
resource_arn = aws_wafv2_web_acl.gateway_waf[0].arn
|
|
275
|
+
}
|
|
167
276
|
<%_ if (cedarPolicy) { _%>
|
|
168
277
|
|
|
169
278
|
# Anchor for the policy_dependencies variable — depends_on only accepts
|
|
@@ -333,3 +442,8 @@ output "gateway_role_arn" {
|
|
|
333
442
|
description = "ARN of the IAM role assumed by the gateway service"
|
|
334
443
|
value = aws_iam_role.gateway_role.arn
|
|
335
444
|
}
|
|
445
|
+
|
|
446
|
+
output "waf_web_acl_arn" {
|
|
447
|
+
description = "ARN of the WAFv2 web ACL associated with the gateway, or null if WAF is disabled"
|
|
448
|
+
value = var.enable_waf ? aws_wafv2_web_acl.gateway_waf[0].arn : null
|
|
449
|
+
}
|
|
@@ -350,29 +350,19 @@ export abstract class AuroraDatabase extends Construct {
|
|
|
350
350
|
timeout: Duration.minutes(5),
|
|
351
351
|
tracing: Tracing.ACTIVE,
|
|
352
352
|
vpc,
|
|
353
|
-
environment:
|
|
353
|
+
environment: {
|
|
354
354
|
DATABASE_SECRET_ARN: this.cluster.secret!.secretArn,
|
|
355
|
-
} : {
|
|
356
|
-
HOSTNAME: databaseHostname,
|
|
357
|
-
DATABASE: databaseName,
|
|
358
|
-
PORT: databasePort.toString(),
|
|
359
|
-
DBUSER: this.dbUser,
|
|
360
355
|
},
|
|
361
356
|
architecture: Architecture.ARM_64,
|
|
362
357
|
});
|
|
363
358
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
this.grantSecretRead(migrationHandler);
|
|
367
|
-
} else {
|
|
368
|
-
this.allowDefaultPortFrom(migrationHandler);
|
|
369
|
-
this.grantConnect(migrationHandler);
|
|
370
|
-
}
|
|
359
|
+
this.cluster.connections.allowDefaultPortFrom(migrationHandler);
|
|
360
|
+
this.grantSecretRead(migrationHandler);
|
|
371
361
|
|
|
372
|
-
const
|
|
362
|
+
const migrationTrigger = new Trigger(this, 'MigrationTrigger', {
|
|
373
363
|
handler: migrationHandler,
|
|
374
364
|
});
|
|
375
|
-
|
|
365
|
+
migrationTrigger.node.addDependency(createDbUserResource);
|
|
376
366
|
|
|
377
367
|
new CfnOutput(this, 'ClusterEndpoint', {
|
|
378
368
|
value: this.cluster.clusterEndpoint.hostname,
|
|
@@ -347,7 +347,6 @@ resource "aws_iam_role_policy" "migration_handler_access" {
|
|
|
347
347
|
policy = jsonencode({
|
|
348
348
|
Version = "2012-10-17"
|
|
349
349
|
Statement = [
|
|
350
|
-
<%_ if (engine === 'mysql') { _%>
|
|
351
350
|
{
|
|
352
351
|
Effect = "Allow"
|
|
353
352
|
Action = [
|
|
@@ -362,17 +361,6 @@ resource "aws_iam_role_policy" "migration_handler_access" {
|
|
|
362
361
|
]
|
|
363
362
|
Resource = [module.aurora.kms_key_arn]
|
|
364
363
|
}
|
|
365
|
-
<%_ } else { _%>
|
|
366
|
-
{
|
|
367
|
-
Effect = "Allow"
|
|
368
|
-
Action = [
|
|
369
|
-
"rds-db:connect"
|
|
370
|
-
]
|
|
371
|
-
Resource = [
|
|
372
|
-
"arn:aws:rds-db:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:dbuser:${var.enable_rds_proxy ? module.aurora.proxy_resource_id : module.aurora.cluster_resource_id}/${local.database_runtime_user}"
|
|
373
|
-
]
|
|
374
|
-
}
|
|
375
|
-
<%_ } _%>
|
|
376
364
|
]
|
|
377
365
|
})
|
|
378
366
|
}
|
|
@@ -459,13 +447,8 @@ resource "aws_security_group" "migration_handler" {
|
|
|
459
447
|
}
|
|
460
448
|
|
|
461
449
|
resource "aws_vpc_security_group_egress_rule" "migration_handler_to_database" {
|
|
462
|
-
<%_ if (engine === 'mysql') { _%>
|
|
463
450
|
security_group_id = aws_security_group.migration_handler.id
|
|
464
451
|
referenced_security_group_id = module.aurora.database_security_group_id
|
|
465
|
-
<%_ } else { _%>
|
|
466
|
-
security_group_id = aws_security_group.migration_handler.id
|
|
467
|
-
referenced_security_group_id = module.aurora.security_group_id
|
|
468
|
-
<%_ } _%>
|
|
469
452
|
from_port = module.aurora.cluster_port
|
|
470
453
|
to_port = module.aurora.cluster_port
|
|
471
454
|
ip_protocol = "tcp"
|
|
@@ -507,11 +490,7 @@ resource "aws_vpc_security_group_egress_rule" "create_db_user_https" {
|
|
|
507
490
|
}
|
|
508
491
|
|
|
509
492
|
resource "aws_vpc_security_group_ingress_rule" "migration_handler_to_database" {
|
|
510
|
-
<%_ if (engine === 'mysql') { _%>
|
|
511
493
|
security_group_id = module.aurora.database_security_group_id
|
|
512
|
-
<%_ } else { _%>
|
|
513
|
-
security_group_id = module.aurora.security_group_id
|
|
514
|
-
<%_ } _%>
|
|
515
494
|
referenced_security_group_id = aws_security_group.migration_handler.id
|
|
516
495
|
from_port = module.aurora.cluster_port
|
|
517
496
|
to_port = module.aurora.cluster_port
|
|
@@ -632,14 +611,7 @@ resource "aws_lambda_function" "migration_handler" {
|
|
|
632
611
|
|
|
633
612
|
environment {
|
|
634
613
|
variables = {
|
|
635
|
-
<%_ if (engine === 'mysql') { _%>
|
|
636
614
|
DATABASE_SECRET_ARN = module.aurora.secret_arn
|
|
637
|
-
<%_ } else { _%>
|
|
638
|
-
HOSTNAME = module.aurora.cluster_endpoint
|
|
639
|
-
DATABASE = module.aurora.database_name
|
|
640
|
-
PORT = tostring(module.aurora.cluster_port)
|
|
641
|
-
DBUSER = local.database_runtime_user
|
|
642
|
-
<%_ } _%>
|
|
643
615
|
}
|
|
644
616
|
}
|
|
645
617
|
|
package/src/utils/website-constructs/files/terraform/core/static-website/static-website.tf.template
CHANGED
|
@@ -423,6 +423,7 @@ resource "aws_cloudfront_response_headers_policy" "website" {
|
|
|
423
423
|
|
|
424
424
|
# CloudFront Distribution
|
|
425
425
|
resource "aws_cloudfront_distribution" "website" {
|
|
426
|
+
# See https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/DownloadDistValuesGeneral.html
|
|
426
427
|
#checkov:skip=CKV_AWS_174:Using CloudFront default certificate which does not support TLS v1.2
|
|
427
428
|
#checkov:skip=CKV_AWS_310:Origin failover not required for single S3 origin static website
|
|
428
429
|
#checkov:skip=CKV_AWS_374:Geo restrictions not required for global web application
|