Rules Architecture (packages/rules)
September 9, 2026 ยท View on GitHub
Type Hierarchy
classDiagram
class Rule {
+string id
+string name
+string description
+string message
+Severity severity
+provider: 'aws' | 'azure' | 'gcp'
+string service
+Severity severity
+Source[] supports
+DiscoveryDatasetKey[] discoveryDependencies?
+DiscoveryDatasetKey[] optionalDiscoveryDependencies?
+string[] supersedesRuleIds?
+StaticDatasetKey[] staticDependencies?
+evaluateLive(ctx: LiveEvaluationContext)? Finding
+getLiveEvaluationCoverage(ctx: LiveEvaluationContext)? LiveEvaluationCoverage
+evaluateStatic(ctx: StaticEvaluationContext)? Finding
}
class Finding {
+string ruleId
+string service
+Source source
+string message
+FindingMatch[] findings
}
class FindingMatch {
+string resourceId
+string resourceType?
+string accountId?
+string region?
+SourceLocation location?
}
class LiveEvaluationContext {
+AwsDiscoveryCatalog catalog
+LiveResourceBag resources
}
class LiveResourceBag {
+get(key: DiscoveryDatasetKey) DiscoveryDatasetMap[key]
}
class StaticResourceBag {
+get(key: StaticDatasetKey) StaticDatasetMap[key]
}
class StaticEvaluationContext {
+StaticResourceBag resources
}
Rule --> Finding : produces
Finding --> FindingMatch : contains
Rule --> LiveEvaluationContext : evaluateLive input
LiveEvaluationContext --> LiveResourceBag : contains
Rule --> StaticEvaluationContext : evaluateStatic input
StaticEvaluationContext --> StaticResourceBag : contains
Rules return a single grouped Finding or null. The SDK regroups those rule findings under providers in the public ScanResult.
Live rules can also implement getLiveEvaluationCoverage(context) to return assessed and unknown resource
identities without changing the evaluator's return shape. assessed includes both findings and known non-findings;
unknown means required evidence is unavailable or incomplete. Use the same identity as the rule's findings, and
include the inventory dataset in discoveryDependencies when missing metric rows would otherwise hide resources.
The pure createLiveEvaluationCoverage helper partitions an inventory with a rule-specific assessment predicate.
All built-in CloudWatch metric rules report this coverage, as do the ECR lifecycle-content rules and the Compute
Optimizer Lambda memory rule. ECR repositories with a lifecycle policy whose traits could not be parsed stay unknown,
while repositories without a policy remain assessed. Lambda functions are assessed only when the memory
recommendation dataset carries a memory_overprovisioned or not_overprovisioned assessment for their ARN; absent or
unavailable assessments stay unknown. EBS volumes attached to an instance that is missing from the inventory, or
whose state was not reported, stay unknown for the stopped-instance attachment rule. Each rule checks its own
required normalized metrics, so
unknown Lambda errors do not prevent duration assessment. A resource that is outside a rule's policy remains
assessed without metric evidence. EC2's low-utilization rule can establish a finding from four observed idle days;
a non-finding requires all 14 observed days. The additive observedDays field records that count; legacy custom
EC2 loaders that omit it can still establish findings, but cannot establish a complete non-finding.
Unknown AWS Config recording metrics retain their candidate identities with null recorded-item counts and saving
estimates. Custom consumers of AwsConfigRecordingFrequencyReview must check these nullable fields before using
them in calculations. The SDK exposes the rule's coverage and reports unknown rather than a passed evaluation when
required evidence is missing and no findings were established.
The rules metadata test enforces that a live rule whose verdict joins more than one dataset, or reads optional
datasets, declares getLiveEvaluationCoverage. Rules whose secondary datasets are complete inventories, where
absence is itself the evidence, are listed with a justification in that test instead of adding a hook.
Rules with stronger evidence can declare supersedesRuleIds. The live engine removes only findings with the same
resource namespace, ID, account, and Region, and only when the superseding rule is active and emits that identity.
Evaluation records retain each evaluator's original result, including findings later omitted from provider output by
precedence.
Rule Assembly Chain
graph LR
RuleFile["createRule({...})\nvolume-type-current-gen.ts"] --> ServiceIdx["ebsRules\nebs/index.ts"]
ServiceIdx --> ProviderIdx["awsRules\naws/index.ts"]
ProviderIdx --> Preset["awsCorePreset\npresets/aws-core.ts"]
ProviderIdx --> Export["public export\nindex.ts"]
Preset --> Export
awsRules is the complete public AWS rule pack. awsCorePreset is the runtime default and may exclude opt-in rules whose infrastructure requirements are not guaranteed by a standard setup.
Authoring Rules
See docs/guides/adding-a-rule.md for the full end-to-end guide and docs/reference/rule-ids.md for the ID convention and complete rule table.
Current Rules
See docs/reference/rule-ids.md for the complete rule table with descriptions and support modes.
AWS evidence joins use the full resource identity. Service-local identifiers such as Redshift cluster names and EMR cluster IDs are scoped by account and region before matching metrics.
Load-balancer rules build one target-group ARN index per evaluation. An unknown target group never counts as empty.