cdk-preflight 0.0.18 → 0.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.jsii +2 -2
- package/AGENTS.md +3 -0
- package/docs/rules.md +20 -0
- package/lib/index.js +1 -1
- package/lib/rules.generated.js +226 -1
- package/package.json +1 -1
package/.jsii
CHANGED
|
@@ -9598,6 +9598,6 @@
|
|
|
9598
9598
|
"symbolId": "src/index:PreflightOptions"
|
|
9599
9599
|
}
|
|
9600
9600
|
},
|
|
9601
|
-
"version": "0.0.
|
|
9602
|
-
"fingerprint": "
|
|
9601
|
+
"version": "0.0.20",
|
|
9602
|
+
"fingerprint": "5pdMGQLdJued4znsVcjqiZpi89l/FzVBfV3KZh/QfQU="
|
|
9603
9603
|
}
|
package/AGENTS.md
CHANGED
|
@@ -82,6 +82,7 @@ bench/ # real-deploy verification (needs an AWS account; no
|
|
|
82
82
|
- **Proving a property absent** (measured 2026-09-02, 1.7.0-beta): `resolve()` is undefined for a missing key AND for an unresolvable value (e.g. `Ref` to a no-default parameter), so `not resolve(...)` misfires on present-but-unresolvable values. The only reliable absence proof is the preprocessed document: `props := input.resources[name].properties; is_object(props); object.get(props, "<Key>", "__pf_absent") == "__pf_absent"`. The `is_object` guard fails closed if the internal shape ever changes. This is the sanctioned exception to "don't depend on `input` internals". Reference implementations: `pf-ecs-container-memory-required`, `pf-ecs-fargate-task-cpu-memory`.
|
|
83
83
|
- `flatten_list()` returns an **empty list for an absent path** — it cannot distinguish "absent" from "present and empty" (measured 2026-09-02). Use the `input.resources` idiom above when the distinction matters (`pf-ecs-container-definitions-empty`).
|
|
84
84
|
- **Intrinsics inside `input.resources` values are marker objects, never strings** (measured 2026-09-03, 1.7.0-beta): `Fn::GetAtt` appears as `{"__kind": "getatt:Arn", "__ref": "B"}` and `Fn::Sub` as `{"__dynamic": "Sub:..."}` at any nesting depth. A plain `is_string(v)` guard therefore safely mutes rules that judge string shapes (ARN format, prefixes) on values users wired via intrinsics — no logical-ID false positives. Reference implementations: `pf-iam-policy-resource-format`, `pf-iam-policy-action-format`.
|
|
85
|
+
- **Dynamic reference strings are markerized too** (measured 2026-09-03): a literal `{{resolve:ssm:/path}}` property value surfaces as `{"__dynamic": "dynamic reference: {{resolve:ssm:/path}}", "__param_type": "String"}` and `resolve()` is undefined for it. A rule that judges the reference text itself (e.g. the SSM parameter path) must read the raw property with `object.get` and extract the `__dynamic` string. Reference implementation: `pf-ec2-instance-ami-arch`.
|
|
85
86
|
- **Deploy-region rules**: the enforce plugin injects a generated module defining `deploy_region` whenever the app-level region is concrete (`deployEnvironmentModule` in `src/private/enforce.ts`; the test harness injects `us-east-1` for fixtures). Rules must read it as `data.cdk_preflight.deploy_region` — the data reference is undefined when not injected, so the rule skips; a bare `deploy_region` variable would be a compile error. Consequences: region-dependent rules are silent in warn mode (`enforce: false` hands rules to the CDK built-in plugin, which we cannot inject into) and in region-agnostic apps; say so in `meta.yaml#repro.evidence`. Reference implementations: `pf-dynamodb-global-table-replica-region`, `pf-dynamodb-kinesis-stream-region`.
|
|
86
87
|
- Helper rules must use a unique `_pf_<rule>_...` prefix (all rules share one package).
|
|
87
88
|
3. `npx projen bundle-rules` then `npx jest test/rules.test.ts test/structure.test.ts` — the duplication guard and fixture checks run here.
|
|
@@ -105,3 +106,5 @@ bench/ # real-deploy verification (needs an AWS account; no
|
|
|
105
106
|
- `to_number(null)` evaluates to `0` (not undefined). When reading optional numbers via `object.get(x, key, null)`, guard with `!= null` before `to_number`, or an absent property silently becomes 0 and can fire the rule (this bit the S3 lifecycle rules during development).
|
|
106
107
|
- The Rego parser rejects two-variable `some k, v in obj` **inside comprehensions** ("unexpected keyword `some`"; fine in rule bodies). Use `some k in object.keys(obj)` and index instead.
|
|
107
108
|
- The CDK renders `Acknowledge with 'cdk-preflight::<rule-id>'` under enforce-mode errors, but `Validations.acknowledge()` currently suppresses only annotation warnings (`validations.ts`: "Currently only annotation warnings can be suppressed") — the hint is inert for policy violations. The working opt-outs in enforce mode are `exclude` and `enforce: false`; do not document the acknowledge mechanism for enforce mode.
|
|
109
|
+
- **`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).
|
|
110
|
+
- 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.
|
package/docs/rules.md
CHANGED
|
@@ -23,6 +23,12 @@
|
|
|
23
23
|
| `pf-apigwv2-jwt-authorizer-config` | AWS::ApiGatewayV2::Authorizer | JWT authorizers need JwtConfiguration | none |
|
|
24
24
|
| `pf-apigwv2-request-authorizer-payload-version` | AWS::ApiGatewayV2::Authorizer | REQUEST authorizers on HTTP APIs need AuthorizerPayloadFormatVersion | none |
|
|
25
25
|
| `pf-apigwv2-websocket-route-selection` | AWS::ApiGatewayV2::Api | WebSocket APIs need RouteSelectionExpression | none |
|
|
26
|
+
| `pf-asg-cooldown-non-negative` | AWS::AutoScaling::AutoScalingGroup | Cooldown cannot be negative | none |
|
|
27
|
+
| `pf-asg-desired-capacity-range` | AWS::AutoScaling::AutoScalingGroup | DesiredCapacity must sit between MinSize and MaxSize | none |
|
|
28
|
+
| `pf-asg-health-check-grace-period` | AWS::AutoScaling::AutoScalingGroup | HealthCheckGracePeriod cannot be negative | none |
|
|
29
|
+
| `pf-asg-ondemand-percentage-max` | AWS::AutoScaling::AutoScalingGroup | OnDemandPercentageAboveBaseCapacity tops out at 100 | none |
|
|
30
|
+
| `pf-asg-target-value-positive` | AWS::AutoScaling::ScalingPolicy | Target tracking needs a positive TargetValue | none |
|
|
31
|
+
| `pf-asg-zone-or-subnet-required` | AWS::AutoScaling::AutoScalingGroup | A group needs AvailabilityZones, AvailabilityZoneIds, or subnets | none |
|
|
26
32
|
| `pf-agentcore-gateway-jwt-authorizer` | AWS::BedrockAgentCore::Gateway | Gateways with AuthorizerType CUSTOM_JWT require AuthorizerConfiguration | none |
|
|
27
33
|
| `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 |
|
|
28
34
|
| `pf-cloudfront-acm-cert-region` | AWS::CloudFront::Distribution | CloudFront viewer certificates must live in us-east-1 | none |
|
|
@@ -64,9 +70,23 @@
|
|
|
64
70
|
| `pf-dynamodb-lsi-attribute-definitions` | AWS::DynamoDB::Table | LSI key attributes must be defined in AttributeDefinitions | none |
|
|
65
71
|
| `pf-dynamodb-lsi-shape` | AWS::DynamoDB::Table | An LSI needs a RANGE key and the table's leading hash key | none |
|
|
66
72
|
| `pf-dynamodb-table-name-length` | AWS::DynamoDB::Table | TableName must be at least 3 characters | pending-engine |
|
|
73
|
+
| `pf-ec2-instance-ami-arch` | AWS::EC2::Instance | Instance type architecture must match the SSM public-parameter AMI architecture | none |
|
|
74
|
+
| `pf-ec2-natgw-allocation` | AWS::EC2::NatGateway | NAT gateway AllocationId is required for public connectivity and forbidden for private | none |
|
|
75
|
+
| `pf-ec2-pg-cluster-burstable` | AWS::EC2::Instance<br>AWS::EC2::PlacementGroup | Burstable instance types are not supported in cluster placement groups | none |
|
|
76
|
+
| `pf-ec2-route-target-exactly-one` | AWS::EC2::Route | A route must name exactly one target | none |
|
|
77
|
+
| `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 |
|
|
78
|
+
| `pf-ec2-sg-group-name` | AWS::EC2::SecurityGroup | Security group names may not start with sg- | none |
|
|
67
79
|
| `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 |
|
|
80
|
+
| `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 |
|
|
68
81
|
| `pf-ec2-userdata-size` | AWS::EC2::Instance<br>AWS::EC2::LaunchTemplate | EC2 user data is limited to 16384 bytes | none |
|
|
69
82
|
| `pf-ec2-volume-iops` | AWS::EC2::Volume | EBS Iops/Throughput must match the volume type's supported ranges and ratios | none |
|
|
83
|
+
| `pf-ec2-volume-iops-required` | AWS::EC2::Volume | io1 and io2 volumes require the Iops property | none |
|
|
84
|
+
| `pf-ec2-volume-kms-encrypted` | AWS::EC2::Volume | KmsKeyId on a volume requires Encrypted to be true | none |
|
|
85
|
+
| `pf-ec2-volume-size-minimum` | AWS::EC2::Volume | EBS volume size must meet the volume type minimum (io1/io2 4 GiB, st1/sc1 125 GiB) | none |
|
|
86
|
+
| `pf-ec2-vpc-cidr-block-size` | AWS::EC2::VPC | VPC IPv4 CIDR block netmask must be between /16 and /28 | none |
|
|
87
|
+
| `pf-ec2-vpce-gateway-service` | AWS::EC2::VPCEndpoint | Gateway VPC endpoints only exist for S3 and DynamoDB | none |
|
|
88
|
+
| `pf-ec2-vpce-service-region` | AWS::EC2::VPCEndpoint | VPC endpoint service names must use the deploy region unless ServiceRegion is set | none |
|
|
89
|
+
| `pf-ec2-vpce-type-config` | AWS::EC2::VPCEndpoint | SubnetIds are not supported on Gateway endpoints (and RouteTableIds only on Gateway) | none |
|
|
70
90
|
| `pf-ecs-container-definitions-empty` | AWS::ECS::TaskDefinition | ContainerDefinitions must contain at least one container | pending-engine |
|
|
71
91
|
| `pf-ecs-container-memory-over-task` | AWS::ECS::TaskDefinition | A container Memory must not exceed the task-level Memory | none |
|
|
72
92
|
| `pf-ecs-container-memory-required` | AWS::ECS::TaskDefinition | A container needs Memory or MemoryReservation when the task sets no Memory | 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.
|
|
20
|
+
static [JSII_RTTI_SYMBOL_1] = { fqn: "cdk-preflight.Preflight", version: "0.0.20" };
|
|
21
21
|
/**
|
|
22
22
|
* Register the cdk-preflight rules on an App or Stage.
|
|
23
23
|
*/
|