cdk-preflight
Catch deploy-time CloudFormation failures at cdk synth time.
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.
cdk-preflight is a curated Rego rule pack 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.
The 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 (or is explicitly marked doc-only). Rules that the built-in validation engine already covers are deliberately not duplicated — a test suite enforces this.
Quick start
npm i -D cdk-preflight
npx cdk-preflight init # inserts Preflight.apply(app) into your CDK app
or add one line yourself:
import { Preflight } from 'cdk-preflight';
const app = new App();
Preflight.apply(app);
On violation, cdk synth fails with one error per finding, including the construct trace:
ERROR idle_timeout.timeout_seconds is 5000 but must be between 1 and 4000 seconds (cdk-preflight)
MyStack/Alb/Resource (Alb16C2F182) aws-cdk-lib.aws_elasticloadbalancingv2.CfnLoadBalancer
Synthesis finished with errors
Observe-only mode
To 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:
Preflight.apply(app, { enforce: false });
WARNING idle_timeout.timeout_seconds is 5000 but must be between 1 and 4000 seconds (CloudFormation Validate)
MyStack/Alb (Alb) aws-cdk-lib.aws_elasticloadbalancingv2.CfnLoadBalancer
Acknowledge with 'CloudFormation-Validate::pf-elbv2-lb-idle-timeout-range'
| Option | Default | Effect |
|---|---|---|
enforce |
true |
Violations of bundled rules fail synthesis; set to false to only warn |
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 |
exclude |
[] |
Rule ids to disable |
includeUpstreamPending |
true |
Include rules already proposed to the upstream engine but not yet merged |
To opt out of a single rule, pass its id in exclude. In observe-only mode, individual findings can also be suppressed with the CDK acknowledge mechanism shown in the warning text.
Bundled rules
See docs/rules.md for the generated rule table. Highlights:
- ELBv2:
idle_timeout/deregistration_delay/slow_startattribute ranges (stringly-typed Key/Value attributes are invisible to schema validation) - IAM: managed (6,144 chars) and inline (role/group/user) policy document size limits
- CloudFront:
MinTTL <= DefaultTTL <= MaxTTLordering, ACM certificates must live inus-east-1 - Step Functions:
Next/Default/Choicesmust reference defined states (a danglingStartAtis already caught by the engine's built-inE3601) - EC2: security group TCP/UDP port ranges and
FromPort <= ToPort
For AI agents
To add cdk-preflight to a CDK app:
npm i -D cdk-preflightnpx cdk-preflight init(finds the entry point viacdk.jsonand insertsPreflight.apply(app); use--dry-runto preview)- Run
cdk synth. Violations fail the synth with a validation report; each finding carries a rule id, the actual value, and a suggested fix - To fix a finding, prefer correcting the resource. To opt out instead:
exclude: ['<rule-id>']disables one rule,enforce: falseswitches to warn-only reporting
The machine-readable findings are written to cdk.out/validation-report.json when synthesizing with -c @aws-cdk/core:validationReportJson=true.
Report missed deploy errors
cdk-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):
## cdk-preflight: report missed deploy errors
If `cdk deploy` fails even though `cdk synth` (with cdk-preflight enabled) passed,
and the failure is a service-side validation rejection — CREATE_FAILED/UPDATE_FAILED
with a 400-class message such as "Invalid request provided: ..." — cdk-preflight is
missing a rule. Report it:
1. Qualify first. NOT reportable: AccessDenied / permissions, service quotas,
throttling, name conflicts with existing resources, stabilization timeouts.
2. Redact account-specific data (account IDs -> 123456789012, real ARNs/domains
-> placeholders).
3. Search existing issues: https://github.com/badmintoncryer/cdk-preflight/issues
4. With your user's approval, open a "Missed deploy error" issue with the verbatim
error message, the resource type, a minimal template snippet, and your
aws-cdk-lib / cdk-preflight versions.
Scope and rule lifecycle
A 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.
CDK 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.
That 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.
Rules 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.
How it works
Preflight.apply() evaluates the rules with the 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.
Constraints 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.
Requirements
aws-cdk-lib>= 2.267.0 (the first release that bundles the built-in CloudFormation validator)
Contributing
Rule authoring, the verification gates (including real-deploy reproduction), and the test layout are documented in AGENTS.md — written for AI coding agents and humans alike.
License
Apache-2.0
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cdk_preflight-0.0.42.tar.gz.
File metadata
- Download URL: cdk_preflight-0.0.42.tar.gz
- Upload date:
- Size: 717.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.14.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9c03bd7a1f4202d810eb24ff53eb02725c4e041858a52455ea491ae9aa3b9d32
|
|
| MD5 |
86a7c811012014ccc8ed68ef953e2d16
|
|
| BLAKE2b-256 |
d611f4c03db9bc9c2a5a6621f3ce74ea73e6a5bbf870ac1eea96a03e68f48e74
|
Provenance
The following attestation bundles were made for cdk_preflight-0.0.42.tar.gz:
Publisher:
release.yml on badmintoncryer/cdk-preflight
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cdk_preflight-0.0.42.tar.gz -
Subject digest:
9c03bd7a1f4202d810eb24ff53eb02725c4e041858a52455ea491ae9aa3b9d32 - Sigstore transparency entry: 2738039633
- Sigstore integration time:
-
Permalink:
badmintoncryer/cdk-preflight@3132d6b6f554a50c35844ddd2dc8d25ff6f7eece -
Branch / Tag:
refs/heads/main - Owner: https://github.com/badmintoncryer
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@3132d6b6f554a50c35844ddd2dc8d25ff6f7eece -
Trigger Event:
push
-
Statement type:
File details
Details for the file cdk_preflight-0.0.42-py3-none-any.whl.
File metadata
- Download URL: cdk_preflight-0.0.42-py3-none-any.whl
- Upload date:
- Size: 715.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.14.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d8b5720f2146ef371dd9c01b1ec8d9e4ff647801589e1919560647ff3ff0a253
|
|
| MD5 |
9162c371961cf0326e2eae427d1d6287
|
|
| BLAKE2b-256 |
65acbc3cca453ae9f90f558a1794b15073ee6d72de2b98d993fb39dcb290fd11
|
Provenance
The following attestation bundles were made for cdk_preflight-0.0.42-py3-none-any.whl:
Publisher:
release.yml on badmintoncryer/cdk-preflight
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
cdk_preflight-0.0.42-py3-none-any.whl -
Subject digest:
d8b5720f2146ef371dd9c01b1ec8d9e4ff647801589e1919560647ff3ff0a253 - Sigstore transparency entry: 2738039606
- Sigstore integration time:
-
Permalink:
badmintoncryer/cdk-preflight@3132d6b6f554a50c35844ddd2dc8d25ff6f7eece -
Branch / Tag:
refs/heads/main - Owner: https://github.com/badmintoncryer
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@3132d6b6f554a50c35844ddd2dc8d25ff6f7eece -
Trigger Event:
push
-
Statement type: