cdk-preflight 0.0.144 → 0.0.146
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 +3 -3
- package/AGENTS.md +1 -0
- package/README.md +4 -2
- package/docs/rules.md +67 -0
- package/lib/index.js +1 -1
- package/lib/rules.generated.js +751 -1
- package/package.json +1 -1
package/.jsii
CHANGED
|
@@ -9416,7 +9416,7 @@
|
|
|
9416
9416
|
},
|
|
9417
9417
|
"name": "cdk-preflight",
|
|
9418
9418
|
"readme": {
|
|
9419
|
-
"markdown": "<p align=\"center\">\n <img src=\"https://raw.githubusercontent.com/badmintoncryer/cdk-preflight/main/assets/logo.png\" alt=\"cdk-preflight\" width=\"104\" height=\"104\">\n</p>\n\n<h1 align=\"center\">cdk-preflight</h1>\n\n<p align=\"center\">\n <strong>Catch deploy-time CloudFormation failures at <code>cdk synth</code> time.</strong>\n</p>\n\n<p align=\"center\">\n <a href=\"https://github.com/badmintoncryer/cdk-preflight/actions/workflows/monthly-verify.yml\"><img src=\"https://github.com/badmintoncryer/cdk-preflight/actions/workflows/monthly-verify.yml/badge.svg\" alt=\"monthly real-deploy verification\"></a>\n <a href=\"https://www.npmjs.com/package/cdk-preflight\"><img src=\"https://img.shields.io/npm/v/cdk-preflight.svg\" alt=\"npm version\"></a>\n <a href=\"https://www.npmjs.com/package/cdk-preflight\"><img src=\"https://img.shields.io/npm/dt/cdk-preflight.svg\" alt=\"npm total downloads\"></a>\n <a href=\"docs/rules.md\"><img src=\"https://img.shields.io/badge/rules-2513-blue\" alt=\"2513 bundled rules\"></a>\n</p>\n\nSome CloudFormation constraints are not expressed in resource provider schemas — they live only in documentation, in service API validation, or across multiple properties. Templates that violate them pass `cdk synth`, pass CloudFormation pre-deployment validation, and then fail minutes into a deployment, burning a rollback cycle.\n\ncdk-preflight is a curated [Rego rule pack](docs/rules.md) for exactly those constraints, evaluated with the CloudFormation validation engine that ships inside `aws-cdk-lib` (>= 2.267.0). By default a violation **fails `cdk synth`** — a template that is known to fail at deploy time never leaves your machine.\n\nThe pack aims at **every deploy-time failure that no existing CDK mechanism already catches** — nothing narrower. Every bundled rule is backed by a `fail`/`pass` template pair, and the failure has been reproduced against real AWS. The handful of rules that could not be reproduced are marked `doc-only` and report as **warnings**, as does a rule whose remaining false positives cannot be told from the template (a cross-account Lambda layer the owner may have shared): they show up in the validation report but never fail synth. Rules that the built-in validation engine already covers are deliberately **not** duplicated — a test suite enforces this.\n\n> **Requires `aws-cdk-lib` >= 2.267.0** (released 2026-08-27) — the first release that bundles\n> the CloudFormation validation engine. On older versions the rules cannot run at all.\n\n## Quick start\n\n```bash\nnpm i -D cdk-preflight\nnpx cdkpf init # inserts Preflight.apply(app) into your CDK app\n # (`npx cdkpf init` is the same command, shorter)\n```\n\nor add one line yourself:\n\n```ts\nimport { Preflight } from 'cdk-preflight';\n\nconst app = new App();\nPreflight.apply(app);\n```\n\nOn violation, `cdk synth` fails with one error per finding, including the construct trace:\n\n```text\nERROR idle_timeout.timeout_seconds is 5000 but must be between 1 and 4000 seconds (cdk-preflight)\n MyStack/Alb/Resource (Alb16C2F182) aws-cdk-lib.aws_elasticloadbalancingv2.CfnLoadBalancer\n\nSynthesis finished with errors\n```\n\n## What it catches\n\nFour ordinary-looking snippets. All of them pass `cdk synth` and CloudFormation\npre-deployment validation, and all of them fail minutes into a deployment:\n\n```ts\n// 1) pf-iam-inline-policy-size — enumerate buckets, grant each one, blow past 10,240 chars\n// \"Maximum policy size of 10240 bytes exceeded for role IngestRole\"\n// (via role.addToPolicy the CDK auto-splits into managed policies instead,\n// and you hit the 6,144-char limit as pf-iam-managed-policy-size)\nnew iam.Policy(this, 'IngestPolicy', {\n roles: [role],\n statements: [new iam.PolicyStatement({\n actions: ['s3:GetObject', 's3:ListBucket'],\n resources: Array.from({ length: 200 },\n (_, i) => `arn:aws:s3:::data-lake-landing-zone-${i}/year=*/month=*/*`),\n })],\n});\n\n// 2) pf-lambda-env-size — a config blob in the environment, over the 4KB total\n// \"Lambda was unable to configure your environment variables because the\n// environment variables you have provided exceeded the 4KB limit\"\nnew lambda.Function(this, 'Fn', {\n runtime: lambda.Runtime.NODEJS_22_X,\n handler: 'index.handler',\n code: lambda.Code.fromInline('exports.handler = async () => {};'),\n environment: { FEATURE_FLAGS: JSON.stringify(bigFeatureFlagMap) },\n});\n\n// 3) pf-sfn-asl-missing-state (+ pf-sfn-asl-unreachable-state) — a typo in a state name\n// \"Invalid State Machine Definition: 'MISSING_TRANSITION_TARGET: ...'\"\nnew sfn.StateMachine(this, 'Pipeline', {\n definitionBody: sfn.DefinitionBody.fromString(JSON.stringify({\n StartAt: 'Validate',\n States: {\n Validate: { Type: 'Pass', Next: 'Transform' },\n Trasform: { Type: 'Pass', End: true }, // typo: Transform\n },\n })),\n});\n\n// 4) pf-logs-filter-pattern-bracket — a filter pattern opened with '[' and never closed\n// \"If a filter pattern starts with '[' it must end with ']'\"\nnew logs.MetricFilter(this, 'ErrorFilter', {\n logGroup,\n metricNamespace: 'Pipeline',\n metricName: 'Errors',\n filterPattern: logs.FilterPattern.literal('[time, level=ERROR, msg'),\n});\n```\n\nNone of these are type errors, so the L2 constructs accept them; none of them are\nexpressible in a resource schema, so CloudFormation accepts the template. With\n`Preflight.apply(app)` in place they fail `cdk synth` instead.\n\n## Observe-only mode\n\nTo roll the rules out gradually, start with `enforce: false`: findings then surface as synth **warnings** through the CDK built-in validator, with construct traces and per-finding acknowledgement:\n\n```ts\nPreflight.apply(app, { enforce: false });\n```\n\n```text\nWARNING idle_timeout.timeout_seconds is 5000 but must be between 1 and 4000 seconds (CloudFormation Validate)\n MyStack/Alb (Alb) aws-cdk-lib.aws_elasticloadbalancingv2.CfnLoadBalancer\n Acknowledge with 'CloudFormation-Validate::pf-elbv2-lb-idle-timeout-range'\n```\n\n> **Known limitation with stages.** The AWS CDK CLI drops validation findings for stacks nested in a `Stage`\n> before printing them, so in observe-only mode those findings appear **only** in `cdk.out/validation-report.json`\n> and never on the console. Enforce mode is not affected: cdk-preflight reports such findings itself and fails\n> synthesis. This is a CLI-side bug (present since aws-cdk 2.1128.1), not a rule evaluation problem.\n\n> **If the rules cannot run, the build stops.** When the evaluation engine fails on a template (a rule pack that\n> does not compile, an engine bug), enforce mode reports it as a violation named `pf-engine-error` and fails\n> synthesis for that stack instead of passing green with no rule having run. The other stacks keep their rules.\n> `pf-engine-error` is not a bundled rule and cannot be `exclude`d; `enforce: false` unblocks the build if you\n> need one.\n\n| Option | Default | Effect |\n|---|---|---|\n| `enforce` | `true` | Violations of bundled rules fail synthesis; set to `false` to only warn |\n| `strict` | `false` | With `enforce`: also fail on error-class findings (`ERROR`/`FATAL`, e.g. `F3034`) of the built-in validation engine itself, which the CDK currently downgrades to warnings |\n| `exclude` | `[]` | Rule ids to disable |\n| `includeUpstreamPending` | `true` | Include rules already proposed to the upstream engine but not yet merged |\n\nTo opt out of a single rule everywhere, pass its id in `exclude`. To suppress a\nsingle *finding* on one construct, acknowledge it — this works in both modes, the\nid prefix just differs (`cdk-preflight::` when enforcing, `CloudFormation-Validate::`\nin observe-only, as printed in the warning text):\n\n```ts\ncdk.Validations.of(errorFilter).acknowledge({\n id: 'cdk-preflight::pf-logs-filter-pattern-bracket',\n reason: 'log group is written by a legacy producer; pattern is fixed upstream',\n});\n```\n\n## Bundled rules\n\nSee [docs/rules.md](docs/rules.md) for the generated rule table.\n\n<!-- supported-resources:start -->\n<details>\n<summary><b>323 resource types across 55 services</b> — click to expand</summary>\n\nResource names are relative to `AWS::<Service>::`; the number in parentheses is how many rules target that type.\n\n| Service | Resource types |\n|---|---|\n| **(any resource type)** | `*` (2) |\n| **ApiGateway** | `ApiKey` (1), `Authorizer` (5), `Deployment` (1), `DocumentationPart` (1), `DomainName` (4), `GatewayResponse` (1), `Method` (12), `Model` (3), `Resource` (1), `RestApi` (4), `Stage` (9), `UsagePlan` (5), `VpcLink` (1) |\n| **ApiGatewayV2** | `Api` (5), `Authorizer` (11), `DomainName` (3), `Integration` (15), `IntegrationResponse` (1), `Model` (2), `Route` (6), `RouteResponse` (2), `Stage` (4), `VpcLink` (1) |\n| **AppSync** | `Api` (7), `ApiCache` (4), `ApiKey` (2), `ChannelNamespace` (5), `DataSource` (15), `DomainName` (1), `FunctionConfiguration` (24), `GraphQLApi` (16), `GraphQLSchema` (12), `Resolver` (32), `SourceApiAssociation` (3) |\n| **Athena** | `DataCatalog` (6), `WorkGroup` (8) |\n| **AutoScaling** | `AutoScalingGroup` (38), `LifecycleHook` (8), `ScalingPolicy` (41), `ScheduledAction` (13), `WarmPool` (4) |\n| **Batch** | `ComputeEnvironment` (40), `ConsumableResource` (2), `JobDefinition` (109), `JobQueue` (18), `SchedulingPolicy` (8), `ServiceEnvironment` (6) |\n| **Bedrock** | `ApplicationInferenceProfile` (2), `AutomatedReasoningPolicy` (3), `Blueprint` (3), `DataAutomationProject` (8), `DataSource` (12), `Flow` (14), `Guardrail` (19), `IntelligentPromptRouter` (5), `KnowledgeBase` (18), `Prompt` (4) |\n| **BedrockAgentCore** | `ApiKeyCredentialProvider` (1), `BrowserCustom` (1), `CodeInterpreterCustom` (1), `ConfigurationBundle` (3), `Dataset` (3), `Evaluator` (4), `Gateway` (5), `GatewayRule` (3), `GatewayTarget` (9), `Harness` (2), `HarnessEndpoint` (2), `Memory` (6), `OAuth2CredentialProvider` (3), `OnlineEvaluationConfig` (3), `PaymentCredentialProvider` (1), `PaymentManager` (1), `Policy` (3), `ResourcePolicy` (1), `Runtime` (8), `RuntimeEndpoint` (1) |\n| **CloudFront** | `AnycastIpList` (1), `CachePolicy` (7), `ContinuousDeploymentPolicy` (5), `Distribution` (55), `Function` (4), `KeyGroup` (1), `KeyValueStore` (2), `OriginRequestPolicy` (5), `PublicKey` (1), `RealtimeLogConfig` (3), `ResponseHeadersPolicy` (8), `VpcOrigin` (3) |\n| **CloudWatch** | `Alarm` (21), `AnomalyDetector` (6), `CompositeAlarm` (6), `Dashboard` (14), `InsightRule` (7), `MetricStream` (6) |\n| **CodeBuild** | `Project` (37), `ReportGroup` (2), `SourceCredential` (4) |\n| **CodeCommit** | `Repository` (11) |\n| **CodeDeploy** | `Application` (7), `DeploymentConfig` (12), `DeploymentGroup` (23) |\n| **CodePipeline** | `CustomActionType` (3), `Pipeline` (25), `Webhook` (2) |\n| **Cognito** | `IdentityPool` (3), `IdentityPoolRoleAttachment` (7), `LogDeliveryConfiguration` (3), `ManagedLoginBranding` (2), `UserPool` (52), `UserPoolClient` (21), `UserPoolDomain` (7), `UserPoolGroup` (1), `UserPoolIdentityProvider` (11), `UserPoolResourceServer` (4), `UserPoolRiskConfigurationAttachment` (6), `UserPoolUICustomizationAttachment` (2) |\n| **DocDB** | `DBCluster` (14), `DBInstance` (1), `DBSubnetGroup` (2), `EventSubscription` (1) |\n| **DocDBElastic** | `Cluster` (7) |\n| **DynamoDB** | `GlobalTable` (26), `Table` (28) |\n| **EC2** | `ClientVpnAuthorizationRule` (1), `ClientVpnEndpoint` (6), `DHCPOptions` (2), `EIPAssociation` (1), `FlowLog` (4), `Instance` (10), `KeyPair` (1), `LaunchTemplate` (5), `NatGateway` (2), `NetworkAclEntry` (1), `NetworkInterface` (2), `PlacementGroup` (3), `PrefixList` (3), `Route` (1), `SecurityGroup` (6), `SecurityGroupEgress` (5), `SecurityGroupIngress` (5), `Subnet` (10), `TrafficMirrorTarget` (1), `TransitGateway` (2), `TransitGatewayRoute` (1), `Volume` (6), `VPC` (2), `VPCCidrBlock` (1), `VPCEndpoint` (4), `VPCGatewayAttachment` (1), `VPNConnection` (5) |\n| **ECR** | `PullThroughCacheRule` (3), `RegistryScanningConfiguration` (1), `ReplicationConfiguration` (1), `Repository` (7), `RepositoryCreationTemplate` (8), `SigningConfiguration` (1) |\n| **ECS** | `CapacityProvider` (3), `Cluster` (5), `Service` (37), `TaskDefinition` (64), `TaskSet` (2) |\n| **EFS** | `AccessPoint` (1), `FileSystem` (7), `MountTarget` (4) |\n| **ElastiCache** | `CacheCluster` (9), `ReplicationGroup` (14), `User` (2), `UserGroup` (1) |\n| **ElasticLoadBalancingV2** | `Listener` (57), `ListenerCertificate` (2), `ListenerRule` (37), `LoadBalancer` (37), `TargetGroup` (58), `TrustStore` (1), `TrustStoreRevocation` (1) |\n| **Events** | `ApiDestination` (1), `Archive` (5), `Connection` (1), `Endpoint` (2), `EventBus` (2), `Rule` (23) |\n| **EventSchemas** | `Discoverer` (1), `Registry` (1), `RegistryPolicy` (1), `Schema` (1) |\n| **Glue** | `Classifier` (6), `Connection` (5), `Crawler` (11), `CustomEntityType` (1), `Database` (1), `DataQualityRuleset` (1), `Job` (15), `MLTransform` (4), `Partition` (1), `Schema` (3), `SecurityConfiguration` (1), `Table` (1), `Trigger` (10), `UserDefinedFunction` (2), `Workflow` (1) |\n| **IAM** | `Group` (23), `GroupPolicy` (1), `InstanceProfile` (2), `ManagedPolicy` (31), `OIDCProvider` (2), `Policy` (29), `Role` (40), `RolePolicy` (1), `ServiceLinkedRole` (1), `User` (24), `UserPolicy` (1) |\n| **Kinesis** | `ResourcePolicy` (4), `Stream` (5), `StreamConsumer` (2) |\n| **KinesisAnalyticsV2** | `Application` (20), `ApplicationCloudWatchLoggingOption` (1), `ApplicationOutput` (1), `ApplicationReferenceDataSource` (1) |\n| **KinesisFirehose** | `DeliveryStream` (68) |\n| **KMS** | `Alias` (2), `Key` (12), `ReplicaKey` (4) |\n| **Lambda** | `Alias` (7), `CodeSigningConfig` (1), `EventInvokeConfig` (5), `EventSourceMapping` (54), `Function` (46), `LayerVersion` (8), `LayerVersionPermission` (3), `Permission` (8), `Url` (8), `Version` (1) |\n| **Logs** | `AccountPolicy` (6), `DeliveryDestination` (3), `Destination` (1), `LogAnomalyDetector` (2), `LogGroup` (10), `MetricFilter` (7), `QueryDefinition` (1), `ResourcePolicy` (1), `SubscriptionFilter` (6), `Transformer` (3) |\n| **MemoryDB** | `Cluster` (8), `User` (1) |\n| **MSK** | `BatchScramSecret` (2), `Cluster` (31), `ClusterPolicy` (1), `Configuration` (4), `Replicator` (10), `ServerlessCluster` (4) |\n| **Neptune** | `DBCluster` (11), `DBClusterParameterGroup` (1), `DBInstance` (3), `DBSubnetGroup` (1), `GlobalCluster` (1) |\n| **NeptuneGraph** | `Graph` (2), `PrivateGraphEndpoint` (1) |\n| **Pipes** | `Pipe` (9) |\n| **RDS** | `DBCluster` (19), `DBInstance` (33), `DBParameterGroup` (2), `DBProxy` (4), `DBProxyTargetGroup` (2), `DBShardGroup` (1), `DBSubnetGroup` (3), `EventSubscription` (3), `OptionGroup` (1) |\n| **Redshift** | `Cluster` (20), `EventSubscription` (1), `ScheduledAction` (2) |\n| **RedshiftServerless** | `Namespace` (5), `Workgroup` (6) |\n| **Route53** | `CidrCollection` (11), `DNSSEC` (3), `HealthCheck` (30), `HostedZone` (14), `KeySigningKey` (9), `RecordSet` (75), `RecordSetGroup` (76) |\n| **Route53Profiles** | `ProfileAssociation` (1), `ProfileResourceAssociation` (6) |\n| **Route53Resolver** | `FirewallDomainList` (3), `FirewallRuleGroup` (18), `FirewallRuleGroupAssociation` (4), `ResolverDNSSECConfig` (1), `ResolverEndpoint` (18), `ResolverQueryLoggingConfig` (1), `ResolverQueryLoggingConfigAssociation` (1), `ResolverRule` (15), `ResolverRuleAssociation` (1) |\n| **S3** | `AccessPoint` (1), `Bucket` (54), `BucketPolicy` (4), `StorageLens` (5), `StorageLensGroup` (3) |\n| **S3Express** | `AccessPoint` (3), `DirectoryBucket` (11) |\n| **Scheduler** | `Schedule` (10), `ScheduleGroup` (1) |\n| **SecretsManager** | `RotationSchedule` (4), `Secret` (5), `SecretTargetAttachment` (1) |\n| **SNS** | `Subscription` (9), `Topic` (12), `TopicPolicy` (1) |\n| **SQS** | `Queue` (9), `QueuePolicy` (1) |\n| **SSM** | `Association` (3), `Document` (3), `MaintenanceWindow` (2), `MaintenanceWindowTarget` (1), `MaintenanceWindowTask` (1), `Parameter` (5) |\n| **StepFunctions** | `Activity` (3), `StateMachine` (26) |\n| **WAFv2** | `IPSet` (3), `LoggingConfiguration` (3), `RegexPatternSet` (3), `RuleGroup` (18), `WebACL` (23), `WebACLAssociation` (2) |\n\n</details>\n<!-- supported-resources:end -->\n\nHighlights:\n\n- **ELBv2**: `idle_timeout` / `deregistration_delay` / `slow_start` attribute ranges (stringly-typed Key/Value attributes are invisible to schema validation)\n- **IAM**: managed (6,144 chars) and inline (role/group/user) policy document size limits\n- **CloudFront**: `MinTTL <= DefaultTTL <= MaxTTL` ordering, ACM certificates must live in `us-east-1`\n- **Step Functions**: `Next`/`Default`/`Choices` must reference defined states (a dangling `StartAt` is already caught by the engine's built-in `E3601`)\n- **EC2**: security group TCP/UDP port ranges and `FromPort <= ToPort`\n\n## For AI agents\n\nTo add cdk-preflight to a CDK app:\n\n1. `npm i -D cdk-preflight`\n2. `npx cdk-preflight init` — or the shorter alias `npx cdkpf init` (finds the entry point via `cdk.json` and inserts `Preflight.apply(app)`; use `--dry-run` to preview)\n3. Run `cdk synth`. Violations fail the synth with a validation report; each finding carries a rule id, the actual value, and a suggested fix\n4. To fix a finding, prefer correcting the resource. To opt out instead: `exclude: ['<rule-id>']` disables one rule, `enforce: false` switches to warn-only reporting\n\nThe machine-readable findings are written to `cdk.out/validation-report.json` when synthesizing with `-c @aws-cdk/core:validationReportJson=true`.\n\n### Report missed deploy errors\n\ncdk-preflight only knows the failure modes it has benched. When a deploy fails on a constraint the pack should have caught, that report is how new rules get added — but at that moment cdk-preflight is out of the loop (it passed the synth), so the instruction has to already sit in your agent's context. Paste this into your repository's `AGENTS.md` (or `CLAUDE.md`):\n\n```markdown\n## cdk-preflight: report missed deploy errors\n\nIf `cdk deploy` fails even though `cdk synth` (with cdk-preflight enabled) passed,\nand the failure is a service-side validation rejection — CREATE_FAILED/UPDATE_FAILED\nwith a 400-class message such as \"Invalid request provided: ...\" — cdk-preflight is\nmissing a rule. Report it:\n\n1. Qualify first. NOT reportable: AccessDenied / permissions, service quotas,\n throttling, name conflicts with existing resources, stabilization timeouts.\n2. Redact account-specific data (account IDs -> 123456789012, real ARNs/domains\n -> placeholders).\n3. Search existing issues: https://github.com/badmintoncryer/cdk-preflight/issues\n4. With your user's approval, open a \"Missed deploy error\" issue with the verbatim\n error message, the resource type, a minimal template snippet, and your\n aws-cdk-lib / cdk-preflight versions.\n```\n\n## Scope and rule lifecycle\n\nA constraint belongs in the pack when violating it makes a real deployment fail *and* no layer that sees the same synthesized template already blocks it. There is no further \"is this worth a rule\" question — if the gap is real, it gets a rule.\n\nCDK L2 construct validation is deliberately **not** one of those layers. `CfnXxx` usage, escape hatches, `addPropertyOverride`, `cloudformation-include` and migrated templates all bypass L2, so an L2 guard covering the same mistake neither disqualifies a rule nor retires one.\n\nThat makes growth the normal state, and it has a consequence worth knowing before you upgrade: **new rules land in minor releases, so a minor upgrade can newly fail a `cdk synth` that passed yesterday.** That is intended, not a regression. If you need a frozen rule set, pin the version; to drop a single rule, `exclude: ['<rule-id>']`; to see everything without failing the build, `enforce: false`.\n\nRules move the other way too. Once the validation engine bundled in `aws-cdk-lib` (or CloudFormation's own pre-deploy validation) starts blocking a constraint, the rule is deleted rather than kept as a duplicate — staying on an older `aws-cdk-lib` and an older cdk-preflight keeps the old behavior.\n\n## How it works\n\n`Preflight.apply()` evaluates the rules with the [cloudformation-validate](https://github.com/aws-cloudformation/cloudformation-validate) Rust/WASM engine that ships inside `aws-cdk-lib` — no extra binaries, no network access at synth time. In the default enforce mode the engine is invoked through a dedicated CDK validation plugin so that violations fail synthesis; with `enforce: false` the rules are instead injected into the CDK built-in `CloudFormationValidatePlugin` and reported as warnings.\n\nConstraints that *can* be expressed in schemas or generic engine rules also make good upstream PRs to that engine, but nothing here waits on one — the upstream release cycle is deliberately slower than this pack's. Each rule's `meta.yaml` tracks its upstream status so that retirement stays bookkeeping.\n\n## Requirements\n\n- `aws-cdk-lib` >= 2.267.0, released 2026-08-27 (the first release that bundles the built-in CloudFormation validator). This is a recent release — an existing CDK app may need an upgrade before cdk-preflight can run.\n\n## Contributing\n\nRule authoring, the verification gates (including real-deploy reproduction), and the test layout are documented in [AGENTS.md](AGENTS.md) — written for AI coding agents and humans alike.\n\n## License\n\nApache-2.0\n"
|
|
9419
|
+
"markdown": "<p align=\"center\">\n <img src=\"https://raw.githubusercontent.com/badmintoncryer/cdk-preflight/main/assets/logo.png\" alt=\"cdk-preflight\" width=\"104\" height=\"104\">\n</p>\n\n<h1 align=\"center\">cdk-preflight</h1>\n\n<p align=\"center\">\n <strong>Catch deploy-time CloudFormation failures at <code>cdk synth</code> time.</strong>\n</p>\n\n<p align=\"center\">\n <a href=\"https://github.com/badmintoncryer/cdk-preflight/actions/workflows/monthly-verify.yml\"><img src=\"https://github.com/badmintoncryer/cdk-preflight/actions/workflows/monthly-verify.yml/badge.svg\" alt=\"monthly real-deploy verification\"></a>\n <a href=\"https://www.npmjs.com/package/cdk-preflight\"><img src=\"https://img.shields.io/npm/v/cdk-preflight.svg\" alt=\"npm version\"></a>\n <a href=\"https://www.npmjs.com/package/cdk-preflight\"><img src=\"https://img.shields.io/npm/dt/cdk-preflight.svg\" alt=\"npm total downloads\"></a>\n <a href=\"docs/rules.md\"><img src=\"https://img.shields.io/badge/rules-2580-blue\" alt=\"2580 bundled rules\"></a>\n</p>\n\nSome CloudFormation constraints are not expressed in resource provider schemas — they live only in documentation, in service API validation, or across multiple properties. Templates that violate them pass `cdk synth`, pass CloudFormation pre-deployment validation, and then fail minutes into a deployment, burning a rollback cycle.\n\ncdk-preflight is a curated [Rego rule pack](docs/rules.md) for exactly those constraints, evaluated with the CloudFormation validation engine that ships inside `aws-cdk-lib` (>= 2.267.0). By default a violation **fails `cdk synth`** — a template that is known to fail at deploy time never leaves your machine.\n\nThe pack aims at **every deploy-time failure that no existing CDK mechanism already catches** — nothing narrower. Every bundled rule is backed by a `fail`/`pass` template pair, and the failure has been reproduced against real AWS. The handful of rules that could not be reproduced are marked `doc-only` and report as **warnings**, as does a rule whose remaining false positives cannot be told from the template (a cross-account Lambda layer the owner may have shared): they show up in the validation report but never fail synth. Rules that the built-in validation engine already covers are deliberately **not** duplicated — a test suite enforces this.\n\n> **Requires `aws-cdk-lib` >= 2.267.0** (released 2026-08-27) — the first release that bundles\n> the CloudFormation validation engine. On older versions the rules cannot run at all.\n\n## Quick start\n\n```bash\nnpm i -D cdk-preflight\nnpx cdkpf init # inserts Preflight.apply(app) into your CDK app\n # (`npx cdkpf init` is the same command, shorter)\n```\n\nor add one line yourself:\n\n```ts\nimport { Preflight } from 'cdk-preflight';\n\nconst app = new App();\nPreflight.apply(app);\n```\n\nOn violation, `cdk synth` fails with one error per finding, including the construct trace:\n\n```text\nERROR idle_timeout.timeout_seconds is 5000 but must be between 1 and 4000 seconds (cdk-preflight)\n MyStack/Alb/Resource (Alb16C2F182) aws-cdk-lib.aws_elasticloadbalancingv2.CfnLoadBalancer\n\nSynthesis finished with errors\n```\n\n## What it catches\n\nFour ordinary-looking snippets. All of them pass `cdk synth` and CloudFormation\npre-deployment validation, and all of them fail minutes into a deployment:\n\n```ts\n// 1) pf-iam-inline-policy-size — enumerate buckets, grant each one, blow past 10,240 chars\n// \"Maximum policy size of 10240 bytes exceeded for role IngestRole\"\n// (via role.addToPolicy the CDK auto-splits into managed policies instead,\n// and you hit the 6,144-char limit as pf-iam-managed-policy-size)\nnew iam.Policy(this, 'IngestPolicy', {\n roles: [role],\n statements: [new iam.PolicyStatement({\n actions: ['s3:GetObject', 's3:ListBucket'],\n resources: Array.from({ length: 200 },\n (_, i) => `arn:aws:s3:::data-lake-landing-zone-${i}/year=*/month=*/*`),\n })],\n});\n\n// 2) pf-lambda-env-size — a config blob in the environment, over the 4KB total\n// \"Lambda was unable to configure your environment variables because the\n// environment variables you have provided exceeded the 4KB limit\"\nnew lambda.Function(this, 'Fn', {\n runtime: lambda.Runtime.NODEJS_22_X,\n handler: 'index.handler',\n code: lambda.Code.fromInline('exports.handler = async () => {};'),\n environment: { FEATURE_FLAGS: JSON.stringify(bigFeatureFlagMap) },\n});\n\n// 3) pf-sfn-asl-missing-state (+ pf-sfn-asl-unreachable-state) — a typo in a state name\n// \"Invalid State Machine Definition: 'MISSING_TRANSITION_TARGET: ...'\"\nnew sfn.StateMachine(this, 'Pipeline', {\n definitionBody: sfn.DefinitionBody.fromString(JSON.stringify({\n StartAt: 'Validate',\n States: {\n Validate: { Type: 'Pass', Next: 'Transform' },\n Trasform: { Type: 'Pass', End: true }, // typo: Transform\n },\n })),\n});\n\n// 4) pf-logs-filter-pattern-bracket — a filter pattern opened with '[' and never closed\n// \"If a filter pattern starts with '[' it must end with ']'\"\nnew logs.MetricFilter(this, 'ErrorFilter', {\n logGroup,\n metricNamespace: 'Pipeline',\n metricName: 'Errors',\n filterPattern: logs.FilterPattern.literal('[time, level=ERROR, msg'),\n});\n```\n\nNone of these are type errors, so the L2 constructs accept them; none of them are\nexpressible in a resource schema, so CloudFormation accepts the template. With\n`Preflight.apply(app)` in place they fail `cdk synth` instead.\n\n## Observe-only mode\n\nTo roll the rules out gradually, start with `enforce: false`: findings then surface as synth **warnings** through the CDK built-in validator, with construct traces and per-finding acknowledgement:\n\n```ts\nPreflight.apply(app, { enforce: false });\n```\n\n```text\nWARNING idle_timeout.timeout_seconds is 5000 but must be between 1 and 4000 seconds (CloudFormation Validate)\n MyStack/Alb (Alb) aws-cdk-lib.aws_elasticloadbalancingv2.CfnLoadBalancer\n Acknowledge with 'CloudFormation-Validate::pf-elbv2-lb-idle-timeout-range'\n```\n\n> **Known limitation with stages.** The AWS CDK CLI drops validation findings for stacks nested in a `Stage`\n> before printing them, so in observe-only mode those findings appear **only** in `cdk.out/validation-report.json`\n> and never on the console. Enforce mode is not affected: cdk-preflight reports such findings itself and fails\n> synthesis. This is a CLI-side bug (present since aws-cdk 2.1128.1), not a rule evaluation problem.\n\n> **If the rules cannot run, the build stops.** When the evaluation engine fails on a template (a rule pack that\n> does not compile, an engine bug), enforce mode reports it as a violation named `pf-engine-error` and fails\n> synthesis for that stack instead of passing green with no rule having run. The other stacks keep their rules.\n> `pf-engine-error` is not a bundled rule and cannot be `exclude`d; `enforce: false` unblocks the build if you\n> need one.\n\n| Option | Default | Effect |\n|---|---|---|\n| `enforce` | `true` | Violations of bundled rules fail synthesis; set to `false` to only warn |\n| `strict` | `false` | With `enforce`: also fail on error-class findings (`ERROR`/`FATAL`, e.g. `F3034`) of the built-in validation engine itself, which the CDK currently downgrades to warnings |\n| `exclude` | `[]` | Rule ids to disable |\n| `includeUpstreamPending` | `true` | Include rules already proposed to the upstream engine but not yet merged |\n\nTo opt out of a single rule everywhere, pass its id in `exclude`. To suppress a\nsingle *finding* on one construct, acknowledge it — this works in both modes, the\nid prefix just differs (`cdk-preflight::` when enforcing, `CloudFormation-Validate::`\nin observe-only, as printed in the warning text):\n\n```ts\ncdk.Validations.of(errorFilter).acknowledge({\n id: 'cdk-preflight::pf-logs-filter-pattern-bracket',\n reason: 'log group is written by a legacy producer; pattern is fixed upstream',\n});\n```\n\n## Bundled rules\n\nSee [docs/rules.md](docs/rules.md) for the generated rule table.\n\n<!-- supported-resources:start -->\n<details>\n<summary><b>329 resource types across 57 services</b> — click to expand</summary>\n\nResource names are relative to `AWS::<Service>::`; the number in parentheses is how many rules target that type.\n\n| Service | Resource types |\n|---|---|\n| **(any resource type)** | `*` (2) |\n| **ApiGateway** | `ApiKey` (1), `Authorizer` (5), `Deployment` (1), `DocumentationPart` (1), `DomainName` (4), `GatewayResponse` (1), `Method` (12), `Model` (3), `Resource` (1), `RestApi` (4), `Stage` (9), `UsagePlan` (5), `VpcLink` (1) |\n| **ApiGatewayV2** | `Api` (5), `Authorizer` (11), `DomainName` (3), `Integration` (15), `IntegrationResponse` (1), `Model` (2), `Route` (6), `RouteResponse` (2), `Stage` (4), `VpcLink` (1) |\n| **ApplicationAutoScaling** | `ScalableTarget` (19), `ScalingPolicy` (30) |\n| **AppSync** | `Api` (7), `ApiCache` (4), `ApiKey` (2), `ChannelNamespace` (5), `DataSource` (15), `DomainName` (1), `FunctionConfiguration` (24), `GraphQLApi` (16), `GraphQLSchema` (12), `Resolver` (32), `SourceApiAssociation` (3) |\n| **Athena** | `DataCatalog` (6), `WorkGroup` (8) |\n| **AutoScaling** | `AutoScalingGroup` (38), `LifecycleHook` (8), `ScalingPolicy` (41), `ScheduledAction` (13), `WarmPool` (4) |\n| **Batch** | `ComputeEnvironment` (40), `ConsumableResource` (2), `JobDefinition` (109), `JobQueue` (18), `SchedulingPolicy` (8), `ServiceEnvironment` (6) |\n| **Bedrock** | `ApplicationInferenceProfile` (2), `AutomatedReasoningPolicy` (3), `Blueprint` (3), `DataAutomationProject` (8), `DataSource` (12), `Flow` (14), `Guardrail` (19), `IntelligentPromptRouter` (5), `KnowledgeBase` (18), `Prompt` (4) |\n| **BedrockAgentCore** | `ApiKeyCredentialProvider` (1), `BrowserCustom` (1), `CodeInterpreterCustom` (1), `ConfigurationBundle` (3), `Dataset` (3), `Evaluator` (4), `Gateway` (5), `GatewayRule` (3), `GatewayTarget` (9), `Harness` (2), `HarnessEndpoint` (2), `Memory` (6), `OAuth2CredentialProvider` (3), `OnlineEvaluationConfig` (3), `PaymentCredentialProvider` (1), `PaymentManager` (1), `Policy` (3), `ResourcePolicy` (1), `Runtime` (8), `RuntimeEndpoint` (1) |\n| **CloudFront** | `AnycastIpList` (1), `CachePolicy` (7), `ContinuousDeploymentPolicy` (5), `Distribution` (55), `Function` (4), `KeyGroup` (1), `KeyValueStore` (2), `OriginRequestPolicy` (5), `PublicKey` (1), `RealtimeLogConfig` (3), `ResponseHeadersPolicy` (8), `VpcOrigin` (3) |\n| **CloudWatch** | `Alarm` (21), `AnomalyDetector` (6), `CompositeAlarm` (6), `Dashboard` (14), `InsightRule` (7), `MetricStream` (6) |\n| **CodeBuild** | `Project` (37), `ReportGroup` (2), `SourceCredential` (4) |\n| **CodeCommit** | `Repository` (11) |\n| **CodeDeploy** | `Application` (7), `DeploymentConfig` (12), `DeploymentGroup` (23) |\n| **CodePipeline** | `CustomActionType` (3), `Pipeline` (25), `Webhook` (2) |\n| **Cognito** | `IdentityPool` (3), `IdentityPoolRoleAttachment` (7), `LogDeliveryConfiguration` (3), `ManagedLoginBranding` (2), `UserPool` (52), `UserPoolClient` (21), `UserPoolDomain` (7), `UserPoolGroup` (1), `UserPoolIdentityProvider` (11), `UserPoolResourceServer` (4), `UserPoolRiskConfigurationAttachment` (6), `UserPoolUICustomizationAttachment` (2) |\n| **DocDB** | `DBCluster` (14), `DBInstance` (1), `DBSubnetGroup` (2), `EventSubscription` (1) |\n| **DocDBElastic** | `Cluster` (7) |\n| **DynamoDB** | `GlobalTable` (26), `Table` (28) |\n| **EC2** | `ClientVpnAuthorizationRule` (1), `ClientVpnEndpoint` (6), `DHCPOptions` (2), `EIPAssociation` (1), `FlowLog` (4), `Instance` (10), `KeyPair` (1), `LaunchTemplate` (5), `NatGateway` (2), `NetworkAclEntry` (1), `NetworkInterface` (2), `PlacementGroup` (3), `PrefixList` (3), `Route` (1), `SecurityGroup` (6), `SecurityGroupEgress` (5), `SecurityGroupIngress` (5), `Subnet` (10), `TrafficMirrorTarget` (1), `TransitGateway` (2), `TransitGatewayRoute` (1), `Volume` (6), `VPC` (2), `VPCCidrBlock` (1), `VPCEndpoint` (4), `VPCGatewayAttachment` (1), `VPNConnection` (5) |\n| **ECR** | `PullThroughCacheRule` (3), `RegistryScanningConfiguration` (1), `ReplicationConfiguration` (1), `Repository` (7), `RepositoryCreationTemplate` (8), `SigningConfiguration` (1) |\n| **ECS** | `CapacityProvider` (3), `Cluster` (5), `Service` (37), `TaskDefinition` (64), `TaskSet` (2) |\n| **EFS** | `AccessPoint` (1), `FileSystem` (7), `MountTarget` (4) |\n| **ElastiCache** | `CacheCluster` (9), `ReplicationGroup` (14), `User` (2), `UserGroup` (1) |\n| **ElasticLoadBalancingV2** | `Listener` (57), `ListenerCertificate` (2), `ListenerRule` (37), `LoadBalancer` (37), `TargetGroup` (58), `TrustStore` (1), `TrustStoreRevocation` (1) |\n| **Events** | `ApiDestination` (1), `Archive` (5), `Connection` (1), `Endpoint` (2), `EventBus` (2), `Rule` (23) |\n| **EventSchemas** | `Discoverer` (1), `Registry` (1), `RegistryPolicy` (1), `Schema` (1) |\n| **Glue** | `Classifier` (6), `Connection` (5), `Crawler` (11), `CustomEntityType` (1), `Database` (1), `DataQualityRuleset` (1), `Job` (15), `MLTransform` (4), `Partition` (1), `Schema` (3), `SecurityConfiguration` (1), `Table` (1), `Trigger` (10), `UserDefinedFunction` (2), `Workflow` (1) |\n| **IAM** | `Group` (23), `GroupPolicy` (1), `InstanceProfile` (2), `ManagedPolicy` (31), `OIDCProvider` (2), `Policy` (29), `Role` (40), `RolePolicy` (1), `ServiceLinkedRole` (1), `User` (24), `UserPolicy` (1) |\n| **Kinesis** | `ResourcePolicy` (4), `Stream` (5), `StreamConsumer` (2) |\n| **KinesisAnalyticsV2** | `Application` (20), `ApplicationCloudWatchLoggingOption` (1), `ApplicationOutput` (1), `ApplicationReferenceDataSource` (1) |\n| **KinesisFirehose** | `DeliveryStream` (68) |\n| **KMS** | `Alias` (2), `Key` (12), `ReplicaKey` (4) |\n| **Lambda** | `Alias` (7), `CodeSigningConfig` (1), `EventInvokeConfig` (5), `EventSourceMapping` (54), `Function` (46), `LayerVersion` (8), `LayerVersionPermission` (3), `Permission` (8), `Url` (8), `Version` (1) |\n| **Logs** | `AccountPolicy` (6), `DeliveryDestination` (3), `Destination` (1), `LogAnomalyDetector` (2), `LogGroup` (10), `MetricFilter` (7), `QueryDefinition` (1), `ResourcePolicy` (1), `SubscriptionFilter` (6), `Transformer` (3) |\n| **MemoryDB** | `Cluster` (8), `User` (1) |\n| **MSK** | `BatchScramSecret` (2), `Cluster` (31), `ClusterPolicy` (1), `Configuration` (4), `Replicator` (10), `ServerlessCluster` (4) |\n| **Neptune** | `DBCluster` (11), `DBClusterParameterGroup` (1), `DBInstance` (3), `DBSubnetGroup` (1), `GlobalCluster` (1) |\n| **NeptuneGraph** | `Graph` (2), `PrivateGraphEndpoint` (1) |\n| **Pipes** | `Pipe` (9) |\n| **RDS** | `DBCluster` (19), `DBInstance` (33), `DBParameterGroup` (2), `DBProxy` (4), `DBProxyTargetGroup` (2), `DBShardGroup` (1), `DBSubnetGroup` (3), `EventSubscription` (3), `OptionGroup` (1) |\n| **Redshift** | `Cluster` (20), `EventSubscription` (1), `ScheduledAction` (2) |\n| **RedshiftServerless** | `Namespace` (5), `Workgroup` (6) |\n| **Route53** | `CidrCollection` (11), `DNSSEC` (3), `HealthCheck` (30), `HostedZone` (14), `KeySigningKey` (9), `RecordSet` (75), `RecordSetGroup` (76) |\n| **Route53Profiles** | `ProfileAssociation` (1), `ProfileResourceAssociation` (6) |\n| **Route53Resolver** | `FirewallDomainList` (3), `FirewallRuleGroup` (18), `FirewallRuleGroupAssociation` (4), `ResolverDNSSECConfig` (1), `ResolverEndpoint` (18), `ResolverQueryLoggingConfig` (1), `ResolverQueryLoggingConfigAssociation` (1), `ResolverRule` (15), `ResolverRuleAssociation` (1) |\n| **S3** | `AccessPoint` (1), `Bucket` (54), `BucketPolicy` (4), `StorageLens` (5), `StorageLensGroup` (3) |\n| **S3Express** | `AccessPoint` (3), `DirectoryBucket` (11) |\n| **Scheduler** | `Schedule` (10), `ScheduleGroup` (1) |\n| **SecretsManager** | `RotationSchedule` (4), `Secret` (5), `SecretTargetAttachment` (1) |\n| **ServiceDiscovery** | `HttpNamespace` (3), `PrivateDnsNamespace` (4), `PublicDnsNamespace` (4), `Service` (12) |\n| **SNS** | `Subscription` (9), `Topic` (12), `TopicPolicy` (1) |\n| **SQS** | `Queue` (9), `QueuePolicy` (1) |\n| **SSM** | `Association` (3), `Document` (3), `MaintenanceWindow` (2), `MaintenanceWindowTarget` (1), `MaintenanceWindowTask` (1), `Parameter` (5) |\n| **StepFunctions** | `Activity` (3), `StateMachine` (26) |\n| **WAFv2** | `IPSet` (3), `LoggingConfiguration` (3), `RegexPatternSet` (3), `RuleGroup` (18), `WebACL` (23), `WebACLAssociation` (2) |\n\n</details>\n<!-- supported-resources:end -->\n\nHighlights:\n\n- **ELBv2**: `idle_timeout` / `deregistration_delay` / `slow_start` attribute ranges (stringly-typed Key/Value attributes are invisible to schema validation)\n- **IAM**: managed (6,144 chars) and inline (role/group/user) policy document size limits\n- **CloudFront**: `MinTTL <= DefaultTTL <= MaxTTL` ordering, ACM certificates must live in `us-east-1`\n- **Step Functions**: `Next`/`Default`/`Choices` must reference defined states (a dangling `StartAt` is already caught by the engine's built-in `E3601`)\n- **EC2**: security group TCP/UDP port ranges and `FromPort <= ToPort`\n\n## For AI agents\n\nTo add cdk-preflight to a CDK app:\n\n1. `npm i -D cdk-preflight`\n2. `npx cdk-preflight init` — or the shorter alias `npx cdkpf init` (finds the entry point via `cdk.json` and inserts `Preflight.apply(app)`; use `--dry-run` to preview)\n3. Run `cdk synth`. Violations fail the synth with a validation report; each finding carries a rule id, the actual value, and a suggested fix\n4. To fix a finding, prefer correcting the resource. To opt out instead: `exclude: ['<rule-id>']` disables one rule, `enforce: false` switches to warn-only reporting\n\nThe machine-readable findings are written to `cdk.out/validation-report.json` when synthesizing with `-c @aws-cdk/core:validationReportJson=true`.\n\n### Report missed deploy errors\n\ncdk-preflight only knows the failure modes it has benched. When a deploy fails on a constraint the pack should have caught, that report is how new rules get added — but at that moment cdk-preflight is out of the loop (it passed the synth), so the instruction has to already sit in your agent's context. Paste this into your repository's `AGENTS.md` (or `CLAUDE.md`):\n\n```markdown\n## cdk-preflight: report missed deploy errors\n\nIf `cdk deploy` fails even though `cdk synth` (with cdk-preflight enabled) passed,\nand the failure is a service-side validation rejection — CREATE_FAILED/UPDATE_FAILED\nwith a 400-class message such as \"Invalid request provided: ...\" — cdk-preflight is\nmissing a rule. Report it:\n\n1. Qualify first. NOT reportable: AccessDenied / permissions, service quotas,\n throttling, name conflicts with existing resources, stabilization timeouts.\n2. Redact account-specific data (account IDs -> 123456789012, real ARNs/domains\n -> placeholders).\n3. Search existing issues: https://github.com/badmintoncryer/cdk-preflight/issues\n4. With your user's approval, open a \"Missed deploy error\" issue with the verbatim\n error message, the resource type, a minimal template snippet, and your\n aws-cdk-lib / cdk-preflight versions.\n```\n\n## Scope and rule lifecycle\n\nA constraint belongs in the pack when violating it makes a real deployment fail *and* no layer that sees the same synthesized template already blocks it. There is no further \"is this worth a rule\" question — if the gap is real, it gets a rule.\n\nCDK L2 construct validation is deliberately **not** one of those layers. `CfnXxx` usage, escape hatches, `addPropertyOverride`, `cloudformation-include` and migrated templates all bypass L2, so an L2 guard covering the same mistake neither disqualifies a rule nor retires one.\n\nThat makes growth the normal state, and it has a consequence worth knowing before you upgrade: **new rules land in minor releases, so a minor upgrade can newly fail a `cdk synth` that passed yesterday.** That is intended, not a regression. If you need a frozen rule set, pin the version; to drop a single rule, `exclude: ['<rule-id>']`; to see everything without failing the build, `enforce: false`.\n\nRules move the other way too. Once the validation engine bundled in `aws-cdk-lib` (or CloudFormation's own pre-deploy validation) starts blocking a constraint, the rule is deleted rather than kept as a duplicate — staying on an older `aws-cdk-lib` and an older cdk-preflight keeps the old behavior.\n\n## How it works\n\n`Preflight.apply()` evaluates the rules with the [cloudformation-validate](https://github.com/aws-cloudformation/cloudformation-validate) Rust/WASM engine that ships inside `aws-cdk-lib` — no extra binaries, no network access at synth time. In the default enforce mode the engine is invoked through a dedicated CDK validation plugin so that violations fail synthesis; with `enforce: false` the rules are instead injected into the CDK built-in `CloudFormationValidatePlugin` and reported as warnings.\n\nConstraints that *can* be expressed in schemas or generic engine rules also make good upstream PRs to that engine, but nothing here waits on one — the upstream release cycle is deliberately slower than this pack's. Each rule's `meta.yaml` tracks its upstream status so that retirement stays bookkeeping.\n\n## Requirements\n\n- `aws-cdk-lib` >= 2.267.0, released 2026-08-27 (the first release that bundles the built-in CloudFormation validator). This is a recent release — an existing CDK app may need an upgrade before cdk-preflight can run.\n\n## Contributing\n\nRule authoring, the verification gates (including real-deploy reproduction), and the test layout are documented in [AGENTS.md](AGENTS.md) — written for AI coding agents and humans alike.\n\n## License\n\nApache-2.0\n"
|
|
9420
9420
|
},
|
|
9421
9421
|
"repository": {
|
|
9422
9422
|
"type": "git",
|
|
@@ -9600,6 +9600,6 @@
|
|
|
9600
9600
|
"symbolId": "src/index:PreflightOptions"
|
|
9601
9601
|
}
|
|
9602
9602
|
},
|
|
9603
|
-
"version": "0.0.
|
|
9604
|
-
"fingerprint": "
|
|
9603
|
+
"version": "0.0.146",
|
|
9604
|
+
"fingerprint": "OgSnnt25AuMXJLeOXQRpLls8NDTGfMjqcBOKPMyTCwc="
|
|
9605
9605
|
}
|
package/AGENTS.md
CHANGED
|
@@ -215,6 +215,7 @@ If you are a subagent running one of these phases, do not spawn further agents.
|
|
|
215
215
|
- **A comprehension inside a rule head does not schedule** (`sprintf("%s", [concat(", ", [k | some k in keys])])` → "statements not scheduled" at evaluation, measured 2026-09-05). Bind it to a variable in the body and use the variable in the head.
|
|
216
216
|
- **`some` cannot re-declare a variable that is already bound in the same body or an enclosing one** ("var `name` used before definition below"). Iterating the same tuple set twice needs fresh names plus equality checks (`some [nm, ii, m, l2, c2] in set; nm == name; ii == i`), and a comprehension inside a body must not reuse the body's variable names.
|
|
217
217
|
- **`sprintf` with the wrong arity silently disables the rule**, like a bare `%`: `sprintf("%d %s", [n], extra)` never evaluates and nothing warns (measured 2026-09-05). Keep every argument inside the array.
|
|
218
|
+
- **`%q` is not a supported `sprintf` verb** (measured 2026-09-24): the policy compiles, but the body never evaluates and no diagnostic fires — the same silent death as a bare `%`. Use `'%s'` (quote it yourself) or `%v`.
|
|
218
219
|
- **`meta.fixtureRegion` moves a rule's fixture evaluation off the harness default (us-east-1)**, in both harnesses (`test/rules.test.ts` and `scripts/rule-check.ts`; it wins over `PF_REGION`). Needed for rules about the deploy region itself (`pf-wafv2-scope-region`: CLOUDFRONT scope only in us-east-1) whose fail template cannot fire where the harness runs.
|
|
219
220
|
- **WAFv2 names are unique per scope and region, so parallel bench runs collide on fixture names.** The WAFv2 generators suffix every `Name` with the rule id (`uniq()` in the scratch `gen-lib.js`); do the same for any service whose entity names are account-unique.
|
|
220
221
|
- **The CLI's service model can lag the API** (measured 2026-09-05: `aws wafv2` had no `Monetize` action and no `PreParseTextTransformations`). Fields the CLI rejects with ParamValidation need a stack for triage; everything else is cheaper through `create-*` calls whose rejections create nothing (WAF: ~290 calls, 13 stacks for the whole survey). `aws wafv2 check-capacity` is the oracle for the WCU estimate in `pf-wafv2-capacity`.
|
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
<a href="https://github.com/badmintoncryer/cdk-preflight/actions/workflows/monthly-verify.yml"><img src="https://github.com/badmintoncryer/cdk-preflight/actions/workflows/monthly-verify.yml/badge.svg" alt="monthly real-deploy verification"></a>
|
|
13
13
|
<a href="https://www.npmjs.com/package/cdk-preflight"><img src="https://img.shields.io/npm/v/cdk-preflight.svg" alt="npm version"></a>
|
|
14
14
|
<a href="https://www.npmjs.com/package/cdk-preflight"><img src="https://img.shields.io/npm/dt/cdk-preflight.svg" alt="npm total downloads"></a>
|
|
15
|
-
<a href="docs/rules.md"><img src="https://img.shields.io/badge/rules-
|
|
15
|
+
<a href="docs/rules.md"><img src="https://img.shields.io/badge/rules-2580-blue" alt="2580 bundled rules"></a>
|
|
16
16
|
</p>
|
|
17
17
|
|
|
18
18
|
Some CloudFormation constraints are not expressed in resource provider schemas — they live only in documentation, in service API validation, or across multiple properties. Templates that violate them pass `cdk synth`, pass CloudFormation pre-deployment validation, and then fail minutes into a deployment, burning a rollback cycle.
|
|
@@ -155,7 +155,7 @@ See [docs/rules.md](docs/rules.md) for the generated rule table.
|
|
|
155
155
|
|
|
156
156
|
<!-- supported-resources:start -->
|
|
157
157
|
<details>
|
|
158
|
-
<summary><b>
|
|
158
|
+
<summary><b>329 resource types across 57 services</b> — click to expand</summary>
|
|
159
159
|
|
|
160
160
|
Resource names are relative to `AWS::<Service>::`; the number in parentheses is how many rules target that type.
|
|
161
161
|
|
|
@@ -164,6 +164,7 @@ Resource names are relative to `AWS::<Service>::`; the number in parentheses is
|
|
|
164
164
|
| **(any resource type)** | `*` (2) |
|
|
165
165
|
| **ApiGateway** | `ApiKey` (1), `Authorizer` (5), `Deployment` (1), `DocumentationPart` (1), `DomainName` (4), `GatewayResponse` (1), `Method` (12), `Model` (3), `Resource` (1), `RestApi` (4), `Stage` (9), `UsagePlan` (5), `VpcLink` (1) |
|
|
166
166
|
| **ApiGatewayV2** | `Api` (5), `Authorizer` (11), `DomainName` (3), `Integration` (15), `IntegrationResponse` (1), `Model` (2), `Route` (6), `RouteResponse` (2), `Stage` (4), `VpcLink` (1) |
|
|
167
|
+
| **ApplicationAutoScaling** | `ScalableTarget` (19), `ScalingPolicy` (30) |
|
|
167
168
|
| **AppSync** | `Api` (7), `ApiCache` (4), `ApiKey` (2), `ChannelNamespace` (5), `DataSource` (15), `DomainName` (1), `FunctionConfiguration` (24), `GraphQLApi` (16), `GraphQLSchema` (12), `Resolver` (32), `SourceApiAssociation` (3) |
|
|
168
169
|
| **Athena** | `DataCatalog` (6), `WorkGroup` (8) |
|
|
169
170
|
| **AutoScaling** | `AutoScalingGroup` (38), `LifecycleHook` (8), `ScalingPolicy` (41), `ScheduledAction` (13), `WarmPool` (4) |
|
|
@@ -211,6 +212,7 @@ Resource names are relative to `AWS::<Service>::`; the number in parentheses is
|
|
|
211
212
|
| **S3Express** | `AccessPoint` (3), `DirectoryBucket` (11) |
|
|
212
213
|
| **Scheduler** | `Schedule` (10), `ScheduleGroup` (1) |
|
|
213
214
|
| **SecretsManager** | `RotationSchedule` (4), `Secret` (5), `SecretTargetAttachment` (1) |
|
|
215
|
+
| **ServiceDiscovery** | `HttpNamespace` (3), `PrivateDnsNamespace` (4), `PublicDnsNamespace` (4), `Service` (12) |
|
|
214
216
|
| **SNS** | `Subscription` (9), `Topic` (12), `TopicPolicy` (1) |
|
|
215
217
|
| **SQS** | `Queue` (9), `QueuePolicy` (1) |
|
|
216
218
|
| **SSM** | `Association` (3), `Document` (3), `MaintenanceWindow` (2), `MaintenanceWindowTarget` (1), `MaintenanceWindowTask` (1), `Parameter` (5) |
|
package/docs/rules.md
CHANGED
|
@@ -102,6 +102,53 @@
|
|
|
102
102
|
| `pf-apigwv2-websocket-no-cors` | AWS::ApiGatewayV2::Api | WebSocket APIs take no CORS configuration | ERROR | none |
|
|
103
103
|
| `pf-apigwv2-websocket-payload-version` | AWS::ApiGatewayV2::Integration | WebSocket AWS_PROXY integrations reject payload format 2.0 | ERROR | none |
|
|
104
104
|
| `pf-apigwv2-websocket-route-selection` | AWS::ApiGatewayV2::Api | WebSocket APIs need RouteSelectionExpression | ERROR | none |
|
|
105
|
+
| `pf-appautoscaling-alb-metric-requires-resource-label` | AWS::ApplicationAutoScaling::ScalingPolicy | ALBRequestCountPerTarget needs a ResourceLabel | ERROR | none |
|
|
106
|
+
| `pf-appautoscaling-customized-metric-exclusive` | AWS::ApplicationAutoScaling::ScalingPolicy | A customized metric uses metric math or a single metric, never both | ERROR | none |
|
|
107
|
+
| `pf-appautoscaling-customized-metric-unsupported-dimension` | AWS::ApplicationAutoScaling::ScalingPolicy | DynamoDB table dimensions do not accept a customized metric | ERROR | none |
|
|
108
|
+
| `pf-appautoscaling-dynamodb-target-value-range` | AWS::ApplicationAutoScaling::ScalingPolicy | A DynamoDB capacity utilization target must be between 10 and 90 | ERROR | none |
|
|
109
|
+
| `pf-appautoscaling-elasticache-replicas-max-capacity-5` | AWS::ApplicationAutoScaling::ScalableTarget | An ElastiCache replication-group:Replicas target caps MaxCapacity at 5 | ERROR | none |
|
|
110
|
+
| `pf-appautoscaling-lambda-resource-id-qualifier` | AWS::ApplicationAutoScaling::ScalableTarget | Lambda provisioned concurrency cannot be scaled on $LATEST | ERROR | none |
|
|
111
|
+
| `pf-appautoscaling-min-adjustment-magnitude-percent-only` | AWS::ApplicationAutoScaling::ScalingPolicy | MinAdjustmentMagnitude only goes with PercentChangeInCapacity | ERROR | none |
|
|
112
|
+
| `pf-appautoscaling-min-capacity-zero-namespace` | AWS::ApplicationAutoScaling::ScalableTarget | MinCapacity 0 is rejected for DynamoDB, Keyspaces, MSK, ElastiCache, Neptune and Comprehend | ERROR | none |
|
|
113
|
+
| `pf-appautoscaling-min-max-capacity` | AWS::ApplicationAutoScaling::ScalableTarget | ScalableTarget MinCapacity must not exceed MaxCapacity | ERROR | none |
|
|
114
|
+
| `pf-appautoscaling-namespace-dimension-match` | AWS::ApplicationAutoScaling::ScalableTarget | ScalableDimension's first segment must be the ServiceNamespace | ERROR | none |
|
|
115
|
+
| `pf-appautoscaling-policy-type-config-mismatch` | AWS::ApplicationAutoScaling::ScalingPolicy | A scaling policy may carry only the configuration block its PolicyType names | ERROR | none |
|
|
116
|
+
| `pf-appautoscaling-policy-type-config-required` | AWS::ApplicationAutoScaling::ScalingPolicy | A scaling policy must carry the configuration block its PolicyType names | ERROR | none |
|
|
117
|
+
| `pf-appautoscaling-predefined-metric-dimension` | AWS::ApplicationAutoScaling::ScalingPolicy | PredefinedMetricType must be one the ScalableDimension supports | ERROR | none |
|
|
118
|
+
| `pf-appautoscaling-predictive-buffer-forbidden` | AWS::ApplicationAutoScaling::ScalingPolicy | HonorMaxCapacity rejects a MaxCapacityBuffer | ERROR | none |
|
|
119
|
+
| `pf-appautoscaling-predictive-buffer-required` | AWS::ApplicationAutoScaling::ScalingPolicy | IncreaseMaxCapacity needs a MaxCapacityBuffer | ERROR | none |
|
|
120
|
+
| `pf-appautoscaling-predictive-metric-pair-exclusive` | AWS::ApplicationAutoScaling::ScalingPolicy | A predictive metric specification is either one pair or one scaling plus one load metric | ERROR | none |
|
|
121
|
+
| `pf-appautoscaling-predictive-metric-pair-type-dimension` | AWS::ApplicationAutoScaling::ScalingPolicy | An ECS predictive metric pair takes CPU, memory or ALB request count | ERROR | none |
|
|
122
|
+
| `pf-appautoscaling-predictive-metric-spec-single` | AWS::ApplicationAutoScaling::ScalingPolicy | A predictive scaling policy takes exactly one metric specification | ERROR | none |
|
|
123
|
+
| `pf-appautoscaling-predictive-scaling-ecs-only` | AWS::ApplicationAutoScaling::ScalingPolicy<br>AWS::ApplicationAutoScaling::ScalableTarget | PredictiveScaling is only available for Amazon ECS | ERROR | none |
|
|
124
|
+
| `pf-appautoscaling-resource-id-shape` | AWS::ApplicationAutoScaling::ScalableTarget | ResourceId must carry the resource type its ScalableDimension names | ERROR | none |
|
|
125
|
+
| `pf-appautoscaling-resource-label-format` | AWS::ApplicationAutoScaling::ScalingPolicy | ResourceLabel must be app/<lb>/<lb-id>/targetgroup/<tg>/<tg-id> | ERROR | none |
|
|
126
|
+
| `pf-appautoscaling-resource-label-requires-alb-metric` | AWS::ApplicationAutoScaling::ScalingPolicy | ResourceLabel is only accepted with ALBRequestCountPerTarget | ERROR | none |
|
|
127
|
+
| `pf-appautoscaling-rolearn-required-no-slr` | AWS::ApplicationAutoScaling::ScalableTarget | EMR scalable targets require an explicit RoleARN | ERROR | none |
|
|
128
|
+
| `pf-appautoscaling-scalable-target-action-empty` | AWS::ApplicationAutoScaling::ScalableTarget | ScalableTargetAction needs MinCapacity, MaxCapacity or both | ERROR | none |
|
|
129
|
+
| `pf-appautoscaling-scalable-target-action-min-max` | AWS::ApplicationAutoScaling::ScalableTarget | ScalableTargetAction MinCapacity must not exceed MaxCapacity | ERROR | none |
|
|
130
|
+
| `pf-appautoscaling-scalable-target-action-required` | AWS::ApplicationAutoScaling::ScalableTarget | Every ScheduledAction needs a ScalableTargetAction | ERROR | none |
|
|
131
|
+
| `pf-appautoscaling-schedule-at-format` | AWS::ApplicationAutoScaling::ScalableTarget | at() takes yyyy-mm-ddThh:mm:ss with no timezone suffix | ERROR | none |
|
|
132
|
+
| `pf-appautoscaling-schedule-cron-day-fields` | AWS::ApplicationAutoScaling::ScalableTarget | cron() needs '?' in exactly one of day-of-month and day-of-week | ERROR | none |
|
|
133
|
+
| `pf-appautoscaling-schedule-expression-form` | AWS::ApplicationAutoScaling::ScalableTarget | ScheduledAction Schedule must be at(), rate() or cron() | ERROR | none |
|
|
134
|
+
| `pf-appautoscaling-schedule-rate-unit` | AWS::ApplicationAutoScaling::ScalableTarget | rate() takes a positive integer and minute(s), hour(s) or day(s) | ERROR | none |
|
|
135
|
+
| `pf-appautoscaling-scheduled-action-name-chars` | AWS::ApplicationAutoScaling::ScalableTarget | ScheduledActionName may not contain ':', '/', '|', control characters or edge spaces | ERROR | none |
|
|
136
|
+
| `pf-appautoscaling-scheduled-action-start-end-order` | AWS::ApplicationAutoScaling::ScalableTarget | ScheduledAction StartTime must be before EndTime | ERROR | none |
|
|
137
|
+
| `pf-appautoscaling-scheduled-action-timezone-iana` | AWS::ApplicationAutoScaling::ScalableTarget | ScheduledAction Timezone must be an IANA time zone name | ERROR | none |
|
|
138
|
+
| `pf-appautoscaling-step-adjustment-both-null` | AWS::ApplicationAutoScaling::ScalingPolicy | A step adjustment must carry at least one bound | ERROR | none |
|
|
139
|
+
| `pf-appautoscaling-step-adjustment-bound-order` | AWS::ApplicationAutoScaling::ScalingPolicy | MetricIntervalUpperBound must be strictly above MetricIntervalLowerBound | ERROR | none |
|
|
140
|
+
| `pf-appautoscaling-step-adjustment-exact-capacity-negative` | AWS::ApplicationAutoScaling::ScalingPolicy | ExactCapacity steps cannot ask for a negative capacity | ERROR | none |
|
|
141
|
+
| `pf-appautoscaling-step-adjustment-gap` | AWS::ApplicationAutoScaling::ScalingPolicy | Step adjustment intervals may not leave a gap between them | ERROR | none |
|
|
142
|
+
| `pf-appautoscaling-step-adjustment-missing-null-lower` | AWS::ApplicationAutoScaling::ScalingPolicy | A negative MetricIntervalLowerBound needs an adjustment open at the bottom | ERROR | none |
|
|
143
|
+
| `pf-appautoscaling-step-adjustment-missing-null-upper` | AWS::ApplicationAutoScaling::ScalingPolicy | A positive MetricIntervalUpperBound needs an adjustment open at the top | ERROR | none |
|
|
144
|
+
| `pf-appautoscaling-step-adjustment-overlap` | AWS::ApplicationAutoScaling::ScalingPolicy | Step adjustment intervals may not overlap | ERROR | none |
|
|
145
|
+
| `pf-appautoscaling-step-adjustment-two-null-lower` | AWS::ApplicationAutoScaling::ScalingPolicy | Only one step adjustment may leave MetricIntervalLowerBound out | ERROR | none |
|
|
146
|
+
| `pf-appautoscaling-step-adjustment-two-null-upper` | AWS::ApplicationAutoScaling::ScalingPolicy | Only one step adjustment may leave MetricIntervalUpperBound out | ERROR | none |
|
|
147
|
+
| `pf-appautoscaling-step-adjustment-type-required` | AWS::ApplicationAutoScaling::ScalingPolicy | A step scaling policy needs an AdjustmentType | ERROR | none |
|
|
148
|
+
| `pf-appautoscaling-step-adjustments-required` | AWS::ApplicationAutoScaling::ScalingPolicy | A step scaling policy needs at least one step adjustment | ERROR | none |
|
|
149
|
+
| `pf-appautoscaling-step-scaling-unsupported-namespace` | AWS::ApplicationAutoScaling::ScalingPolicy<br>AWS::ApplicationAutoScaling::ScalableTarget | StepScaling is not available for DynamoDB, Comprehend, Lambda, Keyspaces, MSK, ElastiCache or Neptune | ERROR | none |
|
|
150
|
+
| `pf-appautoscaling-tt-metric-spec-exclusive` | AWS::ApplicationAutoScaling::ScalingPolicy | A target tracking policy takes one metric specification, not both | ERROR | none |
|
|
151
|
+
| `pf-appautoscaling-tt-metric-spec-missing` | AWS::ApplicationAutoScaling::ScalingPolicy | A target tracking policy needs a metric specification | ERROR | none |
|
|
105
152
|
| `pf-appsync-api-additional-auth-duplicate-primary` | AWS::AppSync::GraphQLApi | An additional authentication provider may not repeat another mode | ERROR | none |
|
|
106
153
|
| `pf-appsync-api-cognito-requires-userpool-config` | AWS::AppSync::GraphQLApi | AMAZON_COGNITO_USER_POOLS authentication needs UserPoolConfig | ERROR | none |
|
|
107
154
|
| `pf-appsync-api-enhanced-metrics-values` | AWS::AppSync::GraphQLApi | DataSourceLevelMetricsBehavior takes one of two values | ERROR | pending-engine |
|
|
@@ -2421,6 +2468,26 @@
|
|
|
2421
2468
|
| `pf-secretsmanager-secret-name` | AWS::SecretsManager::Secret | A secret Name may only contain ASCII letters, digits and -/_+=.@! (no spaces, colons, hashes or non-ASCII text) | ERROR | none |
|
|
2422
2469
|
| `pf-secretsmanager-secret-string-exclusive` | AWS::SecretsManager::Secret | SecretString and GenerateSecretString cannot both be set on a secret | ERROR | none |
|
|
2423
2470
|
| `pf-secretsmanager-target-attachment` | AWS::SecretsManager::SecretTargetAttachment | SecretTargetAttachment needs a TargetType from the documented list and a secret whose value is a JSON object (SecretString JSON or GenerateSecretString with SecretStringTemplate) | ERROR | none |
|
|
2471
|
+
| `pf-servicediscovery-http-namespace-name-charset` | AWS::ServiceDiscovery::HttpNamespace | An HTTP namespace name must be printable ASCII | ERROR | none |
|
|
2472
|
+
| `pf-servicediscovery-http-namespace-name-length` | AWS::ServiceDiscovery::HttpNamespace | An HTTP namespace name is limited to 1024 characters | ERROR | cfn-schema |
|
|
2473
|
+
| `pf-servicediscovery-namespace-description-length` | AWS::ServiceDiscovery::HttpNamespace<br>AWS::ServiceDiscovery::PublicDnsNamespace<br>AWS::ServiceDiscovery::PrivateDnsNamespace | A namespace description is limited to 1024 characters | ERROR | cfn-schema |
|
|
2474
|
+
| `pf-servicediscovery-namespace-soa-ttl-range` | AWS::ServiceDiscovery::PublicDnsNamespace<br>AWS::ServiceDiscovery::PrivateDnsNamespace | The SOA record TTL of a DNS namespace may not exceed 2147483647 | ERROR | cfn-schema |
|
|
2475
|
+
| `pf-servicediscovery-private-namespace-name-charset` | AWS::ServiceDiscovery::PrivateDnsNamespace | A private DNS namespace name must be printable ASCII | ERROR | none |
|
|
2476
|
+
| `pf-servicediscovery-private-namespace-name-length` | AWS::ServiceDiscovery::PrivateDnsNamespace | A private DNS namespace name is limited to 253 characters | ERROR | none |
|
|
2477
|
+
| `pf-servicediscovery-public-namespace-name-length` | AWS::ServiceDiscovery::PublicDnsNamespace | A public DNS namespace name is limited to 253 characters | ERROR | none |
|
|
2478
|
+
| `pf-servicediscovery-public-namespace-name-pattern` | AWS::ServiceDiscovery::PublicDnsNamespace | A public DNS namespace name must be a multi-label DNS domain | ERROR | none |
|
|
2479
|
+
| `pf-servicediscovery-service-attributes-max-entries` | AWS::ServiceDiscovery::Service | A service may carry at most 30 service attributes | ERROR | cfn-schema |
|
|
2480
|
+
| `pf-servicediscovery-service-cname-requires-weighted` | AWS::ServiceDiscovery::Service | A CNAME service record requires the WEIGHTED routing policy | ERROR | none |
|
|
2481
|
+
| `pf-servicediscovery-service-cname-with-healthcheck` | AWS::ServiceDiscovery::Service | A CNAME service cannot carry a Route 53 health check | ERROR | none |
|
|
2482
|
+
| `pf-servicediscovery-service-dnsconfig-in-http-namespace` | AWS::ServiceDiscovery::Service | A service in an HTTP namespace cannot declare DnsConfig | ERROR | none |
|
|
2483
|
+
| `pf-servicediscovery-service-dnsrecord-type-combination` | AWS::ServiceDiscovery::Service | Only a few DnsRecords type combinations are valid | ERROR | none |
|
|
2484
|
+
| `pf-servicediscovery-service-dnsrecord-type-duplicate` | AWS::ServiceDiscovery::Service | DnsRecords may not repeat the same record type | ERROR | none |
|
|
2485
|
+
| `pf-servicediscovery-service-healthcheck-in-private-namespace` | AWS::ServiceDiscovery::Service | A service in a private DNS namespace cannot carry a health check | ERROR | none |
|
|
2486
|
+
| `pf-servicediscovery-service-http-type-with-dnsconfig` | AWS::ServiceDiscovery::Service | A service of Type HTTP cannot declare DnsConfig | ERROR | none |
|
|
2487
|
+
| `pf-servicediscovery-service-name-case-collision` | AWS::ServiceDiscovery::Service | Two services in one DNS namespace may not differ only by case | ERROR | none |
|
|
2488
|
+
| `pf-servicediscovery-service-name-duplicate-in-namespace` | AWS::ServiceDiscovery::Service | Two services in one namespace may not share a name | ERROR | none |
|
|
2489
|
+
| `pf-servicediscovery-service-namespace-required` | AWS::ServiceDiscovery::Service | A service must name the namespace it belongs to | ERROR | none |
|
|
2490
|
+
| `pf-servicediscovery-service-tcp-healthcheck-resourcepath` | AWS::ServiceDiscovery::Service | A TCP health check may not carry a resource path | ERROR | none |
|
|
2424
2491
|
| `pf-sns-delivery-policy` | AWS::SNS::Subscription<br>AWS::SNS::Topic | HTTP/S DeliveryPolicy retry values: minDelayTarget >= 1, maxDelayTarget <= 3600 and >= minDelayTarget, numRetries 0..100 and at least the sum of the phase retries, phase counts >= 0, backoffFunction one of arithmetic|exponential|geometric|linear, maxReceivesPerSecond >= 1 (subscription DeliveryPolicy and topic DeliveryPolicy.http) | ERROR | none |
|
|
2425
2492
|
| `pf-sns-fifo-only-attributes` | AWS::SNS::Topic | ContentBasedDeduplication, ArchivePolicy and FifoThroughputScope are FIFO-only topic attributes, and ArchivePolicy.MessageRetentionPeriod is 1..365 days | ERROR | none |
|
|
2426
2493
|
| `pf-sns-fifo-queue-on-standard-topic` | AWS::SNS::Subscription<br>AWS::SNS::Topic | A FIFO SQS queue cannot subscribe to a standard topic (a FIFO topic may fan out to standard queues, not the reverse) | ERROR | 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.146" };
|
|
21
21
|
/**
|
|
22
22
|
* Register the cdk-preflight rules on an App or Stage.
|
|
23
23
|
*/
|