Findings¶
Findings come from scanners (Prowler, ScoutSuite, Checkov, Trivy, the IAM linter), from cloudg's reachability analysis, or from a loaded findings.json. Each finding is matched to an asset as described under Briefs. Suppressed findings stay in the dataset but drop out of list_findings (unless asked), every count of open findings, top_risks, compliance roll-ups and the prompts.
list_findings¶
Category findings · sensitivity confidential · capabilities read_state · readOnly true, destructive false, idempotent true, openWorld false · outputSchema yes · timeout: layer default (300 s)
Searches findings with filters, sorting and cursor pagination. severity_breakdown counts every match, not only the current page.
| Argument | Type | Default | Constraints | Description |
|---|---|---|---|---|
severities |
string[] or null | null |
Any of CRITICAL, HIGH, MEDIUM, LOW, INFO. | |
min_severity |
string | "" |
At or above this severity. | |
source_tool |
string | "" |
Substring of the producing tool, e.g. 'prowler', 'cloudg-reachability'. | |
framework |
string | "" |
Substring of a compliance framework, e.g. 'CIS', 'PCI'. | |
resource |
string | "" |
Only findings on this asset (ref). | |
query |
string | "" |
Substring of title or description. | |
include_suppressed |
boolean | false |
Also return suppressed findings. | |
sort_by |
string | "risk" |
one of risk, severity, detected_at, title, source_tool |
Sort order (see the sorting table). |
fields |
string[] or null | null |
Project items to these fields. Valid: id, title, severity, risk_score, source_tool, resource_id, resource_arn, asset_id, asset_name, compliance_frameworks, is_suppressed, cvss_score, detected_at, uri | |
limit |
integer | 50 |
1..500 | Maximum items to return. |
cursor |
string | "" |
Opaque cursor from a previous call's next_cursor; empty = first page. | |
dataset |
string | "" |
Dataset name (see list_datasets). Empty = the active dataset. |
Filter semantics: severities is an exact set; min_severity a threshold; source_tool and framework are case-insensitive substrings (pci matches PCI-DSS); resource resolves an asset reference and keeps the findings matched to it; query is a case-insensitive substring of the title or description.
Called with the arguments below, list_findings returned this structuredContent.
{
"dataset": "sample",
"total": 11,
"offset": 0,
"returned": 3,
"next_cursor": "c3.ab0acc7643a8",
"truncated": true,
"severity_breakdown": {
"CRITICAL": 2,
"HIGH": 5,
"MEDIUM": 2,
"LOW": 1,
"INFO": 1
},
"items": [
{
"id": "f-rdp-open",
"title": "NSG allows RDP (3389) from Internet",
"severity": "CRITICAL",
"risk_score": 9.5,
"source_tool": "scoutsuite",
"resource_id": "az-nsg",
"resource_arn": null,
"asset_id": "az-nsg",
"asset_name": "jump-nsg",
"compliance_frameworks": [
"CIS-Azure"
],
"is_suppressed": false,
"cvss_score": null,
"detected_at": "2026-01-15T12:00:00+00:00",
"uri": "cloudg://findings/f-rdp-open"
},
{
"id": "f-ssh-open",
"title": "Security group allows SSH (22) from 0.0.0.0/0",
"severity": "CRITICAL",
"risk_score": 9.5,
"source_tool": "prowler",
"resource_id": "sg-admin",
"resource_arn": "arn:aws:ec2:us-east-1:111111111111:security-group/sg-0admin",
"asset_id": "sg-admin",
"asset_name": "sg-admin",
"compliance_frameworks": [
"CIS-AWS",
"PCI-DSS"
],
"is_suppressed": false,
"cvss_score": null,
"detected_at": "2026-01-15T12:00:00+00:00",
"uri": "cloudg://findings/f-ssh-open"
},
"... 1 more"
]
}
With a framework filter and projection:
Called with the arguments below, list_findings returned this structuredContent.
{
"dataset": "sample",
"total": 3,
"offset": 0,
"returned": 3,
"next_cursor": null,
"truncated": false,
"severity_breakdown": {
"CRITICAL": 1,
"HIGH": 2
},
"items": [
{
"id": "f-ssh-open",
"title": "Security group allows SSH (22) from 0.0.0.0/0",
"severity": "CRITICAL",
"asset_name": "sg-admin"
},
{
"id": "f-web-cve",
"title": "CVE-2024-1234 in openssl 3.0.1",
"severity": "HIGH",
"asset_name": "web-1"
},
"... 1 more"
]
}
Suppressed findings appear only with include_suppressed:
Called with the arguments below, list_findings returned this structuredContent.
{
"dataset": "sample",
"total": 1,
"offset": 0,
"returned": 1,
"next_cursor": null,
"truncated": false,
"severity_breakdown": {
"LOW": 1
},
"items": [
{
"id": "f-versioning",
"title": "S3 versioning disabled",
"severity": "LOW",
"risk_score": 2.5,
"source_tool": "prowler",
"resource_id": "data-bucket",
"resource_arn": null,
"asset_id": "data-bucket",
"asset_name": "prod-data",
"compliance_frameworks": [
"CIS-AWS"
],
"is_suppressed": true,
"cvss_score": null,
"detected_at": "2026-01-15T12:00:00+00:00",
"uri": "cloudg://findings/f-versioning"
}
]
}
Related: get_finding, findings_summary, cloudg://findings/severity/{severity}.
get_finding¶
Category findings · sensitivity confidential · capabilities read_state · readOnly true, destructive false, idempotent true, openWorld false · outputSchema no · timeout: layer default (300 s)
One finding in full. finding_id is the finding's id; a scanner's own source_finding_id also works when exactly one finding has it. Returns the finding brief plus description, evidence, remediation, source_finding_id, controls (every compliance result that lists this finding: framework, control_id, control_title, status), suppression_reason when suppressed, and asset (brief) when the finding is matched. Links the affected asset and cloudg://findings/{id}.
| Argument | Type | Default | Constraints | Description |
|---|---|---|---|---|
finding_id |
string | required | min length 1 | Finding id (or the scanner's source_finding_id). |
dataset |
string | "" |
Dataset name (see list_datasets). Empty = the active dataset. |
Called with the arguments below, get_finding returned this structuredContent.
{
"id": "f-ssh-open",
"title": "Security group allows SSH (22) from 0.0.0.0/0",
"severity": "CRITICAL",
"risk_score": 9.5,
"source_tool": "prowler",
"resource_id": "sg-admin",
"resource_arn": "arn:aws:ec2:us-east-1:111111111111:security-group/sg-0admin",
"asset_id": "sg-admin",
"asset_name": "sg-admin",
"compliance_frameworks": [
"CIS-AWS",
"PCI-DSS"
],
"is_suppressed": false,
"cvss_score": null,
"detected_at": "2026-01-15T12:00:00+00:00",
"uri": "cloudg://findings/f-ssh-open",
"description": "Security group allows SSH (22) from 0.0.0.0/0.",
"evidence": "IpPermissions 0.0.0.0/0 tcp 22",
"remediation": "Restrict 22 to the VPN.",
"source_finding_id": "prowler-aws-ec2_sg_open_22-1",
"controls": [
{
"framework": "CIS-AWS",
"control_id": "5.2",
"control_title": "No SG allows 0.0.0.0/0 to admin ports",
"status": "FAIL"
},
{
"framework": "PCI-DSS",
"control_id": "1.3.1",
"control_title": "Inbound traffic restricted",
"status": "FAIL"
}
],
"asset": {
"id": "sg-admin",
"name": "sg-admin",
"type": "SECURITY_GROUP",
"provider": "AWS",
"region": "us-east-1",
"account_id": "111111111111",
"arn": "arn:aws:ec2:us-east-1:111111111111:security-group/sg-0admin",
"internet_exposed": false,
"open_findings": 1,
"max_severity": "CRITICAL",
"uri": "cloudg://assets/sg-admin"
}
}
The result also carried these resource links in content:
[
{
"type": "resource_link",
"uri": "cloudg://assets/sg-admin",
"name": "sg-admin",
"title": "Affected asset",
"mimeType": "application/json"
},
{
"type": "resource_link",
"uri": "cloudg://findings/f-ssh-open",
"name": "Security group allows SSH (22) from 0.0.0.0/0",
"mimeType": "application/json"
}
]
By scanner id (source_finding_id of the Trivy finding):
Called with the arguments below, get_finding returned this structuredContent.
{
"id": "f-web-cve",
"title": "CVE-2024-1234 in openssl 3.0.1",
"severity": "HIGH",
"risk_score": 7.8,
"source_tool": "trivy",
"resource_id": "web-1",
"resource_arn": null,
"asset_id": "web-1",
"asset_name": "web-1",
"compliance_frameworks": [
"PCI-DSS"
],
"is_suppressed": false,
"cvss_score": 8.1,
"detected_at": "2026-01-15T12:00:00+00:00",
"uri": "cloudg://findings/f-web-cve",
"description": "CVE-2024-1234 in openssl 3.0.1.",
"evidence": null,
"remediation": null,
"source_finding_id": "CVE-2024-1234",
"controls": [],
"asset": {
"id": "web-1",
"name": "web-1",
"type": "EC2",
"provider": "AWS",
"region": "us-east-1",
"account_id": "111111111111",
"arn": "arn:aws:ec2:us-east-1:111111111111:instance/i-0web1",
"internet_exposed": false,
"open_findings": 1,
"max_severity": "HIGH",
"uri": "cloudg://assets/web-1"
}
}
A miss suggests ids that contain the given text:
{
"tool": "get_finding",
"arguments": {
"finding_id": "f-ssh"
},
"isError": true,
"text": "No finding with that id in this dataset. 1 close match, see suggestions in the error data. Use list_findings to browse finding ids.",
"_meta": {
"cloudg/error_code": -32602,
"cloudg/error_data": {
"value": "f-ssh",
"dataset": "sample",
"suggestions": [
{
"finding_id": "f-ssh-open",
"dataset": "sample"
}
]
}
}
}
findings_summary¶
Category findings · sensitivity internal · capabilities read_state · readOnly true, destructive false, idempotent true, openWorld false · outputSchema no · timeout: layer default (300 s)
Finding counts grouped by severity, source tool, compliance framework, asset type, account or asset. Each group is {"total": n, "<SEVERITY>": n, ...}. With group_by: "framework" a finding counts once in each of its frameworks, and findings without one go under (none). With the asset-based groupings, findings not matched to an asset go under unmapped. total is the number of findings counted (open, or all with include_suppressed), not the sum of the groups; suppressed is always the dataset's suppressed count.
| Argument | Type | Default | Constraints | Description |
|---|---|---|---|---|
group_by |
string | "severity" |
one of severity, source_tool, framework, asset_type, account, asset |
Grouping dimension. asset_type, account and asset use the matched asset; unmatched findings go to unmapped. |
include_suppressed |
boolean | false |
Count suppressed findings too. | |
top |
integer | 25 |
1..200 | Maximum number of groups returned. |
dataset |
string | "" |
Dataset name (see list_datasets). Empty = the active dataset. |
Called with the arguments below, findings_summary returned this structuredContent.
{
"dataset": "sample",
"group_by": "severity",
"total": 11,
"suppressed": 1,
"groups": {
"CRITICAL": {
"total": 2,
"CRITICAL": 2
},
"HIGH": {
"total": 5,
"HIGH": 5
},
"MEDIUM": {
"total": 2,
"MEDIUM": 2
},
"LOW": {
"total": 1,
"LOW": 1
},
"INFO": {
"total": 1,
"INFO": 1
}
},
"truncated": false
}
Called with the arguments below, findings_summary returned this structuredContent.
{
"dataset": "sample",
"group_by": "account",
"total": 11,
"suppressed": 1,
"groups": {
"111111111111": {
"total": 7,
"CRITICAL": 1,
"HIGH": 3,
"MEDIUM": 1,
"LOW": 1,
"INFO": 1
},
"00000000-aaaa-bbbb-cccc-000000000001": {
"total": 1,
"CRITICAL": 1
},
"222222222222": {
"total": 1,
"HIGH": 1
},
"proj-analytics": {
"total": 1,
"HIGH": 1
},
"unmapped": {
"total": 1,
"MEDIUM": 1
}
},
"truncated": false
}
Called with the arguments below, findings_summary returned this structuredContent.
{
"dataset": "sample",
"group_by": "framework",
"total": 12,
"suppressed": 1,
"groups": {
"CIS-AWS": {
"total": 7,
"CRITICAL": 1,
"HIGH": 3,
"MEDIUM": 2,
"LOW": 1
},
"PCI-DSS": {
"total": 3,
"CRITICAL": 1,
"HIGH": 2
},
"(none)": {
"total": 2,
"LOW": 1,
"INFO": 1
}
},
"truncated": true
}
findings_for_asset¶
Category findings · sensitivity confidential · capabilities read_state · readOnly true, destructive false, idempotent true, openWorld false · outputSchema yes · timeout: layer default (300 s)
Every finding on one asset, highest risk first, as briefs. Returns asset, total, returned, truncated and items; no cursor.
| Argument | Type | Default | Constraints | Description |
|---|---|---|---|---|
ref |
string | required | min length 1 | Asset reference: internal id, ARN / cloud resource id, unique name, or unique ARN tail (e.g. 'function:api' or 'i-0abc'). |
include_suppressed |
boolean | false |
Also return suppressed findings. | |
limit |
integer | 50 |
1..500 | Maximum items to return. |
dataset |
string | "" |
Dataset name (see list_datasets). Empty = the active dataset. |
Called with the arguments below, findings_for_asset returned this structuredContent.
{
"dataset": "sample",
"asset": {
"id": "sg-admin",
"name": "sg-admin",
"type": "SECURITY_GROUP",
"provider": "AWS",
"region": "us-east-1",
"account_id": "111111111111",
"arn": "arn:aws:ec2:us-east-1:111111111111:security-group/sg-0admin",
"internet_exposed": false,
"open_findings": 1,
"max_severity": "CRITICAL",
"uri": "cloudg://assets/sg-admin"
},
"total": 1,
"returned": 1,
"truncated": false,
"items": [
{
"id": "f-ssh-open",
"title": "Security group allows SSH (22) from 0.0.0.0/0",
"severity": "CRITICAL",
"risk_score": 9.5,
"source_tool": "prowler",
"resource_id": "sg-admin",
"resource_arn": "arn:aws:ec2:us-east-1:111111111111:security-group/sg-0admin",
"asset_id": "sg-admin",
"asset_name": "sg-admin",
"compliance_frameworks": [
"CIS-AWS",
"PCI-DSS"
],
"is_suppressed": false,
"cvss_score": null,
"detected_at": "2026-01-15T12:00:00+00:00",
"uri": "cloudg://findings/f-ssh-open"
}
]
}
top_risks¶
Category findings · sensitivity confidential · capabilities read_state · readOnly true, destructive false, idempotent true, openWorld false · outputSchema yes · timeout: layer default (300 s)
The assets to fix first. Only assets with at least one open finding (at or above min_severity) are candidates; findings on unmapped resources are ignored. The score and its components are described under Risk scores. Each item is {asset, score, components, top_findings} with the three riskiest findings; the result adds total_candidates and the formula string.
| Argument | Type | Default | Constraints | Description |
|---|---|---|---|---|
top |
integer | 10 |
1..100 | Number of assets returned. |
min_severity |
string | "" |
Only consider open findings at or above this severity. | |
dataset |
string | "" |
Dataset name (see list_datasets). Empty = the active dataset. |
internet_reachable in the components is true for any asset that is flagged exposed or that the reachability analysis reaches from the internet over network-flow edges. On the sample estate that includes the two security groups below: their internet-sourced rules make them reachable, although they are not flagged exposed themselves.
Called with the arguments below, top_risks returned this structuredContent.
{
"dataset": "sample",
"items": [
{
"asset": {
"id": "az-nsg",
"name": "jump-nsg",
"type": "NSG",
"provider": "AZURE",
"region": "westeurope",
"account_id": "00000000-aaaa-bbbb-cccc-000000000001",
"arn": "/subscriptions/00000000-aaaa-bbbb-cccc-000000000001/resourceGroups/rg-hub/providers/Microsoft.Network/networkSecurityGroups/jump-nsg",
"internet_exposed": false,
"open_findings": 1,
"max_severity": "CRITICAL",
"uri": "cloudg://assets/az-nsg"
},
"score": 16.39,
"components": {
"max_finding_risk": 9.5,
"exposure_factor": 1.5,
"internet_reachable": true,
"transitive_dependents": 1,
"blast_factor": 1.151,
"open_findings": 1,
"volume_factor": 1.0
},
"top_findings": [
{
"id": "f-rdp-open",
"title": "NSG allows RDP (3389) from Internet",
"severity": "CRITICAL",
"risk_score": 9.5,
"source_tool": "scoutsuite",
"resource_id": "az-nsg",
"resource_arn": null,
"asset_id": "az-nsg",
"asset_name": "jump-nsg",
"compliance_frameworks": [
"CIS-Azure"
],
"is_suppressed": false,
"cvss_score": null,
"detected_at": "2026-01-15T12:00:00+00:00",
"uri": "cloudg://findings/f-rdp-open"
}
]
},
{
"asset": {
"id": "sg-admin",
"name": "sg-admin",
"type": "SECURITY_GROUP",
"provider": "AWS",
"region": "us-east-1",
"account_id": "111111111111",
"arn": "arn:aws:ec2:us-east-1:111111111111:security-group/sg-0admin",
"internet_exposed": false,
"open_findings": 1,
"max_severity": "CRITICAL",
"uri": "cloudg://assets/sg-admin"
},
"score": 16.39,
"components": {
"max_finding_risk": 9.5,
"exposure_factor": 1.5,
"internet_reachable": true,
"transitive_dependents": 1,
"blast_factor": 1.151,
"open_findings": 1,
"volume_factor": 1.0
},
"top_findings": [
{
"id": "f-ssh-open",
"title": "Security group allows SSH (22) from 0.0.0.0/0",
"severity": "CRITICAL",
"risk_score": 9.5,
"source_tool": "prowler",
"resource_id": "sg-admin",
"resource_arn": "arn:aws:ec2:us-east-1:111111111111:security-group/sg-0admin",
"asset_id": "sg-admin",
"asset_name": "sg-admin",
"compliance_frameworks": [
"CIS-AWS",
"PCI-DSS"
],
"is_suppressed": false,
"cvss_score": null,
"detected_at": "2026-01-15T12:00:00+00:00",
"uri": "cloudg://findings/f-ssh-open"
}
]
},
"... 1 more"
],
"total_candidates": 10,
"formula": "max_risk * exposure * blast * volume"
}
Related: get_asset, blast_radius, the remediation_plan prompt.
suppress_findings¶
Category findings · sensitivity confidential · capabilities read_state, write_state · readOnly false, destructive false, idempotent true, openWorld false · outputSchema no · timeout: layer default (300 s)
Marks findings as accepted risk or false positive in the in-memory dataset. Nothing is written to disk or to the cloud, and unloading the dataset loses the suppression. The reason is stored per finding (and shown by get_finding); suppressing an already suppressed finding replaces its reason. Returns suppressed (changed now), already_suppressed and not_found. The dataset version only changes, and cursors only go stale, when at least one finding changed.
| Argument | Type | Default | Constraints | Description |
|---|---|---|---|---|
finding_ids |
string[] | required | min items 1; max items 500 | Finding ids (exact id, not source_finding_id). |
reason |
string | required | min length 3; max length 500 | Why (accepted risk, false positive...). |
dataset |
string | "" |
Dataset name (see list_datasets). Empty = the active dataset. |
Called with the arguments below, suppress_findings returned this structuredContent.
{
"finding_ids": [
"f-default-vpc",
"f-versioning",
"f-nope"
],
"reason": "Accepted risk: sandbox VPC, tracked in RISK-42"
}
{
"dataset": "sample",
"suppressed": [
"f-default-vpc"
],
"already_suppressed": [
"f-versioning"
],
"not_found": [
"f-nope"
]
}
get_finding then shows the reason:
Called with the arguments below, get_finding returned the suppression_reason part of its structuredContent.
{
"tool": "suppress_findings",
"arguments": {
"finding_ids": [
"f-default-vpc"
],
"reason": "ok"
},
"isError": true,
"text": "Invalid arguments: reason: String should have at least 3 characters",
"_meta": {
"cloudg/error_code": -32602,
"cloudg/error_data": [
{
"loc": "reason",
"msg": "String should have at least 3 characters",
"type": "string_too_short"
}
]
}
}
unsuppress_findings¶
Category findings · sensitivity confidential · capabilities read_state, write_state · readOnly false, destructive false, idempotent true, openWorld false · outputSchema no · timeout: layer default (300 s)
Restores suppressed findings. Returns unsuppressed, not_suppressed (were not suppressed) and not_found, and drops the stored reasons.
| Argument | Type | Default | Constraints | Description |
|---|---|---|---|---|
finding_ids |
string[] | required | min items 1; max items 500 | Finding ids (exact id). |
dataset |
string | "" |
Dataset name (see list_datasets). Empty = the active dataset. |
Called with the arguments below, unsuppress_findings returned this structuredContent.
{
"dataset": "sample",
"unsuppressed": [
"f-default-vpc"
],
"not_suppressed": [
"f-web-cve"
],
"not_found": []
}
ingest_reports¶
Category findings · sensitivity confidential · capabilities read_fs, read_state, write_state · readOnly false, destructive false, idempotent false, openWorld false · outputSchema no · timeout: layer default (300 s)
Parses existing scanner output (no scanner runs and nothing is sent to the cloud) and adds the findings to a dataset, matching them to assets by ARN, id or name.
| Argument | Type | Default | Constraints | Description |
|---|---|---|---|---|
reports |
object (string to string[]) | required | Tool -> report paths (files or directories inside an allowed root), e.g. {'prowler': ['out/prowler/'], 'trivy': ['scan.json']}. Tools: prowler, scoutsuite, checkov, trivy. | |
dataset |
string | "" |
Dataset to add the findings to; empty = active. Created if new_dataset is true. | |
new_dataset |
boolean | false |
Create a new findings-only dataset named dataset instead. |
|
normalise |
boolean | true |
Deduplicate across scanners and map to compliance frameworks afterwards. | |
activate |
boolean | true |
With new_dataset: make the new dataset the active one (like load_dataset). | |
replace |
boolean | false |
With new_dataset: overwrite an existing dataset of that name. |
Behaviour in detail:
reportsmaps a tool name (prowler,scoutsuite,checkov,trivy, case-insensitive) to a list of files or directories. An unknown tool fails the whole call before anything is read.- Every path must resolve inside an allowed root; one path outside fails the whole call with an access error. A path that cannot be parsed or does not exist is reported in
errorsand the call continues. Prowler output is read as ASFF or OCSF, record by record, and its passing checks feed the compliance results. - With
new_dataset: true, an empty dataset nameddataset(oringested, made unique) is created withkind: "report",source: "ingest". It becomes the active dataset unlessactivateis false. A name that is already loaded is refused before anything is parsed, unlessreplaceis true. - With
normalise: true(the default) the normaliser runs over the dataset's existing findings plus the new ones: duplicates across scanners merge, findings get scores and framework tags, and the normaliser's compliance results are merged into the dataset's (merge_complianceincloudg/mcp/catalog/_findings.py): a control the normaliser evaluated takes its new result plus any surviving finding ids the old result listed; a control it did not evaluate (scanner-native mappings, PASS results) is kept with its finding ids filtered to findings that still exist, and dropped only when all of them are gone. Suppression flags survive by finding id. Withnormalise: falsethe findings are appended as parsed.
Returns dataset, parsed, per_path (tool, path, findings), errors (tool, path, error), findings_before, findings_after, matched_to_assets (how many parsed findings map to an asset), normalised and active (the active dataset after the call).
A one-record Prowler ASFF file naming sg-web by ARN, taken after snapshot_dataset so the change can be diffed:
Called with the arguments below, ingest_reports returned this structuredContent.
{
"dataset": "sample",
"parsed": 1,
"per_path": [
{
"tool": "prowler",
"path": "scans/prowler-asff.json",
"findings": 1
}
],
"errors": [],
"findings_before": 12,
"findings_after": 13,
"matched_to_assets": 1,
"normalised": true,
"active": "sample"
}
{
"tool": "ingest_reports",
"arguments": {
"reports": {
"nmap": [
"x.xml"
]
}
},
"isError": true,
"text": "Unsupported tool(s) nmap. Supported: prowler, scoutsuite, checkov, trivy",
"_meta": {
"cloudg/error_code": -32602
}
}
Called with the arguments below, ingest_reports returned this structuredContent.
{
"dataset": "sample",
"parsed": 0,
"per_path": [],
"errors": [
{
"tool": "trivy",
"path": "scans/missing.json",
"error": "Report path does not exist: <estate>/scans/missing.json"
}
],
"findings_before": 13,
"findings_after": 13,
"matched_to_assets": 0,
"normalised": true,
"active": "sample"
}
OCSF input into a new, inactive dataset:
Called with the arguments below, ingest_reports returned this structuredContent.
{
"reports": {
"prowler": [
"scans/prowler-ocsf.json"
]
},
"dataset": "ocsf-test",
"new_dataset": true,
"activate": false
}
{
"dataset": "ocsf-test",
"parsed": 1,
"per_path": [
{
"tool": "prowler",
"path": "scans/prowler-ocsf.json",
"findings": 1
}
],
"errors": [],
"findings_before": 0,
"findings_after": 1,
"matched_to_assets": 0,
"normalised": true,
"active": "sample"
}
After this ingest, compliance_summary(framework="CIS-AWS") on the same dataset reported 6 evaluated controls: the fixture's 5.2, 2.1.4, 1.16 and 3.1 (the PASS included) were kept, and the normaliser added CIS-AWS/ec2_sg_open_22 (the check name read from the fixture finding's prowler-aws-ec2_sg_open_22-1 id) and CIS-AWS-aggregate.
Called with the arguments below, compliance_summary returned this structuredContent.
{
"dataset": "sample",
"frameworks": [
{
"framework": "CIS-AWS",
"controls_evaluated": 6,
"controls_failing": 5,
"controls_passing": 1,
"controls_other": 0,
"pass_rate": 16.7,
"open_findings": 7,
"severity_breakdown": {
"CRITICAL": 1,
"HIGH": 3,
"MEDIUM": 2,
"INFO": 1
},
"affected_assets": 6,
"uri": "cloudg://compliance/CIS-AWS"
}
]
}
Related: snapshot_dataset (before), diff_datasets (after), normalise_findings, run_scanners (run the scanners instead).
normalise_findings¶
Category findings · sensitivity internal · capabilities read_state, write_state · readOnly false, destructive false, idempotent true, openWorld false · outputSchema no · timeout: layer default (300 s)
Re-runs cloudg's normaliser (cloudg.normaliser.FindingsNormaliser, with the configured rules directory) over a dataset's findings: deduplication within and across scanners by check-equivalence rules, scoring, and a fresh compliance mapping merged into the existing results the same way ingest_reports merges them. Suppression flags survive by id. Returns before and after counts of findings and compliance results and the resulting frameworks.
| Argument | Type | Default | Constraints | Description |
|---|---|---|---|---|
dataset |
string | "" |
Dataset name (see list_datasets). Empty = the active dataset. |
On the sample dataset, after the ingest above had already normalised it once, a second run changes nothing:
Called with the arguments below, normalise_findings returned this structuredContent.
{
"dataset": "sample",
"findings_before": 13,
"findings_after": 13,
"compliance_results_before": 22,
"compliance_results_after": 22,
"frameworks": [
"CIS-AWS",
"CIS-Azure",
"CIS-GCP",
"... 5 more"
]
}
reachability_findings¶
Category findings · sensitivity confidential · capabilities read_state, write_state · readOnly false, destructive false, idempotent false, openWorld false · outputSchema no · timeout: layer default (300 s)
Runs cloudg.graph.reachability.ReachabilityAnalyzer over a copy of the relationship graph and returns its findings, with source_tool: "cloudg-reachability": a CRITICAL finding for each sensitive data store (RDS, Aurora, Azure SQL, Cloud SQL, DynamoDB) reachable from the internet, a HIGH finding for other reachable assets whose type is not expected to face the internet (load balancers, CloudFront, CDNs and internet gateways are expected; security groups, NSGs, NACLs and target groups are passed through but never reported), and a CRITICAL finding for each sensitive port that an ingress rule opens to the internet (0.0.0.0/0, ::/0 or an Azure Internet, Any or * source). "Reachable" follows network-flow edges only, as described under Graph: an IAM grant does not make a database reachable, and a function behind a public API gateway is not reported.
Without add_to_dataset it only previews. Findings already in the dataset, by id or by (source tool, title, resource id), are skipped, so repeated runs do not duplicate. The ids are the analyser's own: a UUID5 hash of the rule and the asset's ARN (or id), so the same exposure keeps its id from scan to scan and a previewed id is the id that gets added. Added findings are not normalised. Returns generated, new (not yet in the dataset), added, the bounded total, returned, truncated and items (briefs of the new ones).
| Argument | Type | Default | Constraints | Description |
|---|---|---|---|---|
add_to_dataset |
boolean | false |
Append them to the dataset's findings (otherwise preview only). | |
limit |
integer | 50 |
1..500 | Maximum items to return. |
dataset |
string | "" |
Dataset name (see list_datasets). Empty = the active dataset. |
Called with the arguments below, reachability_findings returned this structuredContent.
{
"dataset": "sample",
"generated": 9,
"new": 9,
"added": 0,
"total": 9,
"returned": 3,
"truncated": true,
"items": [
{
"id": "4404191e-4430-5cd8-9a4d-036bbb058662",
"title": "Unexpected internet-exposed resource: public-api",
"severity": "HIGH",
"risk_score": 7.5,
"source_tool": "cloudg-reachability",
"resource_id": "api-gw",
"resource_arn": "arn:aws:apigateway:us-east-1::/restapis/a1b2c3",
"asset_id": "api-gw",
"asset_name": "public-api",
"compliance_frameworks": [],
"is_suppressed": false,
"cvss_score": null,
"detected_at": "2026-10-09T14:25:22.341914",
"uri": "cloudg://findings/4404191e-4430-5cd8-9a4d-036bbb058662"
},
{
"id": "1ee8a511-d242-5bf0-8313-163d439997e2",
"title": "Unexpected internet-exposed resource: jump-vm",
"severity": "HIGH",
"risk_score": 7.5,
"source_tool": "cloudg-reachability",
"resource_id": "az-vm",
"resource_arn": "/subscriptions/00000000-aaaa-bbbb-cccc-000000000001/resourceGroups/rg-hub/providers/Microsoft.Compute/virtualMachines/jump-vm",
"asset_id": "az-vm",
"asset_name": "jump-vm",
"compliance_frameworks": [],
"is_suppressed": false,
"cvss_score": null,
"detected_at": "2026-10-09T14:25:22.341937",
"uri": "cloudg://findings/1ee8a511-d242-5bf0-8313-163d439997e2"
},
"... 1 more"
]
}
Related: normalise_findings after adding, internet_exposure.