cdk-preflight 0.0.40 → 0.0.41

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 CHANGED
@@ -9598,6 +9598,6 @@
9598
9598
  "symbolId": "src/index:PreflightOptions"
9599
9599
  }
9600
9600
  },
9601
- "version": "0.0.40",
9602
- "fingerprint": "PbEn3YhgIMxnTYEt8A4pmaqh3sYJbtevFgL42ipTfWM="
9601
+ "version": "0.0.41",
9602
+ "fingerprint": "psRz6YDSgwEg4ORyiDkQzoiCiLbO0gbtwIwQw3XEo/I="
9603
9603
  }
package/AGENTS.md CHANGED
@@ -30,7 +30,7 @@ Five other validation layers sit around a CDK app. Exactly one of them is a boun
30
30
  | CDK L1 generated validators (`CfnXxx`) | synth, every CDK app | type and required-property checks only — never value ranges, patterns, or cross-field rules | **No practical overlap**: pack rules are value / cross-field constraints by construction |
31
31
  | Bundled engine default rules (`@aws/cloudformation-validate`: SCHEMA / CFN_LINT / ENGINE) | synth, via this plugin | patched registry-schema ranges/patterns/enums + cfn-lint rules | **The hard boundary** (principle 1) **and the only retirement trigger**. If the bare engine reports ERROR/FATAL on the minimal violating template, the rule must not exist — enforced by the jest duplication guard, which turns red by itself when the engine catches up |
32
32
  | cfn-lint (external CLI) | outside the synth path (a separate CI step, if the user runs one) | near-parity with the bundled engine | **Not a boundary** — never disqualifies a rule. A check cfn-lint has but the engine lacks is an upstream-PR candidate *for the engine* (project policy: contribute to cloudformation-validate, not to cfn-lint) |
33
- | CloudFormation server-side pre-deploy validation | CreateStack / UpdateStack / CreateChangeSet, before resources are touched | property syntax against RAW registry schemas for non-excluded types; resource name conflicts | **Effectively no overlap** with this pack's domain: ~420 resource types are excluded (IAM, EC2 SG, ECS, RDS, SFN, …) and raw schemas carry none of the doc-only limits — 0/16 real-world cases detected (measured 2026-09, cdk-validation-gap-research). Never a reason to reject a rule |
33
+ | CloudFormation server-side pre-deploy validation | CreateStack / UpdateStack / CreateChangeSet, before resources are touched | property syntax against RAW registry schemas for non-excluded types; resource name conflicts | **Almost no overlap** with this pack's domain: ~420 resource types are excluded (IAM, EC2 SG, ECS, RDS, SFN, …) and raw schemas carry none of the doc-only limits — 0/16 real-world cases detected (measured 2026-09, cdk-validation-gap-research). Not something to *look* for, but when it does fire it is a **retirement trigger** like the engine: a single-property range that the bundled schema misses can still be enforced here (`AWS::Kinesis::Stream.RetentionPeriodHours` < 24 fails as a stack-level `Validation failed with 1 error(s)`, measured 2026-09-06 — that candidate was dropped) |
34
34
  | CloudFormation + service APIs | deploy (CREATE/UPDATE) | everything else: cross-field rules, service-side business rules, quotas | **The target, not a duplicate to avoid.** A rule exists *iff* it front-runs a real deploy-time failure here; `meta.yaml#repro` (real-deploy gate) proves that equivalence |
35
35
 
36
36
  Selection algorithm for a new rule, in order: (1) duplication guard — run the minimal violating template through the bare engine; any built-in ERROR/FATAL kills the candidate. A **WARN-class-only** engine finding (`W…`) does *not* kill it but marks a gray zone: the engine knows about the constraint and under-classifies it, so nothing blocks the deploy (`strict` promotes only ERROR/FATAL) — prefer filing an upstream severity issue, and if a stopgap rule ships anyway, mark it `upstream: pending-engine` so it retires with the upstream fix. (2) real-deploy gate — the fail template must actually fail CREATE with the predicted service error; a fail template that deploys kills the candidate (it happened: the "30-day minimum before STANDARD_IA" and the "4096-char ZipFile" constraints are documented but not enforced, so those rules were dropped). There is no third gate: L1/L2 coverage, marginal value, and how exotic the mistake looks never disqualify a candidate.
@@ -176,3 +176,9 @@ bench/ # real-deploy verification (needs an AWS account; no
176
176
  - **Fixture name tagging must skip reference properties.** The generator that suffixes fixture names with the rule id has to key off the resource type: `ACLName` is the name on `AWS::MemoryDB::ACL` but a *reference* on `AWS::MemoryDB::Cluster`, and tagging it made every MemoryDB pass template fail with "ACL open-access-port not found" (measured 2026-09-06). Same for `ParameterGroupName` / `CacheParameterGroupName`.
177
177
  - **`bench/verify-rule.sh` polls for 30 minutes** (raised from 15 on 2026-09-06): ElastiCache and MemoryDB clusters take 10-25 minutes to create and about as long to roll back, and the shorter poll reported TIMEOUT / INCONCLUSIVE on rules whose constraint had already fired.
178
178
  - **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.
179
+ - **`as` is a reserved keyword in the engine's Rego build** (measured 2026-09-06): `acts := object.get(s, "Action", null)` is fine but `as := ...` fails to parse ("unexpected keyword `as`") and, like every parse error, takes the whole custom package down — every rule stops firing, and the jest failure names an unrelated rule.
180
+ - **A Managed Flink application deploys with no `ApplicationConfiguration` at all** (measured 2026-09-06), which is what makes `AWS::KinesisAnalyticsV2::Application` fixtures cheap: no S3 bucket, no JAR, no Glue database, just an IAM role the service can assume. Adding a "minimal" code stanza is worse than none — CreateApplication really fetches the S3 object (`We are unable to get the specified fileKey`) and rejects `PLAINTEXT` for a Flink runtime.
181
+ - **A Studio (ZEPPELIN-FLINK) application cannot be created without `glue:GetDatabase` on its service role**, so a Studio *pass* fixture is expensive. Every Studio-specific check (application mode, snapshots, system rollback, custom artifacts, catalog region, note JSON) fires before the Glue call, so the fail fixture can be a Studio app while the clean fixture stays a plain Flink app (measured 2026-09-06).
182
+ - **The CloudFormation handler can word the same rejection differently from the API** (measured 2026-09-06): CreateStream says `ShardCount cannot be set while creating stream in On-Demand StreamMode`, the stack event says `ShardCount is not expected when StreamMode=ON_DEMAND`. Quote the handler's wording in the rule message — that is the string the user will search for.
183
+ - **Kinesis rejects a cross-region ARN before it looks the resource up** ("The region specified in the ARN ... does not match the endpoint region", measured 2026-09-06 for `RegisterStreamConsumer` and `PutResourcePolicy`; `StartStreamEncryption` answers `KMSNotFoundException: Invalid arn us-west-2`). A region-binding repro therefore needs no real resource in the other region.
184
+ - **CloudFormation's server-side validation does enforce some raw-schema ranges the bundled engine misses** (measured 2026-09-06): `RetentionPeriodHours: 12` on `AWS::Kinesis::Stream` fails before any resource is touched, as a stack-level `Validation failed with 1 error(s). Call DescribeEvents ...` with the stack itself as the LogicalResourceId — while the engine's patched schema carries only the 8760 maximum. A fail template that dies at the *stack* level rather than in a resource handler is the tell; the candidate is a duplicate and does not ship.
package/docs/rules.md CHANGED
@@ -252,6 +252,39 @@
252
252
  | `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 |
253
253
  | `pf-iam-trust-policy-no-resource` | AWS::IAM::Role | Trust policies cannot carry a Resource field | none |
254
254
  | `pf-iam-trust-policy-service-principal` | AWS::IAM::Role | Service principals live under amazonaws.com | none |
255
+ | `pf-kinesis-consumer-duplicate-name` | AWS::Kinesis::StreamConsumer | Two consumers of one stream cannot share a ConsumerName | none |
256
+ | `pf-kinesis-consumer-stream-region` | AWS::Kinesis::StreamConsumer | A stream consumer must reference a stream in its own region | none |
257
+ | `pf-kinesis-encryption-key-region` | AWS::Kinesis::Stream | The stream encryption key must live in the stream region | none |
258
+ | `pf-kinesis-on-demand-shard-count` | AWS::Kinesis::Stream | An on-demand stream cannot set ShardCount | none |
259
+ | `pf-kinesis-provisioned-shard-count` | AWS::Kinesis::Stream | A provisioned stream must set ShardCount | none |
260
+ | `pf-kinesis-resource-policy-action` | AWS::Kinesis::ResourcePolicy | Resource policy actions must be plain kinesis: actions | none |
261
+ | `pf-kinesis-resource-policy-principal` | AWS::Kinesis::ResourcePolicy | Every policy statement needs a Principal (and no NotPrincipal) | none |
262
+ | `pf-kinesis-resource-policy-region` | AWS::Kinesis::ResourcePolicy | A resource policy must target a stream in its own region | none |
263
+ | `pf-kinesis-resource-policy-resource` | AWS::Kinesis::ResourcePolicy | Every policy statement Resource must equal the ResourceArn | none |
264
+ | `pf-kinesis-shard-level-metrics-all` | AWS::Kinesis::Stream | DesiredShardLevelMetrics cannot mix ALL with named metrics | none |
265
+ | `pf-kinesis-warm-throughput-shard-count` | AWS::Kinesis::Stream | WarmThroughputMiBps cannot be combined with ShardCount or provisioned mode | none |
266
+ | `pf-kinesisanalytics-application-mode-runtime` | AWS::KinesisAnalyticsV2::Application | ApplicationMode must match the runtime family | none |
267
+ | `pf-kinesisanalytics-checkpoint-configuration-type` | AWS::KinesisAnalyticsV2::Application | CheckpointConfiguration needs ConfigurationType CUSTOM to carry values | none |
268
+ | `pf-kinesisanalytics-code-content-member` | AWS::KinesisAnalyticsV2::Application | CodeContent must carry exactly the member its type names | none |
269
+ | `pf-kinesisanalytics-code-content-type` | AWS::KinesisAnalyticsV2::Application | CodeContentType must match the runtime family | none |
270
+ | `pf-kinesisanalytics-custom-artifact-source` | AWS::KinesisAnalyticsV2::Application | Every Studio custom artifact needs an S3 location or a Maven reference | none |
271
+ | `pf-kinesisanalytics-encryption-key-type` | AWS::KinesisAnalyticsV2::Application | KeyId presence must match the encryption KeyType | none |
272
+ | `pf-kinesisanalytics-glue-database-region` | AWS::KinesisAnalyticsV2::Application | The Studio Glue catalog database must be in the application region | none |
273
+ | `pf-kinesisanalytics-log-stream-arn` | AWS::KinesisAnalyticsV2::ApplicationCloudWatchLoggingOption | LogStreamARN must name a log stream, not a log group | none |
274
+ | `pf-kinesisanalytics-maven-artifact-type` | AWS::KinesisAnalyticsV2::Application | MavenReference is only valid for DEPENDENCY_JAR artifacts | none |
275
+ | `pf-kinesisanalytics-monitoring-configuration-type` | AWS::KinesisAnalyticsV2::Application | MonitoringConfiguration needs ConfigurationType CUSTOM to carry values | none |
276
+ | `pf-kinesisanalytics-parallelism-configuration-type` | AWS::KinesisAnalyticsV2::Application | ParallelismConfiguration needs ConfigurationType CUSTOM to carry values | none |
277
+ | `pf-kinesisanalytics-parallelism-per-kpu` | AWS::KinesisAnalyticsV2::Application | ParallelismPerKPU cannot exceed 8 | none |
278
+ | `pf-kinesisanalytics-property-group-duplicate` | AWS::KinesisAnalyticsV2::Application | PropertyGroupId must be unique within an application | none |
279
+ | `pf-kinesisanalytics-runtime-deprecated` | AWS::KinesisAnalyticsV2::Application | Deprecated runtime environments can no longer be created | none |
280
+ | `pf-kinesisanalytics-service-role-account` | AWS::KinesisAnalyticsV2::Application | ServiceExecutionRole must belong to the deploying account | none |
281
+ | `pf-kinesisanalytics-snapshot-runtime` | AWS::KinesisAnalyticsV2::Application | ApplicationSnapshotConfiguration is not applicable to Studio runtimes | none |
282
+ | `pf-kinesisanalytics-sql-configuration-runtime` | AWS::KinesisAnalyticsV2::Application | SqlApplicationConfiguration belongs to the SQL runtime only | none |
283
+ | `pf-kinesisanalytics-sql-only-resource` | AWS::KinesisAnalyticsV2::ApplicationOutput<br>AWS::KinesisAnalyticsV2::ApplicationReferenceDataSource | Outputs and reference data sources need a SQL application | none |
284
+ | `pf-kinesisanalytics-sql-runtime-unsupported` | AWS::KinesisAnalyticsV2::Application | SQL applications can no longer be created | none |
285
+ | `pf-kinesisanalytics-system-rollback-runtime` | AWS::KinesisAnalyticsV2::Application | ApplicationSystemRollbackConfiguration is not applicable to Studio runtimes | none |
286
+ | `pf-kinesisanalytics-zeppelin-configuration-runtime` | AWS::KinesisAnalyticsV2::Application | ZeppelinApplicationConfiguration belongs to Studio runtimes only | none |
287
+ | `pf-kinesisanalytics-zeppelin-note-json` | AWS::KinesisAnalyticsV2::Application | Studio TextContent must be a Zeppelin note JSON | none |
255
288
  | `pf-kms-alias-name` | AWS::KMS::Alias | AliasName must not start with alias/aws/ (reserved for AWS managed keys) and may not contain a colon (the CloudFormation schema allows it, CreateAlias does not) | none |
256
289
  | `pf-kms-alias-target` | AWS::KMS::Alias | TargetKeyId must be a key id or key ARN (not an alias) of a key in the same account and region | none |
257
290
  | `pf-kms-key-origin` | AWS::KMS::Key | Origin AWS_CLOUDHSM and EXTERNAL_KEY_STORE cannot be created by CloudFormation, and Origin EXTERNAL does not support ML-DSA key specs | 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.40" };
20
+ static [JSII_RTTI_SYMBOL_1] = { fqn: "cdk-preflight.Preflight", version: "0.0.41" };
21
21
  /**
22
22
  * Register the cdk-preflight rules on an App or Stage.
23
23
  */