cdk-preflight 0.0.28 → 0.0.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -51,11 +51,21 @@ CDK のプラグイン経路は `accountId` と `region` をエンジンに渡
51
51
  - テンプレート内の一意性。実測で **Export 名の重複はエンジン未検出**
52
52
  - スタック間の整合性。全スタックのテンプレートを一度に見られるのは我々だけ(`context.stackTemplates`)。ただし Rego はテンプレート単位で評価するので、実装は enforce プラグイン側(TypeScript)になる。**現状は未対応**なので、この種の候補が出たら設計変更の要否とセットで issue に書く
53
53
 
54
- ### レンズ 5:集約・上限(多くはエンジン済み。必ず実測してから書く)
54
+ ### レンズ 5:集約・上限、および文字種・長さ(プロパティ単位で必ず実測)
55
55
 
56
- 実測でエンジンが既に `FATAL` で止めていたもの、つまり**書いてはいけない**もの:リソース数 `F0007`、Output 数 `F0004`、テンプレートサイズ `E1002`、文字列長とパターン `F3031` / `F3033`。
56
+ テンプレート全体に効く集約はエンジンが持っている:リソース数 `F0007`、Output 数 `F0004`、テンプレートサイズ `E1002`。論理 ID の長さは `I3012` の **INFO 止まり**(=グレーゾーン)、Export 名の重複は検出なし。
57
57
 
58
- 空いていたもの:論理 ID の長さは `I3012` の **INFO 止まり**(=グレーゾーン)、Export 名の重複は検出なし。
58
+ **文字種と長さ(`F3031` / `F3033`)を「エンジン済み」と一般化してはいけない**(2026-09-04、57 テンプレートで実測)。カバレッジは**スキーマがそのプロパティに pattern / maxLength を書いているかどうか**で決まるので、同じリソースの中でも非対称になる:
59
+
60
+ | エンジンが止める | 素通り(=候補) |
61
+ |---|---|
62
+ | `SecurityGroup.GroupDescription`(F3031) | **`SecurityGroupIngress[].Description`** |
63
+ | DynamoDB GSI `IndexName`(F3031) | **`Table.TableName`** |
64
+ | `IAM Role.Description`、`Lambda FunctionName`、`Events Rule.Name`、`S3 BucketName`、`Firehose DeliveryStreamName` | `ECS ClusterName/ServiceName/Family`、`ELBv2 Name`(LB/TG とも)、`Cognito UserPoolName/ClientName`、`Batch` の各名前、`SNS TopicName`、`SQS QueueName`、`RDS DBSubnetGroupName`、`CloudWatch Namespace`、`LaunchTemplateName` |
65
+
66
+ しかも `SecurityGroupIngress[].Description` は CDK で日本語が最も入りやすい場所(`addIngressRule(peer, port, '説明')` の第 3 引数)。**プロパティ 1 つずつ重複ガードに掛けること。**
67
+
68
+ そして「日本語なら落ちる」も成立しない。同じ「説明」でも RDS は non-printable 扱いで落ち、IAM ManagedPolicy・Lambda・CloudWatch AlarmDescription は通る。実機ゲートまで通して初めて候補が確定する。
59
69
 
60
70
  ### レンズ 6:時間で変わる制約(対象。ただし重複ガードを先に)
61
71
 
package/.jsii CHANGED
@@ -9598,6 +9598,6 @@
9598
9598
  "symbolId": "src/index:PreflightOptions"
9599
9599
  }
9600
9600
  },
9601
- "version": "0.0.28",
9602
- "fingerprint": "fyyaGGeoMcLqWFI+MPfrrCIBeSIX9Z8OnWK77JFJpN0="
9601
+ "version": "0.0.30",
9602
+ "fingerprint": "zjYDhL+fGcnnHYv1ptJ+kqtPUNu88XjuWHme201WZfg="
9603
9603
  }
package/AGENTS.md CHANGED
@@ -60,9 +60,16 @@ The ordering is by **how easily the L2 guard is bypassed in normal use**, not by
60
60
 
61
61
  ## Rule lifecycle: add fast, retire without ceremony
62
62
 
63
+ The two failure modes are watched separately: **staleness** (the constraint disappeared at AWS — the fail template now deploys clean) is caught by the monthly real-deploy run and reported as BROKEN; **obsolescence** (the engine caught up — the rule is now a duplicate) is caught by the duplication guard and the redundancy scan and reported as REDUNDANT. Both land in the monthly issue.
64
+
63
65
  **Adding.** Two gates, both mechanical, and nothing else can reject a candidate: the duplication guard (`test/rules.test.ts`) and the real-deploy gate (`bench/verify-rule.sh`). The real-deploy gate is the one thing that did *not* get looser with the widened scope, and deliberately so — `enforce` is the default mode, so a false positive is a hard synth failure in someone's CI. The CloudFront survey is the standing evidence: 3 of 9 documented constraints deployed clean (see "A doc sentence is a hypothesis" above). Volume comes from running the bench over more services, never from lowering that bar.
64
66
 
65
- **Retiring.** The trigger is the bundled engine (or CloudFormation's server-side validation) starting to block the constraint — never an L2 construct, never cfn-lint. You do not have to watch for it: the duplication guard turns red on its own the first time an `aws-cdk-lib` bump brings an engine that reports ERROR/FATAL on the rule's fail template. Then:
67
+ **Retiring.** The trigger is the bundled engine (or CloudFormation's server-side validation) starting to block the constraint — never an L2 construct, never cfn-lint. You do not have to watch for it; two mechanisms report it:
68
+
69
+ - The jest duplication guard turns red on its own the first time an `aws-cdk-lib` bump brings an engine that reports ERROR/FATAL on a rule's fail template, and its failure message names the rule to delete.
70
+ - `npx projen redundancy-scan` lists every such rule at once (no AWS account, no cost — it just re-runs each fail template through the bare engine). The monthly `monthly-verify` workflow runs it and files the results under a **REDUNDANT** heading in the same issue that reports drift, so obsolescence and staleness arrive on one page.
71
+
72
+ Then:
66
73
 
67
74
  1. `rm -rf rules/<service>/<rule-id>/` — delete outright, no tombstone. `upstream: retired` exists for a rule mid-flight, not for a corpse.
68
75
  2. `npx projen bundle-rules` (regenerates `src/rules.generated.ts` and `docs/rules.md`).
@@ -128,4 +135,10 @@ bench/ # real-deploy verification (needs an AWS account; no
128
135
  - **`net.cidr_*` builtins do not exist** in the engine's Rego build ("could not find func", measured 2026-09-03 on `net.cidr_contains` / `net.cidr_intersects` / `net.cidr_is_valid`). CIDR math must be hand-rolled: `split`, `to_number`, a 33-entry power-of-two table, and `floor` (which does exist). The gap matters less than it looks: the engine already ships cross-resource CIDR checks — subnet-not-within-VPC is `E3059` and sibling-subnet overlap is `E3060` (both fire on `Ref`-wired resources in one template).
129
136
  - The engine validates instance/node types **against the deploy region** when one is supplied via `validateDetailed(tpl, { pseudoParameterOverrides: { region } })` — `E3628` ('trn1.32xlarge' is not valid for region 'ap-northeast-1'), measured 2026-09-03. Without a region it validates against the union of all regions and emits `I9003`. The enforce plugin passes the region whenever the app's env is concrete, so region-availability rules for instance types belong to the engine, not this pack.
130
137
  - **`json.unmarshal` and `json.is_valid` exist** (measured 2026-09-03, 1.7.0-beta). Opaque JSON-in-a-string properties (CloudWatch `DashboardBody`) can be parsed and validated structurally in Rego — this is the lens-2 workhorse. Reference implementations: `pf-cloudwatch-dashboard-*`.
138
+ - **The Rego regex builtins exist** (`regex.match`, `regex.is_valid`, `regex.find_n`, `regex.replace`) — but the engine is Rust, so its regex flavour is **not** the one AWS's published patterns assume. Two traps, both measured 2026-09-04, both of which shipped broken rules before they were caught:
139
+ - *Character classes are Unicode-aware.* `\w`, `\d` and `\s` match non-ASCII — `regex.match("[\\w]+", "テスト用")` is **true**. AWS API patterns like Cognito's `[\w\s+=,.@-]+` are ASCII-semantics, so copying one verbatim yields a rule that never fires. Write explicit ranges (`^[A-Za-z0-9_ \t+=,.@-]+$`).
140
+ - *No lookahead/lookbehind.* ELBv2 publishes `(?!^-)(?!.*-$)^[A-Za-z0-9-]+$` for `targetGroupName`; that pattern does not compile here, and `regex.match` then returns false for **every** input — the rule fires on all values, which is worse than not firing. Rewrite without lookaround: `^[A-Za-z0-9]([A-Za-z0-9-]*[A-Za-z0-9])?$`.
141
+ - **The absence sentinel must not be a string.** The `object.get(props, "<Key>", "__pf_absent")` idiom is only safe when the next step is `== "__pf_absent"`. If the next step is `is_string(v)` followed by a format check, an *absent* key yields the sentinel string and the rule fires on every resource that omits the property. Use `null` as the default in that case — `is_string(null)` is false, so the rule skips. (This produced three false-positive rules in the 2026-09-04 batch, visible only because other rules' pass fixtures went red.)
142
+ - **Tuple destructuring in `some [a, b] in <array literal>` does not schedule** ("statements not scheduled in query", measured 2026-09-04). Iterating a table of pairs inline is not available; build a set with one helper rule per case and destructure that set (`some [name, path, v] in _pf_x_bad`), which does work.
143
+ - **Schema pattern/length coverage is per property, not per resource or per service.** `AWS::EC2::SecurityGroup.GroupDescription` carries a pattern (`F3031`) while the rule-level `SecurityGroupIngress[].Description` on the same resource carries none; DynamoDB's GSI `IndexName` has one while the table's own `TableName` does not. Never generalise "the engine handles names/lengths" from a sample — probe the exact property (measured 2026-09-04 across 57 templates).
131
144
  - **Probing the raw engine with custom rules**: the rule set must be named `violation` (`data.<pkg>.violation` is looked up; a `diagnostics` set fails with "not a valid rule path"), and hand-built diagnostic objects need lowercase severities (`error`, not `ERROR`/`CUSTOM` — those are display labels added by the wrapper). Pack rules never see this because `make_diag_full` handles the shape.
package/docs/rules.md CHANGED
@@ -29,11 +29,13 @@
29
29
  | `pf-asg-ondemand-percentage-max` | AWS::AutoScaling::AutoScalingGroup | OnDemandPercentageAboveBaseCapacity tops out at 100 | none |
30
30
  | `pf-asg-target-value-positive` | AWS::AutoScaling::ScalingPolicy | Target tracking needs a positive TargetValue | none |
31
31
  | `pf-asg-zone-or-subnet-required` | AWS::AutoScaling::AutoScalingGroup | A group needs AvailabilityZones, AvailabilityZoneIds, or subnets | none |
32
+ | `pf-batch-ce-name` | AWS::Batch::ComputeEnvironment | Compute environment names allow only letters, numbers, hyphen and underscore | none |
32
33
  | `pf-batch-ce-vcpus-order` | AWS::Batch::ComputeEnvironment | MaxvCpus must be at least MinvCpus | none |
33
34
  | `pf-batch-fargate-ce-fields` | AWS::Batch::ComputeEnvironment | Fargate compute environments cannot take AllocationStrategy or InstanceTypes | none |
34
35
  | `pf-batch-fargate-cpu-memory` | AWS::Batch::JobDefinition | Fargate job definitions must use a supported vCPU/memory combination | none |
35
36
  | `pf-batch-fargate-execution-role` | AWS::Batch::JobDefinition | Fargate job definitions require ExecutionRoleArn | none |
36
37
  | `pf-batch-fargate-multinode` | AWS::Batch::JobDefinition | Multi-node parallel jobs are not supported on Fargate | none |
38
+ | `pf-batch-jd-name` | AWS::Batch::JobDefinition | Job definition names allow only letters, numbers, hyphen and underscore | none |
37
39
  | `pf-batch-managed-compute-resources` | AWS::Batch::ComputeEnvironment | MANAGED compute environments require ComputeResources | none |
38
40
  | `pf-batch-queue-order-required` | AWS::Batch::JobQueue | ComputeEnvironmentOrder may not be empty | none |
39
41
  | `pf-batch-retry-attempts` | AWS::Batch::JobDefinition | RetryStrategy.Attempts may not exceed 10 | none |
@@ -43,6 +45,7 @@
43
45
  | `pf-agentcore-runtime-name` | AWS::BedrockAgentCore::Runtime | AgentCore Runtime names must match [a-zA-Z][a-zA-Z0-9_]{0,47} (no hyphens) | pending-engine |
44
46
  | `pf-cloudfront-acm-cert-region` | AWS::CloudFront::Distribution | CloudFront viewer certificates must live in us-east-1 | none |
45
47
  | `pf-cloudfront-aliases-require-custom-certificate` | AWS::CloudFront::Distribution | A distribution with Aliases cannot use the CloudFront default certificate | none |
48
+ | `pf-cloudfront-cache-policy-name` | AWS::CloudFront::CachePolicy | Cache policy names allow only alphanumerics, dash and underscore | none |
46
49
  | `pf-cloudfront-cached-methods-subset` | AWS::CloudFront::Distribution | CachedMethods must be a subset of AllowedMethods | none |
47
50
  | `pf-cloudfront-edge-lambda-region` | AWS::CloudFront::Distribution | Lambda@Edge functions associated with a distribution must be in us-east-1 | none |
48
51
  | `pf-cloudfront-edge-lambda-version` | AWS::CloudFront::Distribution | Lambda@Edge associations must reference a version ARN, not an alias or $LATEST | none |
@@ -59,12 +62,14 @@
59
62
  | `pf-cloudwatch-dashboard-widgets` | AWS::CloudWatch::Dashboard | DashboardBody requires a widgets array | none |
60
63
  | `pf-cloudwatch-datapoints-evaluation` | AWS::CloudWatch::Alarm | DatapointsToAlarm must not exceed EvaluationPeriods | none |
61
64
  | `pf-cloudwatch-extended-statistic` | AWS::CloudWatch::Alarm | A percentile statistic cannot exceed p100 | none |
65
+ | `pf-cloudwatch-metric-namespace-ascii` | AWS::CloudWatch::Alarm | Metric namespaces must not contain non-ASCII characters | none |
62
66
  | `pf-cloudwatch-metric-query-exclusive` | AWS::CloudWatch::Alarm | Expression and MetricStat are mutually exclusive per query | none |
63
67
  | `pf-cloudwatch-metric-query-returndata` | AWS::CloudWatch::Alarm | Exactly one metric query must return data | none |
64
68
  | `pf-cloudwatch-threshold-metric-id` | AWS::CloudWatch::Alarm | ThresholdMetricId must match a metric query that returns data | none |
65
69
  | `pf-cognito-alias-username-exclusive` | AWS::Cognito::UserPool | AliasAttributes and UsernameAttributes are mutually exclusive | none |
66
70
  | `pf-cognito-client-credentials-exclusive` | AWS::Cognito::UserPoolClient | client_credentials cannot combine with code or implicit | none |
67
71
  | `pf-cognito-client-credentials-secret` | AWS::Cognito::UserPoolClient | client_credentials needs a client secret | none |
72
+ | `pf-cognito-client-name` | AWS::Cognito::UserPoolClient | User pool client names allow only word characters, spaces and +=,.@- | none |
68
73
  | `pf-cognito-domain-reserved-word` | AWS::Cognito::UserPoolDomain | Domain prefixes cannot contain reserved words | none |
69
74
  | `pf-cognito-mfa-sms-config` | AWS::Cognito::UserPool | MFA without any factor configuration cannot deploy | none |
70
75
  | `pf-cognito-oauth-callback-required` | AWS::Cognito::UserPoolClient | code and implicit OAuth flows need CallbackURLs | none |
@@ -74,6 +79,7 @@
74
79
  | `pf-cognito-schema-attr-length-order` | AWS::Cognito::UserPool | Schema attribute MaxLength cannot undercut MinLength | none |
75
80
  | `pf-cognito-token-expiration-order` | AWS::Cognito::UserPoolClient | Access and id tokens cannot outlive the refresh token | none |
76
81
  | `pf-cognito-token-validity-range` | AWS::Cognito::UserPoolClient | Token validity ranges depend on token type and unit | none |
82
+ | `pf-cognito-user-pool-name` | AWS::Cognito::UserPool | User pool names allow only word characters, spaces and +=,.@- | none |
77
83
  | `pf-dynamodb-attribute-definitions-usage` | AWS::DynamoDB::Table | Every AttributeDefinitions entry must be used by a key schema | none |
78
84
  | `pf-dynamodb-billing-throughput` | AWS::DynamoDB::Table | ProvisionedThroughput must match BillingMode (required for PROVISIONED, forbidden for PAY_PER_REQUEST) | none |
79
85
  | `pf-dynamodb-duplicate-attribute-definitions` | AWS::DynamoDB::Table | AttributeDefinitions must not define the same attribute twice | none |
@@ -85,15 +91,19 @@
85
91
  | `pf-dynamodb-kinesis-stream-region` | AWS::DynamoDB::Table | A Kinesis streaming destination must be in the table's region | none |
86
92
  | `pf-dynamodb-lsi-attribute-definitions` | AWS::DynamoDB::Table | LSI key attributes must be defined in AttributeDefinitions | none |
87
93
  | `pf-dynamodb-lsi-shape` | AWS::DynamoDB::Table | An LSI needs a RANGE key and the table's leading hash key | none |
94
+ | `pf-dynamodb-table-name-format` | AWS::DynamoDB::Table<br>AWS::DynamoDB::GlobalTable | Table names allow only letters, numbers, underscore, dot and hyphen (max 255) | none |
88
95
  | `pf-dynamodb-table-name-length` | AWS::DynamoDB::Table | TableName must be at least 3 characters | pending-engine |
89
96
  | `pf-ec2-instance-ami-arch` | AWS::EC2::Instance | Instance type architecture must match the SSM public-parameter AMI architecture | none |
97
+ | `pf-ec2-launch-template-name` | AWS::EC2::LaunchTemplate | Launch template names are 3-128 chars of letters, numbers and -()./_ | none |
90
98
  | `pf-ec2-natgw-allocation` | AWS::EC2::NatGateway | NAT gateway AllocationId is required for public connectivity and forbidden for private | none |
91
99
  | `pf-ec2-pg-cluster-burstable` | AWS::EC2::Instance<br>AWS::EC2::PlacementGroup | Burstable instance types are not supported in cluster placement groups | none |
92
100
  | `pf-ec2-route-target-exactly-one` | AWS::EC2::Route | A route must name exactly one target | none |
93
101
  | `pf-ec2-sg-cidr-valid` | AWS::EC2::SecurityGroup<br>AWS::EC2::SecurityGroupIngress<br>AWS::EC2::SecurityGroupEgress | Security group rule CidrIp must be a well-formed IPv4 CIDR | none |
94
102
  | `pf-ec2-sg-group-name` | AWS::EC2::SecurityGroup | Security group names may not start with sg- | none |
95
103
  | `pf-ec2-sg-port-range` | AWS::EC2::SecurityGroup<br>AWS::EC2::SecurityGroupIngress<br>AWS::EC2::SecurityGroupEgress | Security group TCP/UDP ports must be within 0-65535 and FromPort <= ToPort | none |
104
+ | `pf-ec2-sg-rule-description` | AWS::EC2::SecurityGroup<br>AWS::EC2::SecurityGroupIngress<br>AWS::EC2::SecurityGroupEgress | Security group rule descriptions are limited to 255 chars of a restricted ASCII set | none |
96
105
  | `pf-ec2-sg-source-exclusive` | AWS::EC2::SecurityGroup<br>AWS::EC2::SecurityGroupIngress<br>AWS::EC2::SecurityGroupEgress | A security group rule takes exactly one source/destination field | none |
106
+ | `pf-ec2-subnet-cidr-size` | AWS::EC2::Subnet | Subnet IPv4 CIDR netmask must be between /16 and /28 | none |
97
107
  | `pf-ec2-userdata-size` | AWS::EC2::Instance<br>AWS::EC2::LaunchTemplate | EC2 user data is limited to 16384 bytes | none |
98
108
  | `pf-ec2-volume-iops` | AWS::EC2::Volume | EBS Iops/Throughput must match the volume type's supported ranges and ratios | none |
99
109
  | `pf-ec2-volume-iops-required` | AWS::EC2::Volume | io1 and io2 volumes require the Iops property | none |
@@ -103,6 +113,7 @@
103
113
  | `pf-ec2-vpce-gateway-service` | AWS::EC2::VPCEndpoint | Gateway VPC endpoints only exist for S3 and DynamoDB | none |
104
114
  | `pf-ec2-vpce-service-region` | AWS::EC2::VPCEndpoint | VPC endpoint service names must use the deploy region unless ServiceRegion is set | none |
105
115
  | `pf-ec2-vpce-type-config` | AWS::EC2::VPCEndpoint | SubnetIds are not supported on Gateway endpoints (and RouteTableIds only on Gateway) | none |
116
+ | `pf-ecs-cluster-name` | AWS::ECS::Cluster | ECS cluster names allow only letters, numbers, hyphen and underscore (max 255) | none |
106
117
  | `pf-ecs-container-definitions-empty` | AWS::ECS::TaskDefinition | ContainerDefinitions must contain at least one container | pending-engine |
107
118
  | `pf-ecs-container-memory-over-task` | AWS::ECS::TaskDefinition | A container Memory must not exceed the task-level Memory | none |
108
119
  | `pf-ecs-container-memory-required` | AWS::ECS::TaskDefinition | A container needs Memory or MemoryReservation when the task sets no Memory | none |
@@ -118,19 +129,22 @@
118
129
  | `pf-ecs-service-fargate-placement` | AWS::ECS::Service | Placement constraints and strategies are not supported on FARGATE | none |
119
130
  | `pf-ecs-service-launch-type-capacity-provider` | AWS::ECS::Service | LaunchType and CapacityProviderStrategy are mutually exclusive | none |
120
131
  | `pf-ecs-service-lb-target-exclusive` | AWS::ECS::Service | A load balancer entry takes either TargetGroupArn or LoadBalancerName, not both | none |
132
+ | `pf-ecs-service-name` | AWS::ECS::Service | ECS service names allow only letters, numbers, hyphen and underscore (max 255) | none |
121
133
  | `pf-ecs-service-network-config-mode` | AWS::ECS::Service<br>AWS::ECS::TaskDefinition | NetworkConfiguration requires an awsvpc task definition | none |
122
134
  | `pf-ecs-service-platform-version-ec2` | AWS::ECS::Service | PlatformVersion is not allowed with the EC2 launch type | none |
135
+ | `pf-ecs-taskdef-family` | AWS::ECS::TaskDefinition | Task definition Family allows only letters, numbers, hyphen and underscore | none |
123
136
  | `pf-elbv2-alb-subnet-count` | AWS::ElasticLoadBalancingV2::LoadBalancer | Application load balancers need at least two subnets | none |
124
137
  | `pf-elbv2-app-cookie-name` | AWS::ElasticLoadBalancingV2::TargetGroup | app_cookie stickiness requires a cookie name | none |
125
138
  | `pf-elbv2-hc-timeout-interval` | AWS::ElasticLoadBalancingV2::TargetGroup | Health check timeout must be strictly smaller than the interval | none |
126
139
  | `pf-elbv2-lambda-target-protocol` | AWS::ElasticLoadBalancingV2::TargetGroup | Lambda target groups cannot specify Protocol | none |
127
140
  | `pf-elbv2-lb-idle-timeout-range` | AWS::ElasticLoadBalancingV2::LoadBalancer | ALB idle_timeout.timeout_seconds must be between 1 and 4000 | none |
128
- | `pf-elbv2-lb-name` | AWS::ElasticLoadBalancingV2::LoadBalancer | Load balancer names cannot begin with internal- or end with a hyphen | none |
141
+ | `pf-elbv2-lb-name` | AWS::ElasticLoadBalancingV2::LoadBalancer | Load balancer names are at most 32 alphanumeric/hyphen chars and cannot begin with internal- or a hyphen | none |
129
142
  | `pf-elbv2-listener-protocol-lb-type` | AWS::ElasticLoadBalancingV2::Listener<br>AWS::ElasticLoadBalancingV2::LoadBalancer | Listener protocols must match the load balancer type | none |
130
143
  | `pf-elbv2-rule-priority-unique` | AWS::ElasticLoadBalancingV2::ListenerRule | Listener rules on the same listener must have distinct priorities | none |
131
144
  | `pf-elbv2-stickiness-type-protocol` | AWS::ElasticLoadBalancingV2::TargetGroup | Stickiness type lb_cookie needs an HTTP-protocol target group, source_ip a TCP one | none |
132
145
  | `pf-elbv2-tcp-health-check-path` | AWS::ElasticLoadBalancingV2::TargetGroup | TCP health checks cannot take a health check path | none |
133
146
  | `pf-elbv2-tg-deregistration-delay-range` | AWS::ElasticLoadBalancingV2::TargetGroup | Target group deregistration_delay.timeout_seconds must be between 0 and 3600 | none |
147
+ | `pf-elbv2-tg-name` | AWS::ElasticLoadBalancingV2::TargetGroup | Target group names are at most 32 alphanumeric/hyphen chars and cannot start or end with a hyphen | none |
134
148
  | `pf-elbv2-tg-slow-start-range` | AWS::ElasticLoadBalancingV2::TargetGroup | Target group slow_start.duration_seconds must be 0 or between 30 and 900 | none |
135
149
  | `pf-events-input-transformer-placeholders` | AWS::Events::Rule | InputTemplate placeholders must be declared in InputPathsMap | none |
136
150
  | `pf-events-pattern-empty` | AWS::Events::Rule | An empty EventPattern counts as no pattern at all | none |
@@ -146,12 +160,14 @@
146
160
  | `pf-iam-instance-profile-single-role` | AWS::IAM::InstanceProfile | An instance profile holds exactly one role | none |
147
161
  | `pf-iam-managed-policy-count` | AWS::IAM::Role<br>AWS::IAM::User<br>AWS::IAM::Group | Managed policies per identity are capped (hard maximums role 25 / user 20 / group 10) | none |
148
162
  | `pf-iam-managed-policy-size` | AWS::IAM::ManagedPolicy | Managed policy documents are limited to 6144 characters (whitespace excluded) | none |
163
+ | `pf-iam-name-format` | AWS::IAM::Role<br>AWS::IAM::User<br>AWS::IAM::Group<br>AWS::IAM::ManagedPolicy | IAM entity names allow only alphanumerics and +=,.@-_ | none |
149
164
  | `pf-iam-policy-action-format` | AWS::IAM::Role<br>AWS::IAM::Policy<br>AWS::IAM::ManagedPolicy | Actions must carry a service prefix | none |
150
165
  | `pf-iam-policy-condition-operator` | AWS::IAM::Role<br>AWS::IAM::Policy<br>AWS::IAM::ManagedPolicy | Condition operators come from a closed grammar | none |
151
166
  | `pf-iam-policy-duplicate-sid` | AWS::IAM::Role<br>AWS::IAM::Policy<br>AWS::IAM::ManagedPolicy | Statement IDs must be unique within a policy | none |
152
167
  | `pf-iam-policy-effect-case` | AWS::IAM::Role<br>AWS::IAM::Policy<br>AWS::IAM::ManagedPolicy | Effect is case-sensitive Allow or Deny | none |
153
168
  | `pf-iam-policy-exclusive-fields` | AWS::IAM::Role<br>AWS::IAM::Policy<br>AWS::IAM::ManagedPolicy | Action/NotAction and Resource/NotResource are exclusive pairs | none |
154
169
  | `pf-iam-policy-resource-format` | AWS::IAM::Role<br>AWS::IAM::Policy<br>AWS::IAM::ManagedPolicy | Resources must be ARNs or * | none |
170
+ | `pf-iam-policy-sid-format` | AWS::IAM::Role<br>AWS::IAM::User<br>AWS::IAM::Group<br>AWS::IAM::Policy<br>AWS::IAM::ManagedPolicy | Policy statement Sid must be alphanumeric | none |
155
171
  | `pf-iam-policy-statement-resource-required` | AWS::IAM::Role<br>AWS::IAM::Policy<br>AWS::IAM::ManagedPolicy | Identity policy statements need Resource or NotResource | none |
156
172
  | `pf-iam-policy-version` | AWS::IAM::Role<br>AWS::IAM::Policy<br>AWS::IAM::ManagedPolicy | Policy Version must be 2012-10-17 or 2008-10-17 | none |
157
173
  | `pf-iam-trust-policy-no-resource` | AWS::IAM::Role | Trust policies cannot carry a Resource field | none |
@@ -175,12 +191,14 @@
175
191
  | `pf-rds-backup-window-duration` | AWS::RDS::DBInstance | The backup window must be at least 30 minutes | none |
176
192
  | `pf-rds-backup-window-format` | AWS::RDS::DBInstance | PreferredBackupWindow must be hh24:mi-hh24:mi | none |
177
193
  | `pf-rds-dbname-format` | AWS::RDS::DBInstance | postgres DBName must begin with a letter | none |
194
+ | `pf-rds-description-printable` | AWS::RDS::DBSubnetGroup<br>AWS::RDS::DBParameterGroup | RDS group descriptions must be printable ASCII | none |
178
195
  | `pf-rds-gp3-iops-storage-threshold` | AWS::RDS::DBInstance | gp3 below 400 GiB cannot take custom Iops or StorageThroughput (postgres/mysql) | none |
179
196
  | `pf-rds-io1-iops-ratio` | AWS::RDS::DBInstance | postgres io1 Iops may not exceed 50 per GiB of storage | none |
180
197
  | `pf-rds-iops-required` | AWS::RDS::DBInstance | io1 and io2 storage require the Iops property | none |
181
198
  | `pf-rds-password-valid` | AWS::RDS::DBInstance<br>AWS::RDS::DBCluster | MasterUserPassword must be at least 8 characters without '/', '@', '\"' or spaces | none |
182
199
  | `pf-rds-port-range` | AWS::RDS::DBInstance | The database port must be within 1150-65535 | none |
183
200
  | `pf-rds-serverless-v2-capacity` | AWS::RDS::DBCluster | Serverless v2 MinCapacity must not exceed MaxCapacity, and MaxCapacity is at most 256 | none |
201
+ | `pf-rds-subnet-group-name` | AWS::RDS::DBSubnetGroup | DB subnet group names allow only letters, numbers, spaces, dot, underscore and hyphen | none |
184
202
  | `pf-rds-window-overlap` | AWS::RDS::DBInstance | The backup window and the maintenance window must not overlap | none |
185
203
  | `pf-route53-alias-cloudfront-zone-id` | AWS::Route53::RecordSet | A CloudFront alias target must use hosted zone Z2FDTNDATAQYW2 | none |
186
204
  | `pf-route53-apex-cname` | AWS::Route53::RecordSet<br>AWS::Route53::HostedZone | A CNAME record is not permitted at the zone apex | none |
@@ -208,4 +226,8 @@
208
226
  | `pf-scheduler-flexible-window` | AWS::Scheduler::Schedule | FLEXIBLE mode needs MaximumWindowInMinutes, OFF forbids it | none |
209
227
  | `pf-scheduler-rate-positive` | AWS::Scheduler::Schedule | A Scheduler rate() value must be positive | none |
210
228
  | `pf-sns-fifo-topic-name` | AWS::SNS::Topic | FIFO topic names must end with '.fifo' (and '.fifo' names require FifoTopic) | none |
229
+ | `pf-sns-topic-name-format` | AWS::SNS::Topic | Topic names allow only letters, numbers, hyphen and underscore (plus a .fifo suffix) | none |
230
+ | `pf-sqs-queue-name-format` | AWS::SQS::Queue | Queue names allow only letters, numbers, hyphen and underscore (max 80, plus a .fifo suffix) | none |
211
231
  | `pf-sfn-asl-missing-state` | AWS::StepFunctions::StateMachine | ASL Next/Default/Choices must reference a defined state (top-level states; a dangling StartAt is covered by engine rule E3601) | none |
232
+ | `pf-tags-aws-prefix` | * | Tag keys may not use the reserved aws: prefix | none |
233
+ | `pf-tags-count-max` | * | A resource may carry at most 50 tags | none |
package/lib/index.js CHANGED
@@ -17,7 +17,7 @@ const rules_generated_1 = require("./rules.generated");
17
17
  * Preflight.apply(app);
18
18
  */
19
19
  class Preflight {
20
- static [JSII_RTTI_SYMBOL_1] = { fqn: "cdk-preflight.Preflight", version: "0.0.28" };
20
+ static [JSII_RTTI_SYMBOL_1] = { fqn: "cdk-preflight.Preflight", version: "0.0.30" };
21
21
  /**
22
22
  * Register the cdk-preflight rules on an App or Stage.
23
23
  */