cdk-preflight 0.0.154 → 0.0.155

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
@@ -9600,6 +9600,6 @@
9600
9600
  "symbolId": "src/index:PreflightOptions"
9601
9601
  }
9602
9602
  },
9603
- "version": "0.0.154",
9604
- "fingerprint": "G3YXq9YeXPlGBDcps2W7CNphuqDeTe5xQBgbeYxyOuQ="
9603
+ "version": "0.0.155",
9604
+ "fingerprint": "gzhOP6Lz3vrWBte7s3o9kjW23ShFlFUmbthjHHehK/k="
9605
9605
  }
package/AGENTS.md CHANGED
@@ -144,6 +144,7 @@ If you are a subagent running one of these phases, do not spawn further agents.
144
144
  - The standard OPA `walk` builtin is NOT available in this engine. Write explicit traversals.
145
145
  - **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`.
146
146
  - `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`).
147
+ - **`flatten_list()` element counts are not the counts CloudFormation deploys** (measured 2026-09-25, issue #258). Two separate distortions: `Fn::If` is **collapsed to its true branch**, so an element that becomes `AWS::NoValue` is still counted (over-count); and `Ref` / `Fn::Split` come back as a **single element** whatever the imported list holds (under-count). The `{"__conditional": "C", "__if_true": ..., "__if_false": null}` marker only exists in the raw `input.resources[<name>].properties` document — `flatten_list()` never shows it. So a rule that makes a claim about *how many* entries there are must guard first: `_pf_countable_list(name, path)` (`rules/_lib/lists.rego`) is true only when the raw value is a literal array with no conditional element, and `_pf_unconditional_list(name, path)` is the looser guard for `count(...) > 0` presence gates, where a `Ref` list is still definitely present. Reference implementations: `pf-codebuild-secondary-artifacts-max-12` (max), `pf-msk-client-subnets-count` (min), `pf-ec2-instance-eni-exclusive` (presence gate); regression probe in `test/flatten-list-count.test.ts`. A `count(...) == 0` "must not be empty" check needs no guard — both distortions can only make it miss, never misfire. The same hazard reaches a nested array pulled out with `object.get` and it bites harder there: **`count()` of a marker object returns its key count**, so `count(object.get(s, "ClientAliases", []))` on an `Fn::If` reads as 3. Guard those with `_pf_countable_items(<the extracted value>)`, which requires an actual array (`pf-ecs-svc-connect-client-aliases-max`).
147
148
  - **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`.
148
149
  - **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`.
149
150
  - **Deploy-region rules**: the enforce plugin injects a generated module defining `deploy_region` (and `deploy_account` when the account id is concrete) 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. `data.cdk_preflight.deploy_account` works the same way (`pf-kms-key-policy-lockout` treats any account as ours when it is absent, `pf-kms-alias-target` skips its account check). 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`.
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.154" };
20
+ static [JSII_RTTI_SYMBOL_1] = { fqn: "cdk-preflight.Preflight", version: "0.0.155" };
21
21
  /**
22
22
  * Register the cdk-preflight rules on an App or Stage.
23
23
  */