discover() scans your live AWS environment using AWS Resource Explorer. Unlike static analysis, it finds cost issues in resources that are already running — even if they were never deployed through IaC.
Prerequisites
- Valid AWS credentials configured (see AWS Credentials)
- AWS Resource Explorer enabled for catalog-backed rules, including the default AWS Core preset. Runs that enable only account-scoped rules skip Resource Explorer; see Minimum IAM permissions.
How discovery works
Full example
import { CloudBurnClient } from '@cloudburn/sdk';
const client = new CloudBurnClient();
// Initialize Resource Explorer (first time only)
const init = await client.initializeDiscovery({ region: 'us-east-1' });
console.log(`Setup: ${init.status}, coverage: ${init.coverage}`);
// Check status
const status = await client.getDiscoveryStatus();
console.log(`Coverage: ${status.coverage}, regions: ${status.indexedRegionCount}`);
// Run discovery scan
const result = await client.discover();
for (const provider of result.providers) {
for (const finding of provider.rules) {
console.log(`[${finding.ruleId}] ${finding.message} (${finding.findings.length} resources)`);
}
}
Initialize once
initializeDiscovery() attempts cross-region Resource Explorer setup with an aggregator index. Existing indexes can be reused, promoted, or have their default view updated to include tags. If cross-region setup is denied, it can fall back to local-only discovery and return a warning. Inspect indexType, coverage, and verificationStatus; status: 'EXISTING' alone does not establish cross-region readiness. See initializeDiscovery().
After initialization, Resource Explorer takes a few minutes to index your resources before discovery scans return complete results.
Check coverage before scanning
getDiscoveryStatus() returns the current coverage level:
| Coverage | Meaning |
|---|---|
full | An aggregator exists and all enabled regions are indexed |
partial | Some regions are indexed, some are not |
local_only | Only the local region is indexed |
none | No regions are indexed yet |
Scan specific regions
Target a single region:
const result = await client.discover({
target: { mode: 'region', region: 'eu-west-1' },
});
Scan all indexed regions:
const result = await client.discover({
target: { mode: 'all' },
});
Use the current region only:
const result = await client.discover({
target: { mode: 'current' },
});
Scan multiple specific regions:
const result = await client.discover({
target: { mode: 'regions', regions: ['us-east-1', 'eu-west-1'] },
});
Tracking progress
Discovery runs independent collection work in parallel and evaluates each rule as soon as its evidence is ready, so rules finish at different times. Pass onProgress to receive catalog, dataset, and provisional rule events while the run is still going:
const result = await client.discover({
onProgress: (event) => {
if (event.kind === 'catalog') console.log(`Catalog: ${event.resourceCount} resources`);
if (event.kind === 'dataset') console.log(`Dataset ${event.completedDatasets}/${event.totalDatasets}`);
if (event.kind === 'rule') console.log(`${event.ruleId}: ${event.status} (${event.findingCount} findings)`);
},
});
Rule events are provisional; the resolved ScanResult replaces them. See AwsDiscoveryProgressEvent.
Bounding the run
Raise the default deadline with timeoutMs, and cancel a run in flight with your own signal:
const controller = new AbortController();
const result = await client.discover({
target: { mode: 'all' },
timeoutMs: 600_000,
signal: controller.signal,
});
An expired deadline or a cancelled signal rejects without returning a partial ScanResult. See AwsDiscoveryExecutionOptions.
Scoping credentials
discover() accepts per-call AWS credentials for multi-account scans:
const result = await client.discover({
aws: { credentials: assumedRoleCredentials },
});
See AWS Credentials for the multi-account credential pattern.
Reusing evidence between scans
Evidence reuse is off unless you pass cache:
const result = await client.discover({
target: { mode: 'regions', regions: ['eu-west-1'] },
cache: {
directory: '/home/example/.cache/cloudburn/evidence',
mode: 'normal',
authorizationContext: 'production-readonly-policy-v3',
},
});
for (const artifact of result.evidence ?? []) {
console.log(`${artifact.datasetKey}: ${artifact.source}, collected ${artifact.collectedAt}`);
}
Rules and configuration are evaluated again on every run; only collected AWS evidence is reused. See Credentials and evidence reuse for which credentials can reuse evidence, and AwsEvidenceCacheOptions for every field and its default.
Auditing rules that did not produce findings
Set includeEvaluationResources: true to get result.evaluations, which records every selected rule as triggered, passed, unknown, or not_applicable alongside the resource identities it inspected:
const result = await client.discover({ includeEvaluationResources: true });
for (const evaluation of result.evaluations?.rules ?? []) {
console.log(`${evaluation.ruleId}: ${evaluation.status}`);
if (evaluation.coverage) {
console.log(` assessed ${evaluation.coverage.assessed.length}, unknown ${evaluation.coverage.unknown.length}`);
}
}
Code that validates status strings must accept unknown. A rule reports unknown when it ran but could not assess some resources, usually because a metric window was incomplete or a dependency was denied. Shared resource sets are emitted once in result.evaluations.resourceSets and referenced by RuleEvaluation.resourceSetId. See ScanEvaluations.
Checking AWS evidence capabilities
result.capabilities summarizes capability readiness observed through the datasets the scan collected, without making extra readiness calls:
for (const outcome of result.capabilities ?? []) {
console.log(`${outcome.capability}: ${outcome.status} (${outcome.reasons.join(', ')})`);
}
This is scoped evidence rather than an account-wide setup certificate. Keep each outcome's scope, and do not interpret an absent capability as available. See AwsCapabilityOutcome.
Handling diagnostics
If the SDK cannot access certain services or regions, it reports them in result.diagnostics rather than failing the entire scan. See Handling access errors for how to read a denial.
const result = await client.discover();
if (result.diagnostics?.length) {
for (const diag of result.diagnostics) {
console.warn(`[${diag.status}] ${diag.service} in ${diag.region}: ${diag.message}`);
}
}
What's next
| AWS Credentials | Configure credentials and IAM permissions |
| CloudBurnClient Reference | Full discover() API reference |
| Types Reference | AwsDiscoveryStatus and related types |