feat(core): ship default CloudFormation validation rules in Rego - #38448
Open
iankhou wants to merge 7 commits into
Open
feat(core): ship default CloudFormation validation rules in Rego#38448iankhou wants to merge 7 commits into
iankhou wants to merge 7 commits into
Conversation
The CloudFormationValidatePlugin already accepts custom Rego rules via its `regoRules` prop, but the auto-registered default instance passed none. This loads CDK-authored `.rego` rules from `core/lib/validation/rules/` into the default plugin instance so they run on every synth. The first rule set (`gamelift-fleet.rego`) ports the aws-gamelift-alpha BuildFleet L2 validations (name/description length, location and ingress-rule counts, non-negative location capacity) to template-level checks on `AWS::GameLift::Fleet`. Unlike the L2 constructor checks, these also cover templates produced via L1 constructs, escape hatches, and CfnInclude, and they evaluate post-synth so token-valued properties are already resolved. Findings surface as warnings and do not fail synth unless the app opts into `@aws-cdk/core:validateAgainstDefaultRules`, matching the existing plugin rollout posture.
aws-cdk-automation
previously requested changes
Jul 29, 2026
…ants The first version of the GameLift rules duplicated checks the engine's built-in schema rules already report (F3031-F3034 cover string lengths, item counts, per-field minimums and patterns). Replace them with five cross-field invariants the resource schema cannot express: - CDK-GameLift-001: ingress rule FromPort must not exceed ToPort - CDK-GameLift-002: location capacity MinSize must not exceed MaxSize - CDK-GameLift-003: DesiredEC2Instances must lie within [MinSize, MaxSize] - CDK-GameLift-004: SIMPLE-routing alias must not set a terminal Message - CDK-GameLift-005: TERMINAL-routing alias must not reference a fleet The alias rules port the "terminal message or fleet, not both" check from aws-gamelift-alpha's Alias construct; the fleet rules add API-enforced invariants that today only fail at deploy time.
The stack deploys a compliant TERMINAL-routing GameLift alias and carries a violating alias (TERMINAL routing plus FleetId, CDK-GameLift-005) behind a never-true condition: the default Rego rules evaluate the full template regardless of conditions, so the finding is captured in the snapshot's validation-report.json, while CloudFormation never creates the invalid resource the GameLift API would reject. Deploying proves the default warning posture does not block deployment.
An explicitly registered CloudFormationValidatePlugin replaces the auto-registered default instance, so passing custom rules would silently drop the CDK default rules. The constructor now merges the default rules with any user-supplied regoRules; a new includeDefaultRules prop (default true) opts out entirely. Also documents the default rules in the README (rule table, severity posture, suppression by ID) and adds tests covering the merge, the opt-out, and suppression of a default rule finding via Validations.of(scope).acknowledge().
aws-cdk-automation
dismissed
their stale review
July 30, 2026 17:13
✅ Updated pull request passes all PRLinter validations. Dismissing previous PRLinter review.
…avior Empirically probing the GameLift API showed the two failure modes the default rules cover are different: the fleet rules (001-003) catch real deploy-time rejections (CreateFleet refuses inverted port ranges; UpdateFleetCapacity refuses out-of-range capacity values, surfacing as a CloudFormation NotStabilized rollback), while the alias routing rules (004-005) catch contradictory configuration that GameLift accepts and partially ignores - the deployment succeeds with one field silently unused. Reword the rule file, README, and integ test comment accordingly; no behavioral changes.
iankhou
commented
Jul 30, 2026
iankhou
marked this pull request as ready for review
July 30, 2026 20:53
aws-cdk-automation
temporarily deployed
to
automation
July 30, 2026 21:31 — with
GitHub Actions
Inactive
aws-cdk-automation
temporarily deployed
to
automation
July 30, 2026 21:31 — with
GitHub Actions
Inactive
…ft-006/007) Join a fleet to the AWS::GameLift::Build it references through the template's Ref graph and check that every server-process launch path lives under the install root dictated by the build's operating system (C:\game for Windows, /local/game for Linux). A mismatch is schema-valid and deploys, but the fleet then activates into ERROR state because no server process can start. This is the first cross-resource default rule: the invariant spans two resources, so no single construct can validate it — BuildFleet only sees an IBuild interface, which erases the build's operating system. The rules stay silent for imported builds (literal BuildId) and builds that omit OperatingSystem, since the OS is unknowable in those cases.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #38456
Description
CloudFormationValidatePlugin accepts custom Rego rules via its
regoRulesprop, but the auto-registered default instance doesn't pass any rules. This change loads CDK-authored.regorules fromcore/lib/validation/rules/into the default plugin instance so they run on each synth.We use ruleset
gamelift-fleet.regofor alpha moduleaws-gamelift-alphato proof this change. The ruleset validatesBuildFleetclass L2 validations (name/description length, location and ingress-rule counts, non-negative location capacity) to template-level checks onAWS::GameLift::Fleet.In the ruleset at
packages/aws-cdk-lib/core/lib/validation/rules/gamelift-fleet.rego, rules 001-003 validate to ensure against configurations that will fail deployment. Rules 004-005 validate against configurations that are not effective on the service and would deploy correctly, but have no-op behavior. Rules 006-007 are cross-resource rules: they join a fleet to theAWS::GameLift::Buildit references through the template'sRefgraph and check that server-process launch paths match the build's operating system — an invariant no single construct can validate in isolation (see below).Placement policy: why do these rules live in the CDK and not in cloudformation-validate?
All of these rules are plain Rego over the engine's template model, so any of them could eventually be contributed upstream to the engine's built-in ruleset. CDK-authored default rules are the fast-iteration tier: they ship and fix on every aws-cdk-lib release (the engine is pinned and versioned independently — cf. the existing
IGNORE_RULESblock, which exists because upstream rules can only be worked around on CDK's schedule), and they sit next to the L2 constructs whose validation behavior they mirror. Rules that prove stable and generically useful are candidates for upstreaming to cloudformation-validate, at which point the CDK drops its copy.How did we come up with these rules?
We probed the GameLift API directly with various misconfigurations, and deployed a CDK app containing misconfigurations.
Direct calls
CDK-GameLift-001
CDK-GameLift-002
CDK-GameLift-003
CDK-GameLift-004
For this case, we set
Message, even though we configure SIMPLE routing. According to the docs, only TERMINAL routing usesMessage.Note that there are no API failures for this.
Pay particular attention to
Message=goodbyeMessageis gone, since the API just dropped it (instead of erroring on it), but there was no failure.The Message is absent from both the creation response
and the stored state as it was silently discarded by the API. The alias routes normally; the terminal message the author configured can never be shown.
CDK-GameLift-005
In this example, we provide a FleetID with routing strategy TERMINAL. However, only SIMPLE routing uses the FleetID. What happens if we pass it?
The API doesn't throw. But it ignores FleetID and doesn't include it in the response.
Since the operator configured the alias with a FleetId, they might expect to be able to resolve the alias and see it. But that will result in an error.
The
FleetIdis absent from both the creation response and the stored state, as it is silently discarded by the API. Clients resolving the alias get the terminal exception instead of a game server, with no indication a FleetId was ever supplied.GameLift CDK app deployment
We deployed an app with the following misconfiguration:
The misconfigured fields are schema-valid, so template validation passes and the deploy proceeds. GameLift builds the fleet for ~5 minutes, then fails to apply the capacity, and CloudFormation rolls the stack back.
From
aws describe-stack-eventspost-deployment:This whole deploy-time failure took about 7 minutes. With rule 002, we detect these misconfigurations at synth time.
Findings surface as warnings and do not fail synth unless the app opts in using flag
@aws-cdk/core:validateAgainstDefaultRules.Full example app code:
cdk synthoutput for this code:Prior to this change, there would have been no errors.
Cross-resource rules (CDK-GameLift-006/007)
Game builds are installed on fleet instances at an OS-specific root —
C:\gameon Windows,/local/gameon Linux (docs) — so every server-processLaunchPathmust live under the root dictated by the referenced build'sOperatingSystem. A mismatch is schema-valid and deploys, but the fleet then activates intoERRORstate because no server process can start.Describe any new or updated permissions being added
None.
Description of how you validated changes
Unit and integration tests. Manual testing as detailed above.
Integration test validates that the default shipped rules validate the code and report correctly.
Checklist
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license