From dfcfb8da34a495987214e70713b0c61f368ce962 Mon Sep 17 00:00:00 2001 From: Rico Huijbers Date: Fri, 4 Nov 2022 20:41:33 +0100 Subject: [PATCH] refactor: reorganize and document feature flags (#22771) Require feature flag information to be more structured, and generate a Markdown report automatically that people can refer to if they need to review their feature flag setup. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- CONTRIBUTING.md | 21 +- .../@aws-cdk/assert-internal/tsconfig.json | 4 +- packages/@aws-cdk/assert/tsconfig.json | 4 +- packages/@aws-cdk/cfnspec/tsconfig.json | 2 +- .../cloud-assembly-schema/lib/manifest.ts | 8 +- .../cloudformation-diff/tsconfig.json | 4 +- packages/@aws-cdk/core/lib/feature-flags.ts | 2 +- packages/@aws-cdk/cx-api/FEATURE_FLAGS.md | 394 ++++++++ .../cx-api/build-tools/flag-report.ts | 166 ++++ packages/@aws-cdk/cx-api/lib/features.ts | 888 ++++++++++-------- .../cx-api/lib/private/flag-modeling.ts | 39 + packages/@aws-cdk/cx-api/package.json | 3 + .../@aws-cdk/cx-api/test/features.test.ts | 41 +- .../integ-runner/lib/runner/runner-base.ts | 27 +- .../region-info/build-tools/generate.sh | 2 +- .../rewrite-imports/lib/rewrite.ts | 2 +- .../rewrite-imports/tsconfig.json | 4 +- packages/aws-cdk-migration/lib/rewrite.ts | 2 +- packages/aws-cdk-migration/tsconfig.json | 4 +- .../app/typescript/tsconfig.json | 4 +- .../lib/typescript/tsconfig.json | 4 +- .../sample-app/javascript/tsconfig.json | 6 +- .../sample-app/typescript/tsconfig.json | 4 +- packages/aws-cdk/lib/init.ts | 8 +- packages/aws-cdk/test/init.test.ts | 7 +- packages/awslint/tsconfig.json | 4 +- packages/cdk-assets/tsconfig.json | 4 +- packages/cdk-dasm/tsconfig.json | 4 +- tools/@aws-cdk/cdk-build-tools/tsconfig.json | 4 +- .../cdk-integ-tools/lib/integ-helpers.ts | 17 +- tools/@aws-cdk/cdk-integ-tools/tsconfig.json | 4 +- tools/@aws-cdk/cdk-release/tsconfig.json | 4 +- tools/@aws-cdk/cfn2ts/tsconfig.json | 4 +- tools/@aws-cdk/eslint-plugin/tsconfig.json | 4 +- .../@aws-cdk/individual-pkg-gen/tsconfig.json | 4 +- tools/@aws-cdk/pkglint/tsconfig.json | 4 +- tools/@aws-cdk/pkgtools/tsconfig.json | 4 +- tools/@aws-cdk/prlint/tsconfig.json | 4 +- tools/@aws-cdk/ubergen/tsconfig.json | 4 +- tools/@aws-cdk/yarn-cling/tsconfig.json | 4 +- 40 files changed, 1242 insertions(+), 481 deletions(-) create mode 100644 packages/@aws-cdk/cx-api/FEATURE_FLAGS.md create mode 100644 packages/@aws-cdk/cx-api/build-tools/flag-report.ts create mode 100644 packages/@aws-cdk/cx-api/lib/private/flag-modeling.ts diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d0b91c8b3f800..489ffe35943a0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -953,9 +953,17 @@ changes are only allowed in major versions and those are rare. To address this need, we have a feature flags pattern/mechanism. It allows us to introduce new breaking behavior which is disabled by default (so existing projects will not be affected) but enabled automatically for new projects -created through `cdk init`. +created through `cdk init`. Existing users can selectively opt in to new +behavior on their own schedule. -The pattern is simple: +Whenever a change leads to CloudFormation template differences that cause any of +the following during an update, it is not safe to apply the new behavior +automatically, and we have to use a feature flag: + +- Resources replacement leading to service disruption; or +- Users could have taken assumptions on the old setup and the change will break them. + +Adding a new flag looks as follows: 1. Define a new const under [cx-api/lib/features.ts](https://github.com/aws/aws-cdk/blob/main/packages/%40aws-cdk/cx-api/lib/features.ts) @@ -964,10 +972,11 @@ The pattern is simple: form `module.Type:feature` (e.g. `@aws-cdk/core:enableStackNameDuplicates`). 2. Use `FeatureFlags.of(construct).isEnabled(cxapi.ENABLE_XXX)` to check if this feature is enabled in your code. If it is not defined, revert to the legacy behavior. -3. Add your feature flag to the `FUTURE_FLAGS` map in - [cx-api/lib/features.ts](https://github.com/aws/aws-cdk/blob/main/packages/%40aws-cdk/cx-api/lib/features.ts). - This map is inserted to generated `cdk.json` files for new projects created - through `cdk init`. +3. Add your feature flag to the `FLAGS` map in + [cx-api/lib/features.ts](https://github.com/aws/aws-cdk/blob/main/packages/%40aws-cdk/cx-api/lib/features.ts). In + your description, be sure to cover the following: + - Consciously pick the type of feature flag. Can the flag be removed in a future major version, or not? + - Motivate why the feature flag exists. What is the change to existing infrastructure and why is it not safe? 4. Add an entry for your feature flag in the [README](https://github.com/aws/aws-cdk/blob/main/packages/%40aws-cdk/cx-api/README.md) file. 5. In your tests, ensure that you test your feature with and without the feature flag enabled. You can do this by passing the feature flag to the `context` property when instantiating an `App`. ```ts diff --git a/packages/@aws-cdk/assert-internal/tsconfig.json b/packages/@aws-cdk/assert-internal/tsconfig.json index 6aae954779f33..7873e7c128974 100644 --- a/packages/@aws-cdk/assert-internal/tsconfig.json +++ b/packages/@aws-cdk/assert-internal/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { - "target":"es2018", - "lib": ["es2016", "es2017.object", "es2017.string"], + "target":"es2020", + "lib": ["es2020"], "module": "commonjs", "composite": true, "declaration": true, diff --git a/packages/@aws-cdk/assert/tsconfig.json b/packages/@aws-cdk/assert/tsconfig.json index b426f95fcb96a..50c258f73b5a6 100644 --- a/packages/@aws-cdk/assert/tsconfig.json +++ b/packages/@aws-cdk/assert/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { - "target":"ES2018", - "lib": ["es2018"], + "target":"ES2020", + "lib": ["es2020"], "module": "CommonJS", "declaration": true, "strict": true, diff --git a/packages/@aws-cdk/cfnspec/tsconfig.json b/packages/@aws-cdk/cfnspec/tsconfig.json index 5e75173fa8734..0dcbaaec63010 100644 --- a/packages/@aws-cdk/cfnspec/tsconfig.json +++ b/packages/@aws-cdk/cfnspec/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target":"ES2018", + "target":"ES2020", "module": "commonjs", "lib": ["es2016", "es2017.object", "es2017.string"], "declaration": true, diff --git a/packages/@aws-cdk/cloud-assembly-schema/lib/manifest.ts b/packages/@aws-cdk/cloud-assembly-schema/lib/manifest.ts index 62f7894a54dd3..ce7b033901bd4 100644 --- a/packages/@aws-cdk/cloud-assembly-schema/lib/manifest.ts +++ b/packages/@aws-cdk/cloud-assembly-schema/lib/manifest.ts @@ -181,7 +181,13 @@ export class Manifest { } private static loadManifest(filePath: string, schema: jsonschema.Schema, preprocess?: (obj: any) => any, options?: LoadManifestOptions) { - let obj = JSON.parse(fs.readFileSync(filePath, { encoding: 'utf-8' })); + const contents = fs.readFileSync(filePath, { encoding: 'utf-8' }); + let obj; + try { + obj = JSON.parse(contents); + } catch (e) { + throw new Error(`${e.message}, while parsing ${JSON.stringify(contents)}`); + } if (preprocess) { obj = preprocess(obj); } diff --git a/packages/@aws-cdk/cloudformation-diff/tsconfig.json b/packages/@aws-cdk/cloudformation-diff/tsconfig.json index ffd93f2f3985b..7e833481e2ae9 100644 --- a/packages/@aws-cdk/cloudformation-diff/tsconfig.json +++ b/packages/@aws-cdk/cloudformation-diff/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { - "target":"ES2018", + "target":"ES2020", "module": "commonjs", - "lib": ["es2016", "es2017.object", "es2017.string"], + "lib": ["es2020"], "declaration": true, "composite": true, "strict": true, diff --git a/packages/@aws-cdk/core/lib/feature-flags.ts b/packages/@aws-cdk/core/lib/feature-flags.ts index 95ff50be4d040..3d020323f6b9a 100644 --- a/packages/@aws-cdk/core/lib/feature-flags.ts +++ b/packages/@aws-cdk/core/lib/feature-flags.ts @@ -25,7 +25,7 @@ export class FeatureFlags { */ public isEnabled(featureFlag: string): boolean | undefined { const context = Node.of(this.construct).tryGetContext(featureFlag); - if (cxapi.FUTURE_FLAGS_EXPIRED.includes(featureFlag)) { + if (cxapi.CURRENT_VERSION_EXPIRED_FLAGS.includes(featureFlag)) { if (context !== undefined) { throw new Error(`Unsupported feature flag '${featureFlag}'. This flag existed on CDKv1 but has been removed in CDKv2.` + ' CDK will now behave as the same as when the flag is enabled.'); diff --git a/packages/@aws-cdk/cx-api/FEATURE_FLAGS.md b/packages/@aws-cdk/cx-api/FEATURE_FLAGS.md new file mode 100644 index 0000000000000..5bd7e9a7717c8 --- /dev/null +++ b/packages/@aws-cdk/cx-api/FEATURE_FLAGS.md @@ -0,0 +1,394 @@ +# CDK Feature Flags + +[CDK Feature Flags](https://docs.aws.amazon.com/cdk/v2/guide/featureflags.html) are a mechanism that allows the CDK to evolve and change the behavior of certain classes and methods, without causing disruption to existing deployed infrastructure. + +Feature flags are [context values](https://docs.aws.amazon.com/cdk/v2/guide/context.html) and can be configured using any of the context management methods, at any level of the construct tree. Commonly, they are specified in the `cdk.json` file. +`cdk init` will create new CDK projects with a `cdk.json` file containing all recommended feature flags enabled. + +## Feature flag table + +Flags come in three types: + +- **Default change**: The default behavior of an API has been changed in order to improve its ergonomics. The old behavior can still be achieved, but requires source changes. +- **Fix/deprecation**: The old behavior was incorrect or not recommended for new users. The only way to keep it is to not set this flag. +- **Config**: Configurable behavior that we recommend you turn on. + + + +| Flag | Summary | Since | Type | Recommended | +| ----- | ----- | ----- | ----- | ----- | +| @aws-cdk/core:newStyleStackSynthesis | Switch to new stack synthesis method which enables CI/CD | 2.0.0 | (fix) | `true` | +| @aws-cdk/core:stackRelativeExports | Name exports based on the construct paths relative to the stack, rather than the global construct path | 2.0.0 | (fix) | `true` | +| @aws-cdk/aws-rds:lowercaseDbIdentifier | Force lowercasing of RDS Cluster names in CDK | 2.0.0 | (fix) | `true` | +| @aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId | Allow adding/removing multiple UsagePlanKeys independently | 2.0.0 | (fix) | `true` | +| @aws-cdk/aws-lambda:recognizeVersionProps | Enable this feature flag to opt in to the updated logical id calculation for Lambda Version created using the `fn.currentVersion`. | 2.0.0 | (fix) | `true` | +| @aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021 | Enable this feature flag to have cloudfront distributions use the security policy TLSv1.2_2021 by default. | 2.0.0 | (fix) | `true` | +| @aws-cdk/core:target-partitions | What regions to include in lookup tables of environment agnostic stacks | 2.4.0 | (config) | `["aws","aws-cn"]` | +| @aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver | ECS extensions will automatically add an `awslogs` driver if no logging is specified | 2.8.0 | (default) | `true` | +| @aws-cdk/aws-ec2:uniqueImdsv2TemplateName | Enable this feature flag to have Launch Templates generated by the `InstanceRequireImdsv2Aspect` use unique names. | 2.8.0 | (fix) | `true` | +| @aws-cdk/aws-iam:minimizePolicies | Minimize IAM policies by combining Statements | 2.18.0 | (config) | `true` | +| @aws-cdk/core:checkSecretUsage | Enable this flag to make it impossible to accidentally use SecretValues in unsafe locations | 2.21.0 | (config) | `true` | +| @aws-cdk/aws-lambda:recognizeLayerVersion | Enable this feature flag to opt in to the updated logical id calculation for Lambda Version created using the `fn.currentVersion`. | 2.27.0 | (fix) | `true` | +| @aws-cdk/core:validateSnapshotRemovalPolicy | Error on snapshot removal policies on resources that do not support it. | 2.28.0 | (default) | `true` | +| @aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName | Generate key aliases that include the stack name | 2.29.0 | (fix) | `true` | +| @aws-cdk/aws-s3:createDefaultLoggingPolicy | Enable this feature flag to create an S3 bucket policy by default in cases where an AWS service would automatically create the Policy if one does not exist. | 2.31.0 | (fix) | `true` | +| @aws-cdk/aws-sns-subscriptions:restrictSqsDescryption | Restrict KMS key policy for encrypted Queues a bit more | 2.32.0 | (fix) | `true` | +| @aws-cdk/aws-ecs:arnFormatIncludesClusterName | ARN format used by ECS. In the new ARN format, the cluster name is part of the resource ID. | 2.35.0 | (fix) | `true` | +| @aws-cdk/aws-apigateway:disableCloudWatchRole | Make default CloudWatch Role behavior safe for multiple API Gateways in one environment | 2.38.0 | (fix) | `true` | +| @aws-cdk/core:enablePartitionLiterals | Make ARNs concrete if AWS partition is known | 2.38.0 | (fix) | `true` | +| @aws-cdk/aws-events:eventsTargetQueueSameAccount | Event Rules may only push to encrypted SQS queues in the same account | 2.51.0 | (fix) | `true` | + + + +## Feature flag details + +Here are more details about each of the flags: + + +### @aws-cdk/core:newStyleStackSynthesis + +Switch to new stack synthesis method which enables CI/CD (fix) + +If this flag is specified, all `Stack`s will use the `DefaultStackSynthesizer` by +default. If it is not set, they will use the `LegacyStackSynthesizer`. + +Introduced in **2.0.0**, recommended value `true`. + +### @aws-cdk/core:stackRelativeExports + +Name exports based on the construct paths relative to the stack, rather than the global construct path (fix) + +Combined with the stack name this relative construct path is good enough to +ensure uniqueness, and makes the export names robust against refactoring +the location of the stack in the construct tree (specifically, moving the Stack +into a Stage). + +Introduced in **2.0.0**, recommended value `true`. + +### @aws-cdk/aws-rds:lowercaseDbIdentifier + +Force lowercasing of RDS Cluster names in CDK (fix) + +Cluster names must be lowercase, and the service will lowercase the name when the cluster +is created. However, CDK did not use to know about this, and would use the user-provided name +referencing the cluster, which would fail if it happened to be mixed-case. + +With this flag, lowercase the name in CDK so we can reference it properly. + +Must be behind a permanent flag because changing a name from mixed case to lowercase between deployments +would lead CloudFormation to think the name was changed and would trigger a cluster replacement +(losing data!). + +Introduced in **2.0.0**, recommended value `true`. + +### @aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId + +Allow adding/removing multiple UsagePlanKeys independently (fix) + +The UsagePlanKey resource connects an ApiKey with a UsagePlan. API Gateway does not allow more than one UsagePlanKey +for any given UsagePlan and ApiKey combination. For this reason, CloudFormation cannot replace this resource without +either the UsagePlan or ApiKey changing. + +The feature addition to support multiple UsagePlanKey resources - 142bd0e2 - recognized this and attempted to keep +existing UsagePlanKey logical ids unchanged. +However, this intentionally caused the logical id of the UsagePlanKey to be sensitive to order. That is, when +the 'first' UsagePlanKey resource is removed, the logical id of the 'second' assumes what was originally the 'first', +which again is disallowed. + +In effect, there is no way to get out of this mess in a backwards compatible way, while supporting existing stacks. +This flag changes the logical id layout of UsagePlanKey to not be sensitive to order. + +Introduced in **2.0.0**, recommended value `true`. + +### @aws-cdk/aws-lambda:recognizeVersionProps + +Enable this feature flag to opt in to the updated logical id calculation for Lambda Version created using the `fn.currentVersion`. (fix) + +The previous calculation incorrectly considered properties of the `AWS::Lambda::Function` resource that did +not constitute creating a new Version. + +See 'currentVersion' section in the aws-lambda module's README for more details. + +Introduced in **2.0.0**, recommended value `true`. + +### @aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021 + +Enable this feature flag to have cloudfront distributions use the security policy TLSv1.2_2021 by default. (fix) + +The security policy can also be configured explicitly using the `minimumProtocolVersion` property. + +Introduced in **2.0.0**, recommended value `true`. + +### @aws-cdk/core:target-partitions + +What regions to include in lookup tables of environment agnostic stacks (config) + +Has no effect on stacks that have a defined region, but will limit the amount +of unnecessary regions included in stacks without a known region. + +The type of this value should be a list of strings. + +Introduced in **2.4.0**, recommended value `["aws","aws-cn"]`. + +### @aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver + +ECS extensions will automatically add an `awslogs` driver if no logging is specified (default) + +Enable this feature flag to configure default logging behavior for the ECS Service Extensions. This will enable the +`awslogs` log driver for the application container of the service to send the container logs to CloudWatch Logs. + +This is a feature flag as the new behavior provides a better default experience for the users. + +Introduced in **2.8.0**, recommended value `true`. + +### @aws-cdk/aws-ec2:uniqueImdsv2TemplateName + +Enable this feature flag to have Launch Templates generated by the `InstanceRequireImdsv2Aspect` use unique names. (fix) + +Previously, the generated Launch Template names were only unique within a stack because they were based only on the +`Instance` construct ID. If another stack that has an `Instance` with the same construct ID is deployed in the same +account and region, the deployments would always fail as the generated Launch Template names were the same. + +The new implementation addresses this issue by generating the Launch Template name with the `Names.uniqueId` method. + +Introduced in **2.8.0**, recommended value `true`. + +### @aws-cdk/aws-iam:minimizePolicies + +Minimize IAM policies by combining Statements (config) + +Minimize IAM policies by combining Principals, Actions and Resources of two +Statements in the policies, as long as it doesn't change the meaning of the +policy. + +Introduced in **2.18.0**, recommended value `true`. + +### @aws-cdk/core:checkSecretUsage + +Enable this flag to make it impossible to accidentally use SecretValues in unsafe locations (config) + +With this flag enabled, `SecretValue` instances can only be passed to +constructs that accept `SecretValue`s; otherwise, `unsafeUnwrap()` must be +called to use it as a regular string. + +Introduced in **2.21.0**, recommended value `true`. + +### @aws-cdk/aws-lambda:recognizeLayerVersion + +Enable this feature flag to opt in to the updated logical id calculation for Lambda Version created using the `fn.currentVersion`. (fix) + +This flag correct incorporates Lambda Layer properties into the Lambda Function Version. + +See 'currentVersion' section in the aws-lambda module's README for more details. + +Introduced in **2.27.0**, recommended value `true`. + +### @aws-cdk/core:validateSnapshotRemovalPolicy + +Error on snapshot removal policies on resources that do not support it. (default) + +Makes sure we do not allow snapshot removal policy on resources that do not support it. +If supplied on an unsupported resource, CloudFormation ignores the policy altogether. +This flag will reduce confusion and unexpected loss of data when erroneously supplying +the snapshot removal policy. + +Introduced in **2.28.0**, recommended value `true`. + +### @aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName + +Generate key aliases that include the stack name (fix) + +Enable this feature flag to have CodePipeline generate a unique cross account key alias name using the stack name. + +Previously, when creating multiple pipelines with similar naming conventions and when crossAccountKeys is true, +the KMS key alias name created for these pipelines may be the same due to how the uniqueId is generated. + +This new implementation creates a stack safe resource name for the alias using the stack name instead of the stack ID. + +Introduced in **2.29.0**, recommended value `true`. + +### @aws-cdk/aws-s3:createDefaultLoggingPolicy + +Enable this feature flag to create an S3 bucket policy by default in cases where an AWS service would automatically create the Policy if one does not exist. (fix) + +For example, in order to send VPC flow logs to an S3 bucket, there is a specific Bucket Policy +that needs to be attached to the bucket. If you create the bucket without a policy and then add the +bucket as the flow log destination, the service will automatically create the bucket policy with the +necessary permissions. If you were to then try and add your own bucket policy CloudFormation will throw +and error indicating that a bucket policy already exists. + +In cases where we know what the required policy is we can go ahead and create the policy so we can +remain in control of it. + +@see https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/AWS-logs-and-resource-policy.html#AWS-logs-infrastructure-S3 + +Introduced in **2.31.0**, recommended value `true`. + +### @aws-cdk/aws-sns-subscriptions:restrictSqsDescryption + +Restrict KMS key policy for encrypted Queues a bit more (fix) + +Enable this feature flag to restrict the decryption of a SQS queue, which is subscribed to a SNS topic, to +only the topic which it is subscribed to and not the whole SNS service of an account. + +Previously the decryption was only restricted to the SNS service principal. To make the SQS subscription more +secure, it is a good practice to restrict the decryption further and only allow the connected SNS topic to decryption +the subscribed queue. + +Introduced in **2.32.0**, recommended value `true`. + +### @aws-cdk/aws-ecs:arnFormatIncludesClusterName + +ARN format used by ECS. In the new ARN format, the cluster name is part of the resource ID. (fix) + +If this flag is not set, the old ARN format (without cluster name) for ECS is used. +If this flag is set, the new ARN format (with cluster name) for ECS is used. + +This is a feature flag as the old format is still valid for existing ECS clusters. + +See https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-account-settings.html#ecs-resource-ids + +Introduced in **2.35.0**, recommended value `true`. + +### @aws-cdk/aws-apigateway:disableCloudWatchRole + +Make default CloudWatch Role behavior safe for multiple API Gateways in one environment (fix) + +Enable this feature flag to change the default behavior for aws-apigateway.RestApi and aws-apigateway.SpecRestApi +to _not_ create a CloudWatch role and Account. There is only a single ApiGateway account per AWS +environment which means that each time you create a RestApi in your account the ApiGateway account +is overwritten. If at some point the newest RestApi is deleted, the ApiGateway Account and CloudWatch +role will also be deleted, breaking any existing ApiGateways that were depending on them. + +When this flag is enabled you should either create the ApiGateway account and CloudWatch role +separately _or_ only enable the cloudWatchRole on a single RestApi. + +Introduced in **2.38.0**, recommended value `true`. + +### @aws-cdk/core:enablePartitionLiterals + +Make ARNs concrete if AWS partition is known (fix) + +Enable this feature flag to get partition names as string literals in Stacks with known regions defined in +their environment, such as "aws" or "aws-cn". Previously the CloudFormation intrinsic function +"Ref: AWS::Partition" was used. For example: + +```yaml +Principal: + AWS: + Fn::Join: + - "" + - - "arn:" + - Ref: AWS::Partition + - :iam::123456789876:root +``` + +becomes: + +``` +Principal: + AWS: "arn:aws:iam::123456789876:root" +``` + +The intrinsic function will still be used in Stacks where no region is defined or the region's partition +is unknown. + +Introduced in **2.38.0**, recommended value `true`. + +### @aws-cdk/aws-events:eventsTargetQueueSameAccount + +Event Rules may only push to encrypted SQS queues in the same account (fix) + +This flag applies to SQS Queues that are used as the target of event Rules. When enabled, only principals +from the same account as the Queue can send messages. If a queue is unencrypted, this restriction will +always apply, regardless of the value of this flag. + +Introduced in **2.51.0**, recommended value `true`. + + + +## Currently recommended cdk.json + +The following json shows the current recommended set of flags, as `cdk init` would generate it for new projects. + + +```json +{ + "context": { + "@aws-cdk/aws-lambda:recognizeLayerVersion": true, + "@aws-cdk/core:checkSecretUsage": true, + "@aws-cdk/core:target-partitions": [ + "aws", + "aws-cn" + ], + "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, + "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, + "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, + "@aws-cdk/aws-iam:minimizePolicies": true, + "@aws-cdk/core:validateSnapshotRemovalPolicy": true, + "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, + "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, + "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, + "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, + "@aws-cdk/core:enablePartitionLiterals": true, + "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true + } +} +``` + + +## Flags removed in v2 + +These **default change** flags have been removed in v2. These used to be configurable in v1, but in v2 their +behavior has become the default. Remove these from your `cdk.json` file. + + + +| Flag | Summary | Type | Since | Value in v2 | +| ----- | ----- | ----- | ----- | ----- | +| @aws-cdk/core:enableStackNameDuplicates | Allow multiple stacks with the same name | (default) | 1.16.0 | `true` | +| aws-cdk:enableDiffNoFail | Make `cdk diff` not fail when there are differences | (default) | 1.19.0 | `true` | +| @aws-cdk/aws-ecr-assets:dockerIgnoreSupport | DockerImageAsset properly supports `.dockerignore` files by default | (default) | 1.73.0 | `true` | +| @aws-cdk/aws-secretsmanager:parseOwnedSecretName | Fix the referencing of SecretsManager names from ARNs | (default) | 1.77.0 | `true` | +| @aws-cdk/aws-kms:defaultKeyPolicies | Tighten default KMS key policies | (default) | 1.78.0 | `true` | +| @aws-cdk/aws-s3:grantWriteWithoutAcl | Remove `PutObjectAcl` from Bucket.grantWrite | (default) | 1.85.0 | `true` | +| @aws-cdk/aws-ecs-patterns:removeDefaultDesiredCount | Do not specify a default DesiredCount for ECS services | (default) | 1.92.0 | `true` | +| @aws-cdk/aws-efs:defaultEncryptionAtRest | Enable this feature flag to have elastic file systems encrypted at rest by default. | (default) | 1.98.0 | `true` | + + + +## Flags with a different default in v2 + +These **fix/deprecation** flags are still configurable in v2, but their default has changed compared to v1. If you +are migrating a v1 CDK project to v2, explicitly set any of these flags which does not currently appear in your +`cdk.json` to `false`, to avoid unexpected infrastructure changes. + + + +| Flag | Summary | Type | Since | v1 default | v2 default | +| ----- | ----- | ----- | ----- | ----- | ----- | +| @aws-cdk/core:newStyleStackSynthesis | Switch to new stack synthesis method which enables CI/CD | (fix) | 1.39.0 | `false` | `true` | +| @aws-cdk/core:stackRelativeExports | Name exports based on the construct paths relative to the stack, rather than the global construct path | (fix) | 1.58.0 | `false` | `true` | +| @aws-cdk/aws-rds:lowercaseDbIdentifier | Force lowercasing of RDS Cluster names in CDK | (fix) | 1.97.0 | `false` | `true` | +| @aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId | Allow adding/removing multiple UsagePlanKeys independently | (fix) | 1.98.0 | `false` | `true` | +| @aws-cdk/aws-lambda:recognizeVersionProps | Enable this feature flag to opt in to the updated logical id calculation for Lambda Version created using the `fn.currentVersion`. | (fix) | 1.106.0 | `false` | `true` | +| @aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021 | Enable this feature flag to have cloudfront distributions use the security policy TLSv1.2_2021 by default. | (fix) | 1.117.0 | `false` | `true` | + + + +Here is an example of a `cdk.json` file that restores v1 behavior for these flags: + + +```json +{ + "context": { + "@aws-cdk/core:newStyleStackSynthesis": false, + "@aws-cdk/core:stackRelativeExports": false, + "@aws-cdk/aws-rds:lowercaseDbIdentifier": false, + "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": false, + "@aws-cdk/aws-lambda:recognizeVersionProps": false, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": false + } +} +``` + \ No newline at end of file diff --git a/packages/@aws-cdk/cx-api/build-tools/flag-report.ts b/packages/@aws-cdk/cx-api/build-tools/flag-report.ts new file mode 100644 index 0000000000000..002086e36ed6b --- /dev/null +++ b/packages/@aws-cdk/cx-api/build-tools/flag-report.ts @@ -0,0 +1,166 @@ +import { promises as fs } from 'fs'; +import * as path from 'path'; +import * as feats from '../lib/features'; +import { FlagInfo, FlagType } from '../lib/private/flag-modeling'; + +async function main() { + await updateMarkdownFile(path.join(__dirname, '..', 'FEATURE_FLAGS.md'), { + table: flagsTable(), + details: flagsDetails(), + json: recommendedJson(), + removed: removedFlags(), + diff: changedFlags(), + migratejson: migrateJson(), + }); +} + +function flagsTable() { + return renderTable([ + ['Flag', 'Summary', 'Since', 'Type', 'Recommended'], + ...v2flags().map(([name, flag]) => + [name, flag.summary, flag.introducedIn.v2 ?? '', renderType(flag.type), '`' + JSON.stringify(flag.recommendedValue) + '`'], + ), + ]); +} + +function removedFlags() { + const removedInV2 = flags(flag => flag.introducedIn.v2 === undefined && flag.introducedIn.v1 !== undefined); + + return renderTable([ + ['Flag', 'Summary', 'Type', 'Since', 'Value in v2'], + ...removedInV2.map(([name, flag]) => + [name, flag.summary, renderType(flag.type), flag.introducedIn.v1 ?? '', renderValue(flag.defaults?.v2)], + ), + ]); +} + +function changedFlags() { + const changedInV2 = flags(flag => !!flag.defaults?.v2 && !!flag.introducedIn.v2); + + return renderTable([ + ['Flag', 'Summary', 'Type', 'Since', 'v1 default', 'v2 default'], + ...changedInV2.map(([name, flag]) => + [name, flag.summary, renderType(flag.type), flag.introducedIn.v1 ?? '', renderValue(false), renderValue(flag.defaults?.v2)], + ), + ]); +} + +function migrateJson() { + const changedInV2 = flags(flag => !!flag.defaults?.v2 && !!flag.introducedIn.v2); + + const context = Object.fromEntries(changedInV2.map(([name, _]) => [name, false])); + + return [ + '```json', + JSON.stringify({ context }, undefined, 2), + '```', + ].join('\n'); +} + +function flagsDetails() { + return v2flags().flatMap(([name, flag]) => [ + `### ${name}`, + '', + `${flag.summary} ${renderType(flag.type)}`, + '', + dedent(flag.details), + '', + `Introduced in **${flag.introducedIn.v2}**, recommended value ${renderValue(flag.recommendedValue)}.`, + '', + ]).join('\n'); +} + +function recommendedJson() { + return [ + '```json', + JSON.stringify({ context: feats.NEW_PROJECT_CONTEXT }, undefined, 2), + '```', + ].join('\n'); +} + +function v2flags() { + return flags(flag => flag.introducedIn.v2 !== undefined); +} + +function flags(pred: (x: FlagInfo) => boolean) { + const entries = Object.entries(feats.FLAGS) + .filter(([_, flag]) => pred(flag)); + + entries.sort((a, b) => firstCmp( + // Sort by versions first + cmpVersions(a[1].introducedIn.v2, b[1].introducedIn.v2), + cmpVersions(a[1].introducedIn.v1, b[1].introducedIn.v1), + // Then sort by name + a[0].localeCompare(b[0]))); + + return entries; +} + +function renderType(type: FlagType): string { + switch (type) { + case FlagType.ApiDefault: return '(default)'; + case FlagType.BugFix: return '(fix)'; + case FlagType.VisibleContext: return '(config)'; + } +} + +function renderTable(rows: string[][]) { + return [ + '', + '| ' + rows[0].join(' | ') + ' |', + '| ' + rows[0].map(_ => '-----').join(' | ') + ' |', + ...rows.slice(1).map(row => '| ' + row.join(' | ') + ' |'), + '', + ].join('\n'); +} + +/** + * Remove shared leading whitespace from all non-empty lines + */ +function dedent(body: string) { + const lines = body.split('\n').filter((x) => x.trim() !== ''); + const leadingWs = lines.map(x => x.match(/^ */)?.[0].length ?? 0); + const sharedWs = Math.min(...leadingWs); + const re = new RegExp('^' + ' '.repeat(sharedWs), 'mg'); + return body.replace(re, '').trim(); +} + +function renderValue(x: any) { + return `\`${JSON.stringify(x)}\``; +} + +async function updateMarkdownFile(filename: string, sections: Record) { + let contents = await fs.readFile(filename, { encoding: 'utf-8' }); + + for (const [section, value] of Object.entries(sections)) { + const re = new RegExp(`(.*)`, 's'); + contents = contents.replace(re, `\n${value}\n`); + } + + await fs.writeFile(filename, contents, { encoding: 'utf-8' }); +} + +function cmpVersions(a: string | undefined, b: string | undefined): number { + if (a === undefined && b === undefined) { return 0; } + if (a === undefined) { return -1; } + if (b === undefined) { return 1; } + + const as = a.split('.').map(x => parseInt(x, 10)); + const bs = b.split('.').map(x => parseInt(x, 10)); + + for (let i = 0; i < Math.min(as.length, bs.length); i++) { + if (as[i] < bs[i]) { return -1; } + if (as[i] > bs[i]) { return 1; } + } + return as.length - bs.length; +} + +function firstCmp(...xs: number[]) { + return xs.find(x => x !== 0) ?? 0; +} + +main().catch(e => { + // eslint-disable-next-line no-console + console.error(e); + process.exitCode = 1; +}); \ No newline at end of file diff --git a/packages/@aws-cdk/cx-api/lib/features.ts b/packages/@aws-cdk/cx-api/lib/features.ts index a17dfa5f3212b..c4d03eacd0e13 100644 --- a/packages/@aws-cdk/cx-api/lib/features.ts +++ b/packages/@aws-cdk/cx-api/lib/features.ts @@ -1,3 +1,5 @@ +import { FlagInfo, FlagType } from './private/flag-modeling'; + // -------------------------------------------------------------------------------- // This file defines context keys that enable certain features that are // implemented behind a flag in order to preserve backwards compatibility for @@ -5,359 +7,514 @@ // automatically add enable these features by adding them to the generated // `cdk.json` file. // -// Some of these flags only affect the behavior of the construct library -- -// these will be removed in the next major release and the behavior they are -// gating will become the only behavior. +// There are three types of flags: ApiDefault, BugFix, and VisibleContext flags. +// +// - ApiDefault flags: change the behavior or defaults of the construct library. When +// set, the infrastructure that is generated may be different but there is +// a way to get the old infrastructure setup by using the API in a different way. +// +// - BugFix flags: the old infra we used to generate is no longer recommended, +// and there is no way to achieve that result anymore except by making sure the +// flag is unset, or set to `false`. Mostly used for infra-impacting bugfixes or +// enhanced security defaults. // -// Other flags also affect the generated CloudFormation templates, in a way -// that prevents seamless upgrading. In the next major version, their -// behavior will become the default, but the flag still exists so users can -// switch it *off* in order to revert to the old behavior. These flags -// are marked with with the [PERMANENT] tag below. +// - VisibleContext flags: not really a feature flag, but configurable context which is +// advertised by putting the context in the `cdk.json` file of new projects. +// +// In future major versions, the "newProjectValues" will become the version +// default for both DefaultBehavior and BugFix flags, and DefaultBehavior flags +// will be removed (i.e., their new behavior will become the *only* behavior). // // See https://github.com/aws/aws-cdk-rfcs/blob/master/text/0055-feature-flags.md // -------------------------------------------------------------------------------- -/** - * If this is set, multiple stacks can use the same stack name (e.g. deployed to - * different environments). This means that the name of the synthesized template - * file will be based on the construct path and not on the defined `stackName` - * of the stack. - * - * This is a "future flag": the feature is disabled by default for backwards - * compatibility, but new projects created using `cdk init` will have this - * enabled through the generated `cdk.json`. - */ -export const ENABLE_STACK_NAME_DUPLICATES_CONTEXT = '@aws-cdk/core:enableStackNameDuplicates'; -/** - * Determines what status code `cdk diff` should return when the specified stack - * differs from the deployed stack or the local CloudFormation template: - * - * * aws-cdk:enableDiffNoFail=true => status code == 0 - * * aws-cdk:enableDiffNoFail=false => status code == 1 - * - * You can override this behavior with the --fail flag: - * - * * --fail => status code == 1 - * * --no-fail => status code == 0 - */ +export const ENABLE_STACK_NAME_DUPLICATES_CONTEXT = '@aws-cdk/core:enableStackNameDuplicates'; export const ENABLE_DIFF_NO_FAIL_CONTEXT = 'aws-cdk:enableDiffNoFail'; /** @deprecated use `ENABLE_DIFF_NO_FAIL_CONTEXT` */ export const ENABLE_DIFF_NO_FAIL = ENABLE_DIFF_NO_FAIL_CONTEXT; - -/** - * Switch to new stack synthesis method which enable CI/CD - * - * [PERMANENT] - */ export const NEW_STYLE_STACK_SYNTHESIS_CONTEXT = '@aws-cdk/core:newStyleStackSynthesis'; - -/** - * Name exports based on the construct paths relative to the stack, rather than the global construct path - * - * Combined with the stack name this relative construct path is good enough to - * ensure uniqueness, and makes the export names robust against refactoring - * the location of the stack in the construct tree (specifically, moving the Stack - * into a Stage). - * - * [PERMANENT] - */ export const STACK_RELATIVE_EXPORTS_CONTEXT = '@aws-cdk/core:stackRelativeExports'; - -/** - * DockerImageAsset properly supports `.dockerignore` files by default - * - * If this flag is not set, the default behavior for `DockerImageAsset` is to use - * glob semantics for `.dockerignore` files. If this flag is set, the default behavior - * is standard Docker ignore semantics. - * - * This is a feature flag as the old behavior was technically incorrect but - * users may have come to depend on it. - */ export const DOCKER_IGNORE_SUPPORT = '@aws-cdk/aws-ecr-assets:dockerIgnoreSupport'; - -/** - * Secret.secretName for an "owned" secret will attempt to parse the secretName from the ARN, - * rather than the default full resource name, which includes the SecretsManager suffix. - * - * If this flag is not set, Secret.secretName will include the SecretsManager suffix, which cannot be directly - * used by SecretsManager.DescribeSecret, and must be parsed by the user first (e.g., Fn:Join, Fn:Select, Fn:Split). - */ export const SECRETS_MANAGER_PARSE_OWNED_SECRET_NAME = '@aws-cdk/aws-secretsmanager:parseOwnedSecretName'; - -/** - * KMS Keys start with a default key policy that grants the account access to administer the key, - * mirroring the behavior of the KMS SDK/CLI/Console experience. Users may override the default key - * policy by specifying their own. - * - * If this flag is not set, the default key policy depends on the setting of the `trustAccountIdentities` - * flag. If false (the default, for backwards-compatibility reasons), the default key policy somewhat - * resemebles the default admin key policy, but with the addition of 'GenerateDataKey' permissions. If - * true, the policy matches what happens when this feature flag is set. - * - * Additionally, if this flag is not set and the user supplies a custom key policy, this will be appended - * to the key's default policy (rather than replacing it). - */ export const KMS_DEFAULT_KEY_POLICIES = '@aws-cdk/aws-kms:defaultKeyPolicies'; - -/** - * Change the old 's3:PutObject*' permission to 's3:PutObject' on Bucket, - * as the former includes 's3:PutObjectAcl', - * which could be used to grant read/write object access to IAM principals in other accounts. - * Use a feature flag to make sure existing customers who might be relying - * on the overly-broad permissions are not broken. - */ export const S3_GRANT_WRITE_WITHOUT_ACL = '@aws-cdk/aws-s3:grantWriteWithoutAcl'; - -/** - * ApplicationLoadBalancedServiceBase, ApplicationMultipleTargetGroupServiceBase, - * NetworkLoadBalancedServiceBase, NetworkMultipleTargetGroupServiceBase, and - * QueueProcessingServiceBase currently determine a default value for the desired count of - * a CfnService if a desiredCount is not provided. - * - * If this flag is not set, the default behaviour for CfnService.desiredCount is to set a - * desiredCount of 1, if one is not provided. If true, a default will not be defined for - * CfnService.desiredCount and as such desiredCount will be undefined, if one is not provided. - * - * This is a feature flag as the old behavior was technically incorrect, but - * users may have come to depend on it. - */ export const ECS_REMOVE_DEFAULT_DESIRED_COUNT = '@aws-cdk/aws-ecs-patterns:removeDefaultDesiredCount'; - -/** - * ServerlessCluster.clusterIdentifier currently can has uppercase letters, - * and ServerlessCluster pass it through to CfnDBCluster.dbClusterIdentifier. - * The identifier is saved as lowercase string in AWS and is resolved as original string in CloudFormation. - * - * If this flag is not set, original value that one set to ServerlessCluster.clusterIdentifier - * is passed to CfnDBCluster.dbClusterIdentifier. - * If this flag is true, ServerlessCluster.clusterIdentifier is converted into a string containing - * only lowercase characters by the `toLowerCase` function and passed to CfnDBCluster.dbClusterIdentifier. - * - * This feature flag make correct the ServerlessCluster.clusterArn when - * clusterIdentifier contains a Upper case letters. - * - * [PERMANENT] - */ export const RDS_LOWERCASE_DB_IDENTIFIER = '@aws-cdk/aws-rds:lowercaseDbIdentifier'; - -/** - * The UsagePlanKey resource connects an ApiKey with a UsagePlan. API Gateway does not allow more than one UsagePlanKey - * for any given UsagePlan and ApiKey combination. For this reason, CloudFormation cannot replace this resource without - * either the UsagePlan or ApiKey changing. - * - * The feature addition to support multiple UsagePlanKey resources - 142bd0e2 - recognized this and attempted to keep - * existing UsagePlanKey logical ids unchanged. - * However, this intentionally caused the logical id of the UsagePlanKey to be sensitive to order. That is, when - * the 'first' UsagePlanKey resource is removed, the logical id of the 'second' assumes what was originally the 'first', - * which again is disallowed. - * - * In effect, there is no way to get out of this mess in a backwards compatible way, while supporting existing stacks. - * This flag changes the logical id layout of UsagePlanKey to not be sensitive to order. - * - * [PERMANENT] - */ export const APIGATEWAY_USAGEPLANKEY_ORDERINSENSITIVE_ID = '@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId'; - -/** - * Enable this feature flag to have elastic file systems encrypted at rest by default. - * - * Encryption can also be configured explicitly using the `encrypted` property. - */ export const EFS_DEFAULT_ENCRYPTION_AT_REST = '@aws-cdk/aws-efs:defaultEncryptionAtRest'; - -/** - * Enable this feature flag to opt in to the updated logical id calculation for Lambda Version created using the - * `fn.currentVersion`. - * - * The previous calculation incorrectly considered properties of the `AWS::Lambda::Function` resource that did - * not constitute creating a new Version. - * - * See 'currentVersion' section in the aws-lambda module's README for more details. - * - * [PERMANENT] - */ export const LAMBDA_RECOGNIZE_VERSION_PROPS = '@aws-cdk/aws-lambda:recognizeVersionProps'; - -/** - * Enable this feature flag to opt in to the updated logical id calculation for Lambda Version created using the - * `fn.currentVersion`. - * - * This flag correct incorporates Lambda Layer properties into the Lambda Function Version. - * - * See 'currentVersion' section in the aws-lambda module's README for more details. - * - * [PERMANENT] - */ export const LAMBDA_RECOGNIZE_LAYER_VERSION = '@aws-cdk/aws-lambda:recognizeLayerVersion'; - -/** - * Enable this feature flag to have cloudfront distributions use the security policy TLSv1.2_2021 by default. - * - * The security policy can also be configured explicitly using the `minimumProtocolVersion` property. - * - * [PERMANENT] - */ export const CLOUDFRONT_DEFAULT_SECURITY_POLICY_TLS_V1_2_2021 = '@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021'; - -/** - * Enable this flag to make it impossible to accidentally use SecretValues in unsafe locations - * - * With this flag enabled, `SecretValue` instances can only be passed to - * constructs that accept `SecretValue`s; otherwise, `unsafeUnwrap()` must be - * called to use it as a regular string. - */ export const CHECK_SECRET_USAGE = '@aws-cdk/core:checkSecretUsage'; - -/** - * What regions to include in lookup tables of environment agnostic stacks - * - * Has no effect on stacks that have a defined region, but will limit the amount - * of unnecessary regions included in stacks without a known region. - * - * The type of this value should be a list of strings. - * - * [PERMANENT] - */ export const TARGET_PARTITIONS = '@aws-cdk/core:target-partitions'; - -/** - * Enable this feature flag to configure default logging behavior for the ECS Service Extensions. This will enable the - * `awslogs` log driver for the application container of the service to send the container logs to CloudWatch Logs. - * - * This is a feature flag as the new behavior provides a better default experience for the users. - * - * [PERMANENT] - */ export const ECS_SERVICE_EXTENSIONS_ENABLE_DEFAULT_LOG_DRIVER = '@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver'; - -/** - * Enable this feature flag to have Launch Templates generated by the `InstanceRequireImdsv2Aspect` use unique names. - * - * Previously, the generated Launch Template names were only unique within a stack because they were based only on the - * `Instance` construct ID. If another stack that has an `Instance` with the same construct ID is deployed in the same - * account and region, the deployments would always fail as the generated Launch Template names were the same. - * - * The new implementation addresses this issue by generating the Launch Template name with the `Names.uniqueId` method. - */ export const EC2_UNIQUE_IMDSV2_LAUNCH_TEMPLATE_NAME = '@aws-cdk/aws-ec2:uniqueImdsv2TemplateName'; - -/** - * ARN format used by ECS. In the new ARN format, the cluster name is part - * of the resource ID. - * - * If this flag is not set, the old ARN format (without cluster name) for ECS is used. - * If this flag is set, the new ARN format (with cluster name) for ECS is used. - * - * This is a feature flag as the old format is still valid for existing ECS clusters. - * - * @see https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-account-settings.html#ecs-resource-ids - */ export const ECS_ARN_FORMAT_INCLUDES_CLUSTER_NAME = '@aws-cdk/aws-ecs:arnFormatIncludesClusterName'; - -/** - * Minimize IAM policies by combining Principals, Actions and Resources of two - * Statements in the policies, as long as it doesn't change the meaning of the - * policy. - * - * [PERMANENT] - */ export const IAM_MINIMIZE_POLICIES = '@aws-cdk/aws-iam:minimizePolicies'; - -/** - * Makes sure we do not allow snapshot removal policy on resources that do not support it. - * If supplied on an unsupported resource, CloudFormation ignores the policy altogether. - * This flag will reduce confusion and unexpected loss of data when erroneously supplying - * the snapshot removal policy. - * - * [PERMANENT] - */ export const VALIDATE_SNAPSHOT_REMOVAL_POLICY = '@aws-cdk/core:validateSnapshotRemovalPolicy'; - -/** - * Enable this feature flag to have CodePipeline generate a unique cross account key alias name using the stack name. - * - * Previously, when creating multiple pipelines with similar naming conventions and when crossAccountKeys is true, - * the KMS key alias name created for these pipelines may be the same due to how the uniqueId is generated. - * - * This new implementation creates a stack safe resource name for the alias using the stack name instead of the stack ID. - */ export const CODEPIPELINE_CROSS_ACCOUNT_KEY_ALIAS_STACK_SAFE_RESOURCE_NAME = '@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName'; - -/** - * Enable this feature flag to create an S3 bucket policy by default in cases where - * an AWS service would automatically create the Policy if one does not exist. - * - * For example, in order to send VPC flow logs to an S3 bucket, there is a specific Bucket Policy - * that needs to be attached to the bucket. If you create the bucket without a policy and then add the - * bucket as the flow log destination, the service will automatically create the bucket policy with the - * necessary permissions. If you were to then try and add your own bucket policy CloudFormation will throw - * and error indicating that a bucket policy already exists. - * - * In cases where we know what the required policy is we can go ahead and create the policy so we can - * remain in control of it. - * - * @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/AWS-logs-and-resource-policy.html#AWS-logs-infrastructure-S3 - */ export const S3_CREATE_DEFAULT_LOGGING_POLICY = '@aws-cdk/aws-s3:createDefaultLoggingPolicy'; - -/** -* Enable this feature flag to restrict the decryption of a SQS queue, which is subscribed to a SNS topic, to -* only the topic which it is subscribed to and not the whole SNS service of an account. -* -* Previously the decryption was only restricted to the SNS service principal. To make the SQS subscription more -* secure, it is a good practice to restrict the decryption further and only allow the connected SNS topic to decryption -* the subscribed queue. -* -*/ export const SNS_SUBSCRIPTIONS_SQS_DECRYPTION_POLICY = '@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption'; - -/** - * Enable this feature flag to change the default behavior for aws-apigateway.RestApi and aws-apigateway.SpecRestApi - * to _not_ create a CloudWatch role and Account. There is only a single ApiGateway account per AWS - * environment which means that each time you create a RestApi in your account the ApiGateway account - * is overwritten. If at some point the newest RestApi is deleted, the ApiGateway Account and CloudWatch - * role will also be deleted, breaking any existing ApiGateways that were depending on them. - * - * When this flag is enabled you should either create the ApiGateway account and CloudWatch role - * separately _or_ only enable the cloudWatchRole on a single RestApi. - */ export const APIGATEWAY_DISABLE_CLOUDWATCH_ROLE = '@aws-cdk/aws-apigateway:disableCloudWatchRole'; - -/** - * Enable this feature flag to get partition names as string literals in Stacks with known regions defined in - * their environment, such as "aws" or "aws-cn". Previously the CloudFormation intrinsic function - * "Ref: AWS::Partition" was used. For example: - * - * ```yaml - * Principal: - * AWS: - * Fn::Join: - * - "" - * - - "arn:" - * - Ref: AWS::Partition - * - :iam::123456789876:root - * ``` - * - * becomes: - * - * ``` - * Principal: - * AWS: "arn:aws:iam::123456789876:root" - * ``` - * - * The intrinsic function will still be used in Stacks where no region is defined or the region's partition - * is unknown. - */ export const ENABLE_PARTITION_LITERALS = '@aws-cdk/core:enablePartitionLiterals'; +export const EVENTS_TARGET_QUEUE_SAME_ACCOUNT = '@aws-cdk/aws-events:eventsTargetQueueSameAccount'; + +export const FLAGS: Record = { + ////////////////////////////////////////////////////////////////////// + [ENABLE_STACK_NAME_DUPLICATES_CONTEXT]: { + type: FlagType.ApiDefault, + summary: 'Allow multiple stacks with the same name', + details: ` + If this is set, multiple stacks can use the same stack name (e.g. deployed to + different environments). This means that the name of the synthesized template + file will be based on the construct path and not on the defined \`stackName\` + of the stack.`, + recommendedValue: true, + introducedIn: { v1: '1.16.0' }, + defaults: { v2: true }, + }, + + ////////////////////////////////////////////////////////////////////// + [ENABLE_DIFF_NO_FAIL_CONTEXT]: { + type: FlagType.ApiDefault, + summary: 'Make `cdk diff` not fail when there are differences', + details: ` + Determines what status code \`cdk diff\` should return when the specified stack + differs from the deployed stack or the local CloudFormation template: + + * \`aws-cdk:enableDiffNoFail=true\` => status code == 0 + * \`aws-cdk:enableDiffNoFail=false\` => status code == 1 + + You can override this behavior with the --fail flag: + + * \`--fail\` => status code == 1 + * \`--no-fail\` => status code == 0`, + introducedIn: { v1: '1.19.0' }, + defaults: { v2: true }, + recommendedValue: true, + }, + + ////////////////////////////////////////////////////////////////////// + [NEW_STYLE_STACK_SYNTHESIS_CONTEXT]: { + type: FlagType.BugFix, + summary: 'Switch to new stack synthesis method which enables CI/CD', + details: ` + If this flag is specified, all \`Stack\`s will use the \`DefaultStackSynthesizer\` by + default. If it is not set, they will use the \`LegacyStackSynthesizer\`.`, + introducedIn: { v1: '1.39.0', v2: '2.0.0' }, + defaults: { v2: true }, + recommendedValue: true, + }, + + ////////////////////////////////////////////////////////////////////// + [STACK_RELATIVE_EXPORTS_CONTEXT]: { + type: FlagType.BugFix, + summary: 'Name exports based on the construct paths relative to the stack, rather than the global construct path', + details: ` + Combined with the stack name this relative construct path is good enough to + ensure uniqueness, and makes the export names robust against refactoring + the location of the stack in the construct tree (specifically, moving the Stack + into a Stage).`, + introducedIn: { v1: '1.58.0', v2: '2.0.0' }, + defaults: { v2: true }, + recommendedValue: true, + }, + + ////////////////////////////////////////////////////////////////////// + [DOCKER_IGNORE_SUPPORT]: { + type: FlagType.ApiDefault, + summary: 'DockerImageAsset properly supports `.dockerignore` files by default', + details: ` + If this flag is not set, the default behavior for \`DockerImageAsset\` is to use + glob semantics for \`.dockerignore\` files. If this flag is set, the default behavior + is standard Docker ignore semantics. + + This is a feature flag as the old behavior was technically incorrect but + users may have come to depend on it.`, + introducedIn: { v1: '1.73.0' }, + defaults: { v2: true }, + recommendedValue: true, + }, + + ////////////////////////////////////////////////////////////////////// + [SECRETS_MANAGER_PARSE_OWNED_SECRET_NAME]: { + type: FlagType.ApiDefault, + summary: 'Fix the referencing of SecretsManager names from ARNs', + details: ` + Secret.secretName for an "owned" secret will attempt to parse the secretName from the ARN, + rather than the default full resource name, which includes the SecretsManager suffix. + + If this flag is not set, Secret.secretName will include the SecretsManager suffix, which cannot be directly + used by SecretsManager.DescribeSecret, and must be parsed by the user first (e.g., Fn:Join, Fn:Select, Fn:Split).`, + introducedIn: { v1: '1.77.0' }, + defaults: { v2: true }, + recommendedValue: true, + }, + + ////////////////////////////////////////////////////////////////////// + [KMS_DEFAULT_KEY_POLICIES]: { + type: FlagType.ApiDefault, + summary: 'Tighten default KMS key policies', + details: ` + KMS Keys start with a default key policy that grants the account access to administer the key, + mirroring the behavior of the KMS SDK/CLI/Console experience. Users may override the default key + policy by specifying their own. + + If this flag is not set, the default key policy depends on the setting of the \`trustAccountIdentities\` + flag. If false (the default, for backwards-compatibility reasons), the default key policy somewhat + resembles the default admin key policy, but with the addition of 'GenerateDataKey' permissions. If + true, the policy matches what happens when this feature flag is set. + + Additionally, if this flag is not set and the user supplies a custom key policy, this will be appended + to the key's default policy (rather than replacing it).`, + introducedIn: { v1: '1.78.0' }, + defaults: { v2: true }, + recommendedValue: true, + }, + + ////////////////////////////////////////////////////////////////////// + [S3_GRANT_WRITE_WITHOUT_ACL]: { + type: FlagType.ApiDefault, + summary: 'Remove `PutObjectAcl` from Bucket.grantWrite', + details: ` + Change the old 's3:PutObject*' permission to 's3:PutObject' on Bucket, + as the former includes 's3:PutObjectAcl', + which could be used to grant read/write object access to IAM principals in other accounts. + Use a feature flag to make sure existing customers who might be relying + on the overly-broad permissions are not broken.`, + introducedIn: { v1: '1.85.0' }, + defaults: { v2: true }, + recommendedValue: true, + }, + + ////////////////////////////////////////////////////////////////////// + [ECS_REMOVE_DEFAULT_DESIRED_COUNT]: { + type: FlagType.ApiDefault, + summary: 'Do not specify a default DesiredCount for ECS services', + details: ` + ApplicationLoadBalancedServiceBase, ApplicationMultipleTargetGroupServiceBase, + NetworkLoadBalancedServiceBase, NetworkMultipleTargetGroupServiceBase, and + QueueProcessingServiceBase currently determine a default value for the desired count of + a CfnService if a desiredCount is not provided. The result of this is that on every + deployment, the service count is reset to the fixed value, even if it was autoscaled. + + If this flag is not set, the default behaviour for CfnService.desiredCount is to set a + desiredCount of 1, if one is not provided. If true, a default will not be defined for + CfnService.desiredCount and as such desiredCount will be undefined, if one is not provided.`, + introducedIn: { v1: '1.92.0' }, + defaults: { v2: true }, + recommendedValue: true, + }, + + ////////////////////////////////////////////////////////////////////// + [RDS_LOWERCASE_DB_IDENTIFIER]: { + type: FlagType.BugFix, + summary: 'Force lowercasing of RDS Cluster names in CDK', + details: ` + Cluster names must be lowercase, and the service will lowercase the name when the cluster + is created. However, CDK did not use to know about this, and would use the user-provided name + referencing the cluster, which would fail if it happened to be mixed-case. + + With this flag, lowercase the name in CDK so we can reference it properly. + + Must be behind a permanent flag because changing a name from mixed case to lowercase between deployments + would lead CloudFormation to think the name was changed and would trigger a cluster replacement + (losing data!).`, + introducedIn: { v1: '1.97.0', v2: '2.0.0' }, + defaults: { v2: true }, + recommendedValue: true, + }, + + ////////////////////////////////////////////////////////////////////// + [APIGATEWAY_USAGEPLANKEY_ORDERINSENSITIVE_ID]: { + type: FlagType.BugFix, + summary: 'Allow adding/removing multiple UsagePlanKeys independently', + details: ` + The UsagePlanKey resource connects an ApiKey with a UsagePlan. API Gateway does not allow more than one UsagePlanKey + for any given UsagePlan and ApiKey combination. For this reason, CloudFormation cannot replace this resource without + either the UsagePlan or ApiKey changing. + + The feature addition to support multiple UsagePlanKey resources - 142bd0e2 - recognized this and attempted to keep + existing UsagePlanKey logical ids unchanged. + However, this intentionally caused the logical id of the UsagePlanKey to be sensitive to order. That is, when + the 'first' UsagePlanKey resource is removed, the logical id of the 'second' assumes what was originally the 'first', + which again is disallowed. + + In effect, there is no way to get out of this mess in a backwards compatible way, while supporting existing stacks. + This flag changes the logical id layout of UsagePlanKey to not be sensitive to order.`, + introducedIn: { v1: '1.98.0', v2: '2.0.0' }, + defaults: { v2: true }, + recommendedValue: true, + }, + + ////////////////////////////////////////////////////////////////////// + [EFS_DEFAULT_ENCRYPTION_AT_REST]: { + type: FlagType.ApiDefault, + summary: 'Enable this feature flag to have elastic file systems encrypted at rest by default.', + details: ` + Encryption can also be configured explicitly using the \`encrypted\` property. + `, + introducedIn: { v1: '1.98.0' }, + defaults: { v2: true }, + recommendedValue: true, + }, + + ////////////////////////////////////////////////////////////////////// + [LAMBDA_RECOGNIZE_VERSION_PROPS]: { + type: FlagType.BugFix, + summary: 'Enable this feature flag to opt in to the updated logical id calculation for Lambda Version created using the `fn.currentVersion`.', + details: ` + The previous calculation incorrectly considered properties of the \`AWS::Lambda::Function\` resource that did + not constitute creating a new Version. + + See 'currentVersion' section in the aws-lambda module's README for more details.`, + introducedIn: { v1: '1.106.0', v2: '2.0.0' }, + defaults: { v2: true }, + recommendedValue: true, + }, + + ////////////////////////////////////////////////////////////////////// + [LAMBDA_RECOGNIZE_LAYER_VERSION]: { + type: FlagType.BugFix, + summary: 'Enable this feature flag to opt in to the updated logical id calculation for Lambda Version created using the `fn.currentVersion`.', + details: ` + This flag correct incorporates Lambda Layer properties into the Lambda Function Version. + + See 'currentVersion' section in the aws-lambda module's README for more details.`, + introducedIn: { v1: '1.159.0', v2: '2.27.0' }, + recommendedValue: true, + }, + + ////////////////////////////////////////////////////////////////////// + [CLOUDFRONT_DEFAULT_SECURITY_POLICY_TLS_V1_2_2021]: { + type: FlagType.BugFix, + summary: 'Enable this feature flag to have cloudfront distributions use the security policy TLSv1.2_2021 by default.', + details: ` + The security policy can also be configured explicitly using the \`minimumProtocolVersion\` property.`, + introducedIn: { v1: '1.117.0', v2: '2.0.0' }, + defaults: { v2: true }, + recommendedValue: true, + }, + + ////////////////////////////////////////////////////////////////////// + [CHECK_SECRET_USAGE]: { + type: FlagType.VisibleContext, + summary: 'Enable this flag to make it impossible to accidentally use SecretValues in unsafe locations', + details: ` + With this flag enabled, \`SecretValue\` instances can only be passed to + constructs that accept \`SecretValue\`s; otherwise, \`unsafeUnwrap()\` must be + called to use it as a regular string.`, + introducedIn: { v1: '1.153.0', v2: '2.21.0' }, + recommendedValue: true, + }, + + ////////////////////////////////////////////////////////////////////// + [TARGET_PARTITIONS]: { + type: FlagType.VisibleContext, + summary: 'What regions to include in lookup tables of environment agnostic stacks', + details: ` + Has no effect on stacks that have a defined region, but will limit the amount + of unnecessary regions included in stacks without a known region. + + The type of this value should be a list of strings.`, + introducedIn: { v1: '1.137.0', v2: '2.4.0' }, + recommendedValue: ['aws', 'aws-cn'], + }, + + ////////////////////////////////////////////////////////////////////// + [ECS_SERVICE_EXTENSIONS_ENABLE_DEFAULT_LOG_DRIVER]: { + type: FlagType.ApiDefault, + summary: 'ECS extensions will automatically add an `awslogs` driver if no logging is specified', + details: ` + Enable this feature flag to configure default logging behavior for the ECS Service Extensions. This will enable the + \`awslogs\` log driver for the application container of the service to send the container logs to CloudWatch Logs. + + This is a feature flag as the new behavior provides a better default experience for the users.`, + introducedIn: { v1: '1.140.0', v2: '2.8.0' }, + recommendedValue: true, + }, + + ////////////////////////////////////////////////////////////////////// + [EC2_UNIQUE_IMDSV2_LAUNCH_TEMPLATE_NAME]: { + type: FlagType.BugFix, + summary: 'Enable this feature flag to have Launch Templates generated by the `InstanceRequireImdsv2Aspect` use unique names.', + details: ` + Previously, the generated Launch Template names were only unique within a stack because they were based only on the + \`Instance\` construct ID. If another stack that has an \`Instance\` with the same construct ID is deployed in the same + account and region, the deployments would always fail as the generated Launch Template names were the same. + + The new implementation addresses this issue by generating the Launch Template name with the \`Names.uniqueId\` method.`, + introducedIn: { v1: '1.140.0', v2: '2.8.0' }, + recommendedValue: true, + }, + + ////////////////////////////////////////////////////////////////////// + [ECS_ARN_FORMAT_INCLUDES_CLUSTER_NAME]: { + type: FlagType.BugFix, + summary: 'ARN format used by ECS. In the new ARN format, the cluster name is part of the resource ID.', + details: ` + If this flag is not set, the old ARN format (without cluster name) for ECS is used. + If this flag is set, the new ARN format (with cluster name) for ECS is used. + + This is a feature flag as the old format is still valid for existing ECS clusters. + + See https://docs.aws.amazon.com/AmazonECS/latest/developerguide/ecs-account-settings.html#ecs-resource-ids + `, + introducedIn: { v2: '2.35.0' }, + recommendedValue: true, + }, + + ////////////////////////////////////////////////////////////////////// + [IAM_MINIMIZE_POLICIES]: { + type: FlagType.VisibleContext, + summary: 'Minimize IAM policies by combining Statements', + details: ` + Minimize IAM policies by combining Principals, Actions and Resources of two + Statements in the policies, as long as it doesn't change the meaning of the + policy.`, + introducedIn: { v1: '1.150.0', v2: '2.18.0' }, + recommendedValue: true, + }, + + ////////////////////////////////////////////////////////////////////// + [VALIDATE_SNAPSHOT_REMOVAL_POLICY]: { + type: FlagType.ApiDefault, + summary: 'Error on snapshot removal policies on resources that do not support it.', + details: ` + Makes sure we do not allow snapshot removal policy on resources that do not support it. + If supplied on an unsupported resource, CloudFormation ignores the policy altogether. + This flag will reduce confusion and unexpected loss of data when erroneously supplying + the snapshot removal policy.`, + introducedIn: { v2: '2.28.0' }, + recommendedValue: true, + }, + + ////////////////////////////////////////////////////////////////////// + [CODEPIPELINE_CROSS_ACCOUNT_KEY_ALIAS_STACK_SAFE_RESOURCE_NAME]: { + type: FlagType.BugFix, + summary: 'Generate key aliases that include the stack name', + details: ` + Enable this feature flag to have CodePipeline generate a unique cross account key alias name using the stack name. + + Previously, when creating multiple pipelines with similar naming conventions and when crossAccountKeys is true, + the KMS key alias name created for these pipelines may be the same due to how the uniqueId is generated. + + This new implementation creates a stack safe resource name for the alias using the stack name instead of the stack ID. + `, + introducedIn: { v2: '2.29.0' }, + recommendedValue: true, + }, + + ////////////////////////////////////////////////////////////////////// + [S3_CREATE_DEFAULT_LOGGING_POLICY]: { + type: FlagType.BugFix, + summary: 'Enable this feature flag to create an S3 bucket policy by default in cases where an AWS service would automatically create the Policy if one does not exist.', + details: ` + For example, in order to send VPC flow logs to an S3 bucket, there is a specific Bucket Policy + that needs to be attached to the bucket. If you create the bucket without a policy and then add the + bucket as the flow log destination, the service will automatically create the bucket policy with the + necessary permissions. If you were to then try and add your own bucket policy CloudFormation will throw + and error indicating that a bucket policy already exists. + + In cases where we know what the required policy is we can go ahead and create the policy so we can + remain in control of it. + + @see https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/AWS-logs-and-resource-policy.html#AWS-logs-infrastructure-S3 + `, + introducedIn: { v2: '2.31.0' }, + recommendedValue: true, + }, + + ////////////////////////////////////////////////////////////////////// + [SNS_SUBSCRIPTIONS_SQS_DECRYPTION_POLICY]: { + type: FlagType.BugFix, + summary: 'Restrict KMS key policy for encrypted Queues a bit more', + details: ` + Enable this feature flag to restrict the decryption of a SQS queue, which is subscribed to a SNS topic, to + only the topic which it is subscribed to and not the whole SNS service of an account. + + Previously the decryption was only restricted to the SNS service principal. To make the SQS subscription more + secure, it is a good practice to restrict the decryption further and only allow the connected SNS topic to decryption + the subscribed queue.`, + introducedIn: { v2: '2.32.0' }, + recommendedValue: true, + }, + + ////////////////////////////////////////////////////////////////////// + [APIGATEWAY_DISABLE_CLOUDWATCH_ROLE]: { + type: FlagType.BugFix, + summary: 'Make default CloudWatch Role behavior safe for multiple API Gateways in one environment', + details: ` + Enable this feature flag to change the default behavior for aws-apigateway.RestApi and aws-apigateway.SpecRestApi + to _not_ create a CloudWatch role and Account. There is only a single ApiGateway account per AWS + environment which means that each time you create a RestApi in your account the ApiGateway account + is overwritten. If at some point the newest RestApi is deleted, the ApiGateway Account and CloudWatch + role will also be deleted, breaking any existing ApiGateways that were depending on them. + + When this flag is enabled you should either create the ApiGateway account and CloudWatch role + separately _or_ only enable the cloudWatchRole on a single RestApi. + `, + introducedIn: { v2: '2.38.0' }, + recommendedValue: true, + }, + + ////////////////////////////////////////////////////////////////////// + [ENABLE_PARTITION_LITERALS]: { + type: FlagType.BugFix, + summary: 'Make ARNs concrete if AWS partition is known', + details: ` + Enable this feature flag to get partition names as string literals in Stacks with known regions defined in + their environment, such as "aws" or "aws-cn". Previously the CloudFormation intrinsic function + "Ref: AWS::Partition" was used. For example: + + \`\`\`yaml + Principal: + AWS: + Fn::Join: + - "" + - - "arn:" + - Ref: AWS::Partition + - :iam::123456789876:root + \`\`\` + + becomes: + + \`\`\` + Principal: + AWS: "arn:aws:iam::123456789876:root" + \`\`\` + + The intrinsic function will still be used in Stacks where no region is defined or the region's partition + is unknown. + `, + introducedIn: { v2: '2.38.0' }, + recommendedValue: true, + }, + + ////////////////////////////////////////////////////////////////////// + [EVENTS_TARGET_QUEUE_SAME_ACCOUNT]: { + type: FlagType.BugFix, + summary: 'Event Rules may only push to encrypted SQS queues in the same account', + details: ` + This flag applies to SQS Queues that are used as the target of event Rules. When enabled, only principals + from the same account as the Rule can send messages. If a queue is unencrypted, this restriction will + always apply, regardless of the value of this flag. + `, + introducedIn: { v2: '2.51.0' }, + recommendedValue: true, + }, +}; + +const CURRENT_MV = 'v2'; /** - * This flag applies to SQS Queues that are used as the target of event Rules. When enabled, only principals - * from the same account as the Rule can send messages. If a queue is unencrypted, this restriction will - * always apply, regardless of the value of this flag. + * The list of future flags that are now expired. This is going to be used to identify + * and block usages of old feature flags in the new major version of CDK. */ -export const EVENTS_TARGET_QUEUE_SAME_ACCOUNT = '@aws-cdk/aws-events:eventsTargetQueueSameAccount'; +export const CURRENT_VERSION_EXPIRED_FLAGS: string[] = Object.entries(FLAGS) + .filter(([_, flag]) => flag.introducedIn[CURRENT_MV] === undefined) + .map(([name, _]) => name).sort(); /** * Flag values that should apply for new projects @@ -368,59 +525,14 @@ export const EVENTS_TARGET_QUEUE_SAME_ACCOUNT = '@aws-cdk/aws-events:eventsTarge * * Tests must cover the default (disabled) case and the future (enabled) case. */ -export const FUTURE_FLAGS: { [key: string]: boolean } = { - [APIGATEWAY_USAGEPLANKEY_ORDERINSENSITIVE_ID]: true, - [ENABLE_STACK_NAME_DUPLICATES_CONTEXT]: true, - [ENABLE_DIFF_NO_FAIL_CONTEXT]: true, - [STACK_RELATIVE_EXPORTS_CONTEXT]: true, - [DOCKER_IGNORE_SUPPORT]: true, - [SECRETS_MANAGER_PARSE_OWNED_SECRET_NAME]: true, - [KMS_DEFAULT_KEY_POLICIES]: true, - [S3_GRANT_WRITE_WITHOUT_ACL]: true, - [ECS_REMOVE_DEFAULT_DESIRED_COUNT]: true, - [RDS_LOWERCASE_DB_IDENTIFIER]: true, - [EFS_DEFAULT_ENCRYPTION_AT_REST]: true, - [LAMBDA_RECOGNIZE_VERSION_PROPS]: true, - [LAMBDA_RECOGNIZE_LAYER_VERSION]: true, - [CLOUDFRONT_DEFAULT_SECURITY_POLICY_TLS_V1_2_2021]: true, - [ECS_SERVICE_EXTENSIONS_ENABLE_DEFAULT_LOG_DRIVER]: true, - [EC2_UNIQUE_IMDSV2_LAUNCH_TEMPLATE_NAME]: true, - [CHECK_SECRET_USAGE]: true, - [IAM_MINIMIZE_POLICIES]: true, - [ECS_ARN_FORMAT_INCLUDES_CLUSTER_NAME]: true, - [VALIDATE_SNAPSHOT_REMOVAL_POLICY]: true, - [CODEPIPELINE_CROSS_ACCOUNT_KEY_ALIAS_STACK_SAFE_RESOURCE_NAME]: true, - [S3_CREATE_DEFAULT_LOGGING_POLICY]: true, - [SNS_SUBSCRIPTIONS_SQS_DECRYPTION_POLICY]: true, - [APIGATEWAY_DISABLE_CLOUDWATCH_ROLE]: true, - [ENABLE_PARTITION_LITERALS]: true, - [EVENTS_TARGET_QUEUE_SAME_ACCOUNT]: true, -}; - -/** - * Values that will be set by default in a new project, which are not necessarily booleans (and don't expire) - */ -export const NEW_PROJECT_DEFAULT_CONTEXT: { [key: string]: any} = { - [TARGET_PARTITIONS]: ['aws', 'aws-cn'], -}; +export const NEW_PROJECT_CONTEXT = Object.fromEntries( + Object.entries(FLAGS) + .filter(([_, flag]) => flag.recommendedValue !== flag.defaults?.[CURRENT_MV] && flag.introducedIn[CURRENT_MV]) + .map(([name, flag]) => [name, flag.recommendedValue]), +); /** - * The list of future flags that are now expired. This is going to be used to identify - * and block usages of old feature flags in the new major version of CDK. - */ -export const FUTURE_FLAGS_EXPIRED: string[] = [ - DOCKER_IGNORE_SUPPORT, - ECS_REMOVE_DEFAULT_DESIRED_COUNT, - EFS_DEFAULT_ENCRYPTION_AT_REST, - ENABLE_DIFF_NO_FAIL_CONTEXT, - ENABLE_STACK_NAME_DUPLICATES_CONTEXT, - KMS_DEFAULT_KEY_POLICIES, - S3_GRANT_WRITE_WITHOUT_ACL, - SECRETS_MANAGER_PARSE_OWNED_SECRET_NAME, -]; - -/** - * The default values of each of these flags. + * The default values of each of these flags in the current major version. * * This is the effective value of the flag, unless it's overriden via * context. @@ -428,27 +540,27 @@ export const FUTURE_FLAGS_EXPIRED: string[] = [ * Adding new flags here is only allowed during the pre-release period of a new * major version! */ -const FUTURE_FLAGS_DEFAULTS: { [key: string]: boolean } = { - [APIGATEWAY_USAGEPLANKEY_ORDERINSENSITIVE_ID]: true, - [ENABLE_STACK_NAME_DUPLICATES_CONTEXT]: true, - [ENABLE_DIFF_NO_FAIL_CONTEXT]: true, - [STACK_RELATIVE_EXPORTS_CONTEXT]: true, - [NEW_STYLE_STACK_SYNTHESIS_CONTEXT]: true, - [DOCKER_IGNORE_SUPPORT]: true, - [SECRETS_MANAGER_PARSE_OWNED_SECRET_NAME]: true, - [KMS_DEFAULT_KEY_POLICIES]: true, - [S3_GRANT_WRITE_WITHOUT_ACL]: true, - [ECS_REMOVE_DEFAULT_DESIRED_COUNT]: true, - [RDS_LOWERCASE_DB_IDENTIFIER]: true, - [EFS_DEFAULT_ENCRYPTION_AT_REST]: true, - [LAMBDA_RECOGNIZE_VERSION_PROPS]: true, - [CLOUDFRONT_DEFAULT_SECURITY_POLICY_TLS_V1_2_2021]: true, - // Every feature flag below this should have its default behavior set to "not - // activated", as it was introduced AFTER v2 was released. - [ECS_SERVICE_EXTENSIONS_ENABLE_DEFAULT_LOG_DRIVER]: false, - [EC2_UNIQUE_IMDSV2_LAUNCH_TEMPLATE_NAME]: false, -}; +export const CURRENT_VERSION_FLAG_DEFAULTS = Object.fromEntries(Object.entries(FLAGS) + .filter(([_, flag]) => flag.defaults?.[CURRENT_MV] !== undefined) + .map(([name, flag]) => [name, flag.defaults?.[CURRENT_MV]])); export function futureFlagDefault(flag: string): boolean { - return FUTURE_FLAGS_DEFAULTS[flag] ?? false; + const value = CURRENT_VERSION_FLAG_DEFAULTS[flag] ?? false; + if (typeof value !== 'boolean') { + throw new Error(`futureFlagDefault: default type of flag '${flag}' should be boolean, got '${typeof value}'`); + } + return value; } + +// Nobody should have been using any of this, but you never know + +/** @deprecated use CURRENT_VERSION_EXPIRED_FLAGS instead */ +export const FUTURE_FLAGS_EXPIRED = CURRENT_VERSION_EXPIRED_FLAGS; + +/** @deprecated use NEW_PROJECT_CONTEXT instead */ +export const FUTURE_FLAGS = Object.fromEntries(Object.entries(NEW_PROJECT_CONTEXT) + .filter(([_, v]) => typeof v === 'boolean')); + +/** @deprecated use NEW_PROJECT_CONTEXT instead */ +export const NEW_PROJECT_DEFAULT_CONTEXT = Object.fromEntries(Object.entries(NEW_PROJECT_CONTEXT) + .filter(([_, v]) => typeof v !== 'boolean')); \ No newline at end of file diff --git a/packages/@aws-cdk/cx-api/lib/private/flag-modeling.ts b/packages/@aws-cdk/cx-api/lib/private/flag-modeling.ts new file mode 100644 index 0000000000000..cb4d11da7e59c --- /dev/null +++ b/packages/@aws-cdk/cx-api/lib/private/flag-modeling.ts @@ -0,0 +1,39 @@ +export enum FlagType { + /** + * Change the default behavior of the API + * + * The old behavior is not disrecommended, and possible to achieve with source + * code changes. Also valid for changes that don't affect CloudFormation, but + * the CXAPI contract. + */ + ApiDefault, + + /** + * Address a bug/introduce a recommended change + * + * The old behavior is no longer recommended. The only way to achieve it is by + * keeping the flag at the legacy value. + */ + BugFix, + + /** + * Advertise the presence of this context option in `cdk.json` + */ + VisibleContext, +}; + +export interface FlagInfo { + /** Flag type */ + readonly type: FlagType; + /** Single-line description for the flag */ + readonly summary: string; + /** Detailed description for the flag */ + readonly details: string; + /** Version number the flag was introduced in each version line. `undefined` means flag does not exist in that line. */ + readonly introducedIn: { v1?: string; v2?: string }; + /** Default value, if flag is unset by user. Adding a flag with a default may not change behavior after GA! */ + readonly defaults?: { v2?: any }; + /** Default in new projects */ + readonly recommendedValue: any; +}; + diff --git a/packages/@aws-cdk/cx-api/package.json b/packages/@aws-cdk/cx-api/package.json index 77b8e342b5c83..f2baa9edd345e 100644 --- a/packages/@aws-cdk/cx-api/package.json +++ b/packages/@aws-cdk/cx-api/package.json @@ -52,6 +52,9 @@ "build+extract": "yarn build && yarn rosetta:extract", "build+test+extract": "yarn build+test && yarn rosetta:extract" }, + "cdk-build": { + "post": ["node ./build-tools/flag-report.js"] + }, "author": { "name": "Amazon Web Services", "url": "https://aws.amazon.com", diff --git a/packages/@aws-cdk/cx-api/test/features.test.ts b/packages/@aws-cdk/cx-api/test/features.test.ts index c370f24415730..1a5a872dbda2b 100644 --- a/packages/@aws-cdk/cx-api/test/features.test.ts +++ b/packages/@aws-cdk/cx-api/test/features.test.ts @@ -1,7 +1,7 @@ import * as feats from '../lib/features'; test('all future flags have defaults configured', () => { - Object.keys(feats.FUTURE_FLAGS).forEach(flag => { + Object.keys(feats.FLAGS).forEach(flag => { expect(typeof(feats.futureFlagDefault(flag))).toEqual('boolean'); }); }); @@ -9,3 +9,42 @@ test('all future flags have defaults configured', () => { test('futureFlagDefault returns false if non existent flag was given', () => { expect(feats.futureFlagDefault('non-existent-flag')).toEqual(false); }); + +test('feature flag defaults may not be changed anymore', () => { + // In principle, these flags were decided upon during the v2 alpha period, and they are now frozen + // and may not be changed anymore. + // + // One exception is allowed: to avoid a double negative in your flag name (`disableOldBehavior: true`). + // + // In that case, it is permitted to name the flag `oldBehavior`, add a new default set to `true`, + // and have the recommended value be `false`. + expect(feats.CURRENT_VERSION_FLAG_DEFAULTS).toEqual({ + [feats.APIGATEWAY_USAGEPLANKEY_ORDERINSENSITIVE_ID]: true, + [feats.ENABLE_STACK_NAME_DUPLICATES_CONTEXT]: true, + [feats.ENABLE_DIFF_NO_FAIL_CONTEXT]: true, + [feats.STACK_RELATIVE_EXPORTS_CONTEXT]: true, + [feats.NEW_STYLE_STACK_SYNTHESIS_CONTEXT]: true, + [feats.DOCKER_IGNORE_SUPPORT]: true, + [feats.SECRETS_MANAGER_PARSE_OWNED_SECRET_NAME]: true, + [feats.KMS_DEFAULT_KEY_POLICIES]: true, + [feats.S3_GRANT_WRITE_WITHOUT_ACL]: true, + [feats.ECS_REMOVE_DEFAULT_DESIRED_COUNT]: true, + [feats.RDS_LOWERCASE_DB_IDENTIFIER]: true, + [feats.EFS_DEFAULT_ENCRYPTION_AT_REST]: true, + [feats.LAMBDA_RECOGNIZE_VERSION_PROPS]: true, + [feats.CLOUDFRONT_DEFAULT_SECURITY_POLICY_TLS_V1_2_2021]: true, + }); +}); + +test('expired feature flags may not be changed anymore', () => { + expect(feats.CURRENT_VERSION_EXPIRED_FLAGS).toEqual([ + feats.DOCKER_IGNORE_SUPPORT, + feats.ECS_REMOVE_DEFAULT_DESIRED_COUNT, + feats.EFS_DEFAULT_ENCRYPTION_AT_REST, + feats.ENABLE_DIFF_NO_FAIL_CONTEXT, + feats.ENABLE_STACK_NAME_DUPLICATES_CONTEXT, + feats.KMS_DEFAULT_KEY_POLICIES, + feats.S3_GRANT_WRITE_WITHOUT_ACL, + feats.SECRETS_MANAGER_PARSE_OWNED_SECRET_NAME, + ].sort()); +}); \ No newline at end of file diff --git a/packages/@aws-cdk/integ-runner/lib/runner/runner-base.ts b/packages/@aws-cdk/integ-runner/lib/runner/runner-base.ts index dc99952509714..7f8e1963dd5e4 100644 --- a/packages/@aws-cdk/integ-runner/lib/runner/runner-base.ts +++ b/packages/@aws-cdk/integ-runner/lib/runner/runner-base.ts @@ -1,6 +1,6 @@ import * as path from 'path'; import { TestCase, DefaultCdkOptions } from '@aws-cdk/cloud-assembly-schema'; -import { AVAILABILITY_ZONE_FALLBACK_CONTEXT_KEY, FUTURE_FLAGS, TARGET_PARTITIONS, FUTURE_FLAGS_EXPIRED } from '@aws-cdk/cx-api'; +import { AVAILABILITY_ZONE_FALLBACK_CONTEXT_KEY, TARGET_PARTITIONS, NEW_PROJECT_CONTEXT } from '@aws-cdk/cx-api'; import { CdkCliWrapper, ICdk } from 'cdk-cli-wrapper'; import * as fs from 'fs-extra'; import { flatten } from '../utils'; @@ -356,15 +356,22 @@ export abstract class IntegRunner { } protected getContext(additionalContext?: Record): Record { - const futureFlags: { [key: string]: any } = {}; - Object.entries(FUTURE_FLAGS) - .filter(([k, _]) => !FUTURE_FLAGS_EXPIRED.includes(k)) - .forEach(([k, v]) => futureFlags[k] = v); - return { - ...futureFlags, + ...NEW_PROJECT_CONTEXT, ...this.legacyContext, ...additionalContext, + + // We originally had PLANNED to set this to ['aws', 'aws-cn'], but due to a programming mistake + // it was set to everything. In this PR, set it to everything to not mess up all the snapshots. + [TARGET_PARTITIONS]: undefined, + + /* ---------------- THE FUTURE LIVES BELOW---------------------------- + // Restricting to these target partitions makes most service principals synthesize to + // `service.${URL_SUFFIX}`, which is technically *incorrect* (it's only `amazonaws.com` + // or `amazonaws.com.cn`, never UrlSuffix for any of the restricted regions) but it's what + // most existing integ tests contain, and we want to disturb as few as possible. + // [TARGET_PARTITIONS]: ['aws', 'aws-cn'], + /* ---------------- END OF THE FUTURE ------------------------------- */ }; } } @@ -407,12 +414,6 @@ export const DEFAULT_SYNTH_OPTIONS = { }, ], }, - - // Restricting to these target partitions makes most service principals synthesize to - // `service.${URL_SUFFIX}`, which is technically *incorrect* (it's only `amazonaws.com` - // or `amazonaws.com.cn`, never UrlSuffix for any of the restricted regions) but it's what - // most existing integ tests contain, and we want to disturb as few as possible. - [TARGET_PARTITIONS]: ['aws', 'aws-cn'], }, env: { CDK_INTEG_ACCOUNT: '12345678', diff --git a/packages/@aws-cdk/region-info/build-tools/generate.sh b/packages/@aws-cdk/region-info/build-tools/generate.sh index 8ffbbdf0d7b58..66bb576070aa0 100644 --- a/packages/@aws-cdk/region-info/build-tools/generate.sh +++ b/packages/@aws-cdk/region-info/build-tools/generate.sh @@ -15,7 +15,7 @@ tsc \ --resolveJsonModule \ --strict \ --strictNullChecks \ - --target ES2018 \ + --target ES2020 \ build-tools/*.ts echo "⌛️ Generating the static data..." diff --git a/packages/@monocdk-experiment/rewrite-imports/lib/rewrite.ts b/packages/@monocdk-experiment/rewrite-imports/lib/rewrite.ts index c0dd892cd6356..11c947d4a7f23 100644 --- a/packages/@monocdk-experiment/rewrite-imports/lib/rewrite.ts +++ b/packages/@monocdk-experiment/rewrite-imports/lib/rewrite.ts @@ -22,7 +22,7 @@ import * as ts from 'typescript'; * @returns the updated source code. */ export function rewriteImports(sourceText: string, fileName: string = 'index.ts'): string { - const sourceFile = ts.createSourceFile(fileName, sourceText, ts.ScriptTarget.ES2018); + const sourceFile = ts.createSourceFile(fileName, sourceText, ts.ScriptTarget.ES2020); const replacements = new Array<{ original: ts.Node, updatedLocation: string }>(); diff --git a/packages/@monocdk-experiment/rewrite-imports/tsconfig.json b/packages/@monocdk-experiment/rewrite-imports/tsconfig.json index 644a2975f7200..e48deb1b6520b 100644 --- a/packages/@monocdk-experiment/rewrite-imports/tsconfig.json +++ b/packages/@monocdk-experiment/rewrite-imports/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { - "target": "ES2018", + "target": "ES2020", "module": "commonjs", - "lib": ["es2018", "dom"], + "lib": ["es2020", "dom"], "strict": true, "alwaysStrict": true, "declaration": true, diff --git a/packages/aws-cdk-migration/lib/rewrite.ts b/packages/aws-cdk-migration/lib/rewrite.ts index 9d3e414587d15..3924ccce718d3 100644 --- a/packages/aws-cdk-migration/lib/rewrite.ts +++ b/packages/aws-cdk-migration/lib/rewrite.ts @@ -126,7 +126,7 @@ export function rewriteImports( fileName: string = 'index.ts', rewriteConstructsImports: boolean = false, ): string { - const sourceFile = ts.createSourceFile(fileName, sourceText, ts.ScriptTarget.ES2018, true); + const sourceFile = ts.createSourceFile(fileName, sourceText, ts.ScriptTarget.ES2020, true); const rewriter = new ImportRewriter(sourceFile, updatedLocation, rewriteConstructsImports); ts.transform(sourceFile, [rewriter.rewriteTransformer()]); return rewriter.rewriteImports(); diff --git a/packages/aws-cdk-migration/tsconfig.json b/packages/aws-cdk-migration/tsconfig.json index 644a2975f7200..e48deb1b6520b 100644 --- a/packages/aws-cdk-migration/tsconfig.json +++ b/packages/aws-cdk-migration/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { - "target": "ES2018", + "target": "ES2020", "module": "commonjs", - "lib": ["es2018", "dom"], + "lib": ["es2020", "dom"], "strict": true, "alwaysStrict": true, "declaration": true, diff --git a/packages/aws-cdk/lib/init-templates/app/typescript/tsconfig.json b/packages/aws-cdk/lib/init-templates/app/typescript/tsconfig.json index 9f8e8beabd233..fc44377a1edb7 100644 --- a/packages/aws-cdk/lib/init-templates/app/typescript/tsconfig.json +++ b/packages/aws-cdk/lib/init-templates/app/typescript/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2018", + "target": "ES2020", "module": "commonjs", "lib": [ - "es2018" + "es2020" ], "declaration": true, "strict": true, diff --git a/packages/aws-cdk/lib/init-templates/lib/typescript/tsconfig.json b/packages/aws-cdk/lib/init-templates/lib/typescript/tsconfig.json index 9f8e8beabd233..fc44377a1edb7 100644 --- a/packages/aws-cdk/lib/init-templates/lib/typescript/tsconfig.json +++ b/packages/aws-cdk/lib/init-templates/lib/typescript/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2018", + "target": "ES2020", "module": "commonjs", "lib": [ - "es2018" + "es2020" ], "declaration": true, "strict": true, diff --git a/packages/aws-cdk/lib/init-templates/sample-app/javascript/tsconfig.json b/packages/aws-cdk/lib/init-templates/sample-app/javascript/tsconfig.json index 47ad92078bbef..0662466bf545e 100644 --- a/packages/aws-cdk/lib/init-templates/sample-app/javascript/tsconfig.json +++ b/packages/aws-cdk/lib/init-templates/sample-app/javascript/tsconfig.json @@ -1,11 +1,9 @@ { "compilerOptions": { - "target": "ES2018", + "target": "ES2020", "module": "commonjs", "lib": [ - "es2016", - "es2017.object", - "es2017.string" + "es2020" ], "declaration": true, "strict": true, diff --git a/packages/aws-cdk/lib/init-templates/sample-app/typescript/tsconfig.json b/packages/aws-cdk/lib/init-templates/sample-app/typescript/tsconfig.json index 9f8e8beabd233..fc44377a1edb7 100644 --- a/packages/aws-cdk/lib/init-templates/sample-app/typescript/tsconfig.json +++ b/packages/aws-cdk/lib/init-templates/sample-app/typescript/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { - "target": "ES2018", + "target": "ES2020", "module": "commonjs", "lib": [ - "es2018" + "es2020" ], "declaration": true, "strict": true, diff --git a/packages/aws-cdk/lib/init.ts b/packages/aws-cdk/lib/init.ts index 810aa53113bd4..822178308437f 100644 --- a/packages/aws-cdk/lib/init.ts +++ b/packages/aws-cdk/lib/init.ts @@ -180,16 +180,10 @@ export class InitTemplate { return; } - const futureFlags: {[key: string]: any} = {}; - Object.entries(cxapi.FUTURE_FLAGS) - .filter(([k, _]) => !cxapi.FUTURE_FLAGS_EXPIRED.includes(k)) - .forEach(([k, v]) => futureFlags[k] = v); - const config = await fs.readJson(cdkJson); config.context = { ...config.context, - ...futureFlags, - ...cxapi.NEW_PROJECT_DEFAULT_CONTEXT, + ...cxapi.NEW_PROJECT_CONTEXT, }; await fs.writeJson(cdkJson, config, { spaces: 2 }); diff --git a/packages/aws-cdk/test/init.test.ts b/packages/aws-cdk/test/init.test.ts index 0e674ff8ab963..79af055608578 100644 --- a/packages/aws-cdk/test/init.test.ts +++ b/packages/aws-cdk/test/init.test.ts @@ -151,14 +151,13 @@ describe('constructs version', () => { const config = await fs.readJson(path.join(tmpDir, 'cdk.json')); const context = config.context || {}; for (const [key, actual] of Object.entries(context)) { - expect(key in cxapi.FUTURE_FLAGS || key in cxapi.NEW_PROJECT_DEFAULT_CONTEXT).toBeTruthy(); - - expect(cxapi.FUTURE_FLAGS[key] ?? cxapi.NEW_PROJECT_DEFAULT_CONTEXT[key]).toEqual(actual); + expect(key in cxapi.NEW_PROJECT_CONTEXT).toBeTruthy(); + expect(cxapi.NEW_PROJECT_CONTEXT[key]).toEqual(actual); } // assert that expired future flags are not part of the cdk.json Object.keys(context).forEach(k => { - expect(cxapi.FUTURE_FLAGS_EXPIRED.includes(k)).toEqual(false); + expect(cxapi.CURRENT_VERSION_EXPIRED_FLAGS.includes(k)).toEqual(false); }); }); } diff --git a/packages/awslint/tsconfig.json b/packages/awslint/tsconfig.json index 980ad7d85412f..08b0188c40091 100644 --- a/packages/awslint/tsconfig.json +++ b/packages/awslint/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { - "target": "ES2018", + "target": "ES2020", "module": "commonjs", - "lib": ["es2018"], + "lib": ["es2020"], "strict": true, "alwaysStrict": true, "declaration": true, diff --git a/packages/cdk-assets/tsconfig.json b/packages/cdk-assets/tsconfig.json index 04e0404f04442..b238d46998d26 100644 --- a/packages/cdk-assets/tsconfig.json +++ b/packages/cdk-assets/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { - "target": "ES2018", + "target": "ES2020", "module": "commonjs", - "lib": ["es2018", "dom"], + "lib": ["es2020", "dom"], "strict": true, "alwaysStrict": true, "declaration": true, diff --git a/packages/cdk-dasm/tsconfig.json b/packages/cdk-dasm/tsconfig.json index a6f749194f219..53c673ac6eba5 100644 --- a/packages/cdk-dasm/tsconfig.json +++ b/packages/cdk-dasm/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { - "target": "ES2018", + "target": "ES2020", "module": "commonjs", - "lib": ["es2018"], + "lib": ["es2020"], "strict": true, "alwaysStrict": true, "declaration": true, diff --git a/tools/@aws-cdk/cdk-build-tools/tsconfig.json b/tools/@aws-cdk/cdk-build-tools/tsconfig.json index 6b870d2cb95a2..b2d7ffc951efa 100644 --- a/tools/@aws-cdk/cdk-build-tools/tsconfig.json +++ b/tools/@aws-cdk/cdk-build-tools/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { - "target": "ES2018", + "target": "ES2020", "module": "commonjs", - "lib": ["es2018"], + "lib": ["es2020"], "strict": true, "alwaysStrict": true, "declaration": true, diff --git a/tools/@aws-cdk/cdk-integ-tools/lib/integ-helpers.ts b/tools/@aws-cdk/cdk-integ-tools/lib/integ-helpers.ts index 7cccd2578022d..50396b6bf6782 100644 --- a/tools/@aws-cdk/cdk-integ-tools/lib/integ-helpers.ts +++ b/tools/@aws-cdk/cdk-integ-tools/lib/integ-helpers.ts @@ -330,11 +330,6 @@ export class IntegrationTest { } } -const futureFlags: {[key: string]: any} = {}; -Object.entries(cxapi.FUTURE_FLAGS) - .filter(([k, _]) => !cxapi.FUTURE_FLAGS_EXPIRED.includes(k)) - .forEach(([k, v]) => futureFlags[k] = v); - // Default context we run all integ tests with, so they don't depend on the // account of the exercising user. export const DEFAULT_SYNTH_OPTIONS = { @@ -374,12 +369,18 @@ export const DEFAULT_SYNTH_OPTIONS = { }, ], }, + ...cxapi.NEW_PROJECT_CONTEXT, + // We originally had PLANNED to set this to ['aws', 'aws-cn'], but due to a programming mistake + // it was set to everything. In this PR, set it to everything to not mess up all the snapshots. + [TARGET_PARTITIONS]: undefined, + + /* ---------------- THE FUTURE LIVES BELOW---------------------------- // Restricting to these target partitions makes most service principals synthesize to // `service.${URL_SUFFIX}`, which is technically *incorrect* (it's only `amazonaws.com` // or `amazonaws.com.cn`, never UrlSuffix for any of the restricted regions) but it's what // most existing integ tests contain, and we want to disturb as few as possible. - [TARGET_PARTITIONS]: ['aws', 'aws-cn'], - ...futureFlags, + // [TARGET_PARTITIONS]: ['aws', 'aws-cn'], + /* ---------------- END OF THE FUTURE ------------------------------- */ }, env: { CDK_INTEG_ACCOUNT: '12345678', @@ -432,4 +433,4 @@ function deepEqual(a: any, b: any) { } catch (e) { return false; } -} \ No newline at end of file +} diff --git a/tools/@aws-cdk/cdk-integ-tools/tsconfig.json b/tools/@aws-cdk/cdk-integ-tools/tsconfig.json index 871d4115f698d..dc595f6a9a983 100644 --- a/tools/@aws-cdk/cdk-integ-tools/tsconfig.json +++ b/tools/@aws-cdk/cdk-integ-tools/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { - "target": "ES2018", + "target": "ES2020", "module": "commonjs", - "lib": ["es2018"], + "lib": ["es2020"], "strict": true, "alwaysStrict": true, "declaration": true, diff --git a/tools/@aws-cdk/cdk-release/tsconfig.json b/tools/@aws-cdk/cdk-release/tsconfig.json index 89d1f04da5020..002399730885c 100644 --- a/tools/@aws-cdk/cdk-release/tsconfig.json +++ b/tools/@aws-cdk/cdk-release/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { - "target": "ES2018", + "target": "ES2020", "module": "commonjs", - "lib": ["es2018"], + "lib": ["es2020"], "strict": true, "alwaysStrict": true, "declaration": true, diff --git a/tools/@aws-cdk/cfn2ts/tsconfig.json b/tools/@aws-cdk/cfn2ts/tsconfig.json index 89d1f04da5020..002399730885c 100644 --- a/tools/@aws-cdk/cfn2ts/tsconfig.json +++ b/tools/@aws-cdk/cfn2ts/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { - "target": "ES2018", + "target": "ES2020", "module": "commonjs", - "lib": ["es2018"], + "lib": ["es2020"], "strict": true, "alwaysStrict": true, "declaration": true, diff --git a/tools/@aws-cdk/eslint-plugin/tsconfig.json b/tools/@aws-cdk/eslint-plugin/tsconfig.json index aea4e63c9206c..c2df43942c2c6 100644 --- a/tools/@aws-cdk/eslint-plugin/tsconfig.json +++ b/tools/@aws-cdk/eslint-plugin/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { - "target": "ES2018", + "target": "ES2020", "module": "commonjs", - "lib": ["es2018"], + "lib": ["es2020"], "strict": true, "alwaysStrict": true, "declaration": true, diff --git a/tools/@aws-cdk/individual-pkg-gen/tsconfig.json b/tools/@aws-cdk/individual-pkg-gen/tsconfig.json index 14499cd2abfaf..d34fdc6881bb3 100644 --- a/tools/@aws-cdk/individual-pkg-gen/tsconfig.json +++ b/tools/@aws-cdk/individual-pkg-gen/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { - "target": "ES2018", + "target": "ES2020", "module": "commonjs", - "lib": ["es2018"], + "lib": ["es2020"], "strict": true, "alwaysStrict": true, "declaration": true, diff --git a/tools/@aws-cdk/pkglint/tsconfig.json b/tools/@aws-cdk/pkglint/tsconfig.json index 6b870d2cb95a2..b2d7ffc951efa 100644 --- a/tools/@aws-cdk/pkglint/tsconfig.json +++ b/tools/@aws-cdk/pkglint/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { - "target": "ES2018", + "target": "ES2020", "module": "commonjs", - "lib": ["es2018"], + "lib": ["es2020"], "strict": true, "alwaysStrict": true, "declaration": true, diff --git a/tools/@aws-cdk/pkgtools/tsconfig.json b/tools/@aws-cdk/pkgtools/tsconfig.json index 14499cd2abfaf..d34fdc6881bb3 100644 --- a/tools/@aws-cdk/pkgtools/tsconfig.json +++ b/tools/@aws-cdk/pkgtools/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { - "target": "ES2018", + "target": "ES2020", "module": "commonjs", - "lib": ["es2018"], + "lib": ["es2020"], "strict": true, "alwaysStrict": true, "declaration": true, diff --git a/tools/@aws-cdk/prlint/tsconfig.json b/tools/@aws-cdk/prlint/tsconfig.json index 6b870d2cb95a2..b2d7ffc951efa 100644 --- a/tools/@aws-cdk/prlint/tsconfig.json +++ b/tools/@aws-cdk/prlint/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { - "target": "ES2018", + "target": "ES2020", "module": "commonjs", - "lib": ["es2018"], + "lib": ["es2020"], "strict": true, "alwaysStrict": true, "declaration": true, diff --git a/tools/@aws-cdk/ubergen/tsconfig.json b/tools/@aws-cdk/ubergen/tsconfig.json index 14499cd2abfaf..d34fdc6881bb3 100644 --- a/tools/@aws-cdk/ubergen/tsconfig.json +++ b/tools/@aws-cdk/ubergen/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { - "target": "ES2018", + "target": "ES2020", "module": "commonjs", - "lib": ["es2018"], + "lib": ["es2020"], "strict": true, "alwaysStrict": true, "declaration": true, diff --git a/tools/@aws-cdk/yarn-cling/tsconfig.json b/tools/@aws-cdk/yarn-cling/tsconfig.json index 14499cd2abfaf..d34fdc6881bb3 100644 --- a/tools/@aws-cdk/yarn-cling/tsconfig.json +++ b/tools/@aws-cdk/yarn-cling/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { - "target": "ES2018", + "target": "ES2020", "module": "commonjs", - "lib": ["es2018"], + "lib": ["es2020"], "strict": true, "alwaysStrict": true, "declaration": true,