This page explains the structure of a rule, what a finding looks like, and how to control which rules run.
Rule Anatomy
Every CloudBurn rule is a Rule object with the following properties. Optional fields are marked ?.
| Field | Type | Description |
|---|---|---|
id | string | Unique rule identifier (e.g., CLDBRN-AWS-EC2-3) |
name | string | Human-readable rule name |
description | string | What the rule checks and why it matters |
message | string | Finding message template shown in output |
provider | CloudProvider | Cloud provider: aws, azure, or gcp |
service | string | Service short name (e.g., ec2, s3) |
severity | Severity | Relative cost impact: high, medium, or low |
supports | Source[] | Scan types this rule supports: discovery, iac, or both |
discoveryDependencies? | DiscoveryDatasetKey[] | Live datasets the rule requires |
optionalDiscoveryDependencies? | DiscoveryDatasetKey[] | Live datasets the rule uses only when another active rule already requested them |
staticDependencies? | StaticDatasetKey[] | Normalized IaC datasets the rule requires |
supersedesRuleIds? | string[] | Rule IDs whose identical resource findings this rule replaces with stronger evidence |
evaluateLive? | (context: LiveEvaluationContext) => Finding | null | Discovery evaluator |
getLiveEvaluationCoverage? | (context: LiveEvaluationContext) => LiveEvaluationCoverage | Resource-level evidence coverage, reported independently of findings |
evaluateStatic? | (context: StaticEvaluationContext) => Finding | null | IaC evaluator |
Source is 'discovery' | 'iac'. ScanSource is a deprecated alias for Source. Severity is derived from the exported SEVERITIES tuple (['high', 'medium', 'low']).
See Rule in the SDK reference for the same contract as consumed from TypeScript.
Rule Dependencies
A rule does not call AWS APIs itself. It declares the normalized datasets it needs, and the SDK loads only those datasets for the rules in the active scan.
discoveryDependencieslistsDiscoveryDatasetKeyvalues (for exampleaws-rds-instances,aws-lambda-function-metrics). The SDK hands them toevaluateLivethrough aLiveResourceBag, reachable ascontext.resources.get(key). A missing dataset reads as an empty array, so evaluators need no defensive checks.optionalDiscoveryDependencieslists datasets the evaluator reads when they happen to be loaded but never triggers a collection for on its own. Rules use this to cross-check another rule's evidence without adding API cost to scans that do not need it.staticDependencieslistsStaticDatasetKeyvalues thatevaluateStaticreads from aStaticResourceBag, populated from parsed Terraform and CloudFormation files.
LiveEvaluationContext carries catalog (the Resource Explorer-backed AwsDiscoveryCatalog used as the scan seed) plus resources. StaticEvaluationContext carries resources only.
Severity
Every rule declares a severity of high, medium, or low, reflecting its relative cost impact. Severity is fixed per rule — it's not computed from the finding count or resource size — and every finding produced by a rule inherits that rule's severity.
Severity powers policy gates: the CLI and SDK can fail a scan when active findings meet or exceed a configured severity threshold, so CI can block a merge on high-severity waste while still surfacing low-severity findings informationally. See the CLI scan command and CLI discover command for the --fail-on flag, and ScanPolicyResult in the SDK reference for the programmatic equivalent.
Finding Anatomy
When a rule detects a problem, it produces a finding. The overall result for a scan run looks like this:
{
"ruleId": "CLDBRN-AWS-EC2-3",
"service": "ec2",
"source": "discovery",
"severity": "low",
"message": "Elastic IP address is not associated with any resource",
"findings": [
{
"resourceId": "eipalloc-0abc1234def56789",
"accountId": "123456789012",
"region": "us-east-1"
}
]
}
The outer object is a Finding. Each entry in findings[] is a FindingMatch.
| Field | Description |
|---|---|
ruleId | The rule that produced this finding |
service | AWS service the finding belongs to |
source | How the finding was detected: discovery or iac |
severity | The producing rule's severity: high, medium, or low |
message | Human-readable description of the problem |
findings[] | One entry per affected resource |
findings[].resourceId | The specific resource ID (instance ID, bucket name, etc.) |
findings[].resourceType | Provider resource namespace, set when one resource ID can appear under more than one namespace |
findings[].actionType | Recommended operation, set when several findings on one resource need to stay distinct |
findings[].accountId | AWS account that owns the resource (discovery scans only) |
findings[].region | AWS region where the resource lives (discovery scans only) |
findings[].location | File location as a SourceLocation object (IaC scans only) |
resourceType and actionType exist so that two rules reporting the same resource ID can still be compared. A rule that reports rds:db capacity waste and one that reports rds:db-storage waste describe different spend on the same identifier, and a Rightsize match is not the same result as a Stop match. They stay absent when the resource ID alone is unambiguous.
Live Evaluation Coverage
A discovery rule can declare getLiveEvaluationCoverage, which reports, per resource, whether the rule had enough evidence to decide anything. It runs independently of evaluateLive and returns a LiveEvaluationCoverage:
type LiveEvaluationCoverage = {
/** Resources with enough evidence to establish a finding or a non-finding. */
assessed: FindingMatch[];
/** Resources that cannot be assessed because required evidence is unavailable or incomplete. */
unknown: FindingMatch[];
};
Both arrays hold the same FindingMatch identities the rule's findings use, so a resource can be traced from coverage to finding and back.
This separates "the rule checked this resource and it is fine" from "the rule could not check this resource". A CloudWatch metric with incomplete datapoints, an AWS Compute Optimizer result that never arrived, or a load balancer protocol the rule cannot reason about all land in unknown rather than being silently counted as a pass. Rules that do not declare getLiveEvaluationCoverage report no coverage breakdown.
Each service rule page states which resources a given rule reports as unknown under a Coverage label.
Finding Precedence
Two rules can legitimately report the same waste from different evidence, usually a CloudBurn rule that inspects the resource directly and an AWS-sourced recommendation that reports the same resource second-hand. A rule declares supersedesRuleIds to name the rule IDs whose identical resource findings it replaces, so the run reports the stronger evidence once instead of two findings for one problem.
Matching is by finding identity, not by rule. A superseded finding is dropped only when its resourceType, resourceId, accountId, region, and actionType all match a finding the superseding rule actually produced in the same run. Findings the superseding rule did not produce are left alone, and a superseding rule that is disabled or produced nothing suppresses nothing.
Discovery vs IaC Scan Types
Discovery
Discovery rules scan live AWS resources. CloudBurn uses AWS Resource Explorer to enumerate resources and then calls service APIs to gather the data each rule needs.
- Requires AWS credentials with read access to the scanned accounts
- Reflects the actual state of your infrastructure right now
- Can detect runtime issues like idle resources, missing attachments, and low utilization
IaC
IaC rules scan Terraform (.tf) and CloudFormation (.json and .yaml) template files statically. No AWS credentials required.
- Works in CI pipelines before resources are deployed
- Catches misconfigurations at the point of authorship
- Covers Terraform resource types like
aws_instance,aws_lambda_function, and CloudFormation types likeAWS::EC2::Instance
Both
Some rules support both modes. In discovery mode they evaluate the live resource; in IaC mode they evaluate the template. The rule ID and finding format are identical regardless of source.
Enabling and Disabling Rules
Most built-in rules run by default under the aws-core preset. A small number of rules are excluded from that preset because they depend on AWS features you have to turn on yourself, or because they report account-wide rather than on one service. Add an opt-in rule's ID to enabled-rules to include it in a scan.
| Opt-in rule | Why it is excluded |
|---|---|
| CLDBRN-AWS-COSTOPTIMIZATIONHUB-1 to -6 | Read AWS Cost Optimization Hub, which has to be enabled in the payer account before it returns anything |
| CLDBRN-AWS-LAMBDA-4 | Reads AWS Compute Optimizer memory recommendations, which require Compute Optimizer to be opted in |
| CLDBRN-AWS-TAGGING-1 | Reports on every taggable resource in the account and needs an accessible Resource Explorer aggregator index |
Config File (.cloudburn.yml)
Rules are configured per scan mode (iac or discovery):
iac:
# Run only these rules for IaC scans
enabled-rules:
- CLDBRN-AWS-EC2-1
- CLDBRN-AWS-S3-1
discovery:
# Exclude specific rules from discovery scans
disabled-rules:
- CLDBRN-AWS-EC2-11
- CLDBRN-AWS-EC2-10
Use enabled-rules when you want an explicit allowlist. Use disabled-rules when you want to suppress a small number of rules while running everything else. See the Configuration reference for the full schema.
CLI Flags
# Run only specific rules
cloudburn discover --enabled-rules CLDBRN-AWS-EC2-3,CLDBRN-AWS-S3-1
# Exclude specific rules
cloudburn scan --disabled-rules CLDBRN-AWS-EC2-11,CLDBRN-AWS-EC2-10
SDK
import { CloudBurnClient } from '@cloudburn/sdk';
const client = new CloudBurnClient();
// Discovery scan with rule filter
await client.discover({
config: {
discovery: {
enabledRules: ['CLDBRN-AWS-EC2-3', 'CLDBRN-AWS-S3-1'],
},
},
});
// IaC scan with rule exclusion
await client.scanStatic('./iac', {
iac: {
disabledRules: ['CLDBRN-AWS-EC2-11'],
},
});
Service Filtering
You can limit scans to specific AWS services rather than filtering by individual rule IDs.
Config file:
discovery:
services:
- ec2
- s3
- rds
CLI:
cloudburn discover --service ec2,s3
SDK:
await client.discover({
config: {
discovery: {
services: ['ec2', 's3'],
},
},
});
Conservative Evaluation
Rules skip resources when the data needed to make a confident determination is incomplete. This means CloudBurn produces fewer false positives — if a rule cannot conclusively identify waste, it does not flag the resource. You will not be chased to remediate something that turns out to be fine.
Skipping is not the same as passing. Where a rule declares live evaluation coverage, the resources it skipped are reported as unknown instead of disappearing into the set of resources that looked fine, so a gap in evidence stays visible.
What's Next
- Rules Overview — full list of rules by service
- CLI scan command — run IaC scans
- CLI discover command — scan live resources
- SDK Reference — integrate CloudBurn programmatically