cloudg 0.3.0__tar.gz → 0.3.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {cloudg-0.3.0 → cloudg-0.3.2}/PKG-INFO +3 -6
- {cloudg-0.3.0 → cloudg-0.3.2}/README.md +2 -5
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/__init__.py +1 -1
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/api.py +59 -8
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/cli.py +260 -248
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/normaliser.py +194 -34
- cloudg-0.3.2/cloudg/rules/check_equivalence.yaml +67 -0
- cloudg-0.3.2/cloudg/ui.py +255 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/pyproject.toml +1 -1
- {cloudg-0.3.0 → cloudg-0.3.2}/tests/test_normaliser.py +106 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/tests/test_scanner_orchestration.py +40 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/.gitignore +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/LICENSE +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/collectors/__init__.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/collectors/aws.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/collectors/azure.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/collectors/base.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/collectors/gcp.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/collectors/multi.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/config.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/coverage.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/credentials.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/graph/__init__.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/graph/builder.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/graph/ontology.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/graph/rag_export.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/graph/reachability.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/policies/custodian-aws-security.yml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/policies/custodian-azure.yml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/policies/custodian-gcp.yml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/policies/custodian.yml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/region_discovery.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/registry.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/renderers/__init__.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/renderers/html_report.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/renderers/json_export.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/renderers/svg.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/renderers/terraform_export.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/retry.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/cis_aws_v3.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/cis_azure_v2.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/cis_gcp_v3.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/frameworks/aws_foundational_security_best_practices_aws.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/frameworks/cis_5.0_aws.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/frameworks/cis_5.0_azure.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/frameworks/cis_5.0_gcp.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/frameworks/gdpr_aws.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/frameworks/hipaa_aws.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/frameworks/hipaa_azure.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/frameworks/hipaa_gcp.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/frameworks/iso27001_2022_aws.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/frameworks/iso27001_2022_azure.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/frameworks/iso27001_2022_gcp.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/frameworks/mitre_attack_aws.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/frameworks/mitre_attack_azure.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/frameworks/mitre_attack_gcp.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/frameworks/nist_800_53_revision_5_aws.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/frameworks/nist_csf_2.0_aws.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/frameworks/pci_4.0_aws.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/frameworks/pci_4.0_azure.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/frameworks/pci_4.0_gcp.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/frameworks/soc2_aws.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/frameworks/soc2_azure.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/frameworks/soc2_gcp.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/gdpr.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/hipaa_security_rule.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/iso_27001_2022.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/nist_800_53.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/pci_dss_v4.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/rules/soc2_tsc.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/scanners/__init__.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/scanners/checkov.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/scanners/iam_linter.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/scanners/prowler.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/scanners/scoutsuite.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/scanners/trivy.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/schema/__init__.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/schema/models.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/cloudg/templates/report.html.j2 +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/tests/__init__.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/tests/conftest.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/tests/test_api.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/tests/test_collectors.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/tests/test_ontology.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/tests/test_rag_export.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/tests/test_region_discovery.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.2}/tests/test_terraform_export.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: cloudg
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.2
|
|
4
4
|
Summary: cloudg (cloud graphing) — multi-cloud infrastructure mapping, knowledge graphs and security intelligence for AWS, Azure and GCP
|
|
5
5
|
Project-URL: Homepage, https://github.com/morpheuslord/cloudg
|
|
6
6
|
Project-URL: Repository, https://github.com/morpheuslord/cloudg
|
|
@@ -75,7 +75,7 @@ Description-Content-Type: text/markdown
|
|
|
75
75
|
<p align="center">
|
|
76
76
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License: MIT"></a>
|
|
77
77
|
<img src="https://img.shields.io/badge/python-3.11%2B-blue.svg" alt="Python 3.11+">
|
|
78
|
-
<img src="https://img.shields.io/badge/version-0.3.
|
|
78
|
+
<img src="https://img.shields.io/badge/version-0.3.1-4c1.svg" alt="Version 0.3.1">
|
|
79
79
|
<a href="https://github.com/astral-sh/uv"><img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json" alt="uv"></a>
|
|
80
80
|
</p>
|
|
81
81
|
|
|
@@ -194,7 +194,7 @@ Collection runs all providers concurrently with asyncio, iterating accounts and
|
|
|
194
194
|
|
|
195
195
|
The same inventory feeds three other exports. The ontology module infers about 62 typed relations (`exposed_to_internet`, `assumes_role`, `encrypted_by`, `hosted_in_vpc` and so on) and writes RDF you can query with SPARQL. The RAG exporter chunks the graph three ways (per asset, per Louvain community, per relation domain) into JSONL for retrieval pipelines. The Terraform exporter maps 25+ asset types to `.tf.json` resources with an `import.sh` to adopt them into state.
|
|
196
196
|
|
|
197
|
-
Scanner findings are deduplicated by resource and title
|
|
197
|
+
Scanner findings are deduplicated in two passes — within a scanner by (scanner, check ID, resource), and across scanners only when both the normalised title and the underlying check semantics (`rules/check_equivalence.yaml`) match — then rescored against CVSS and mapped to compliance controls.
|
|
198
198
|
|
|
199
199
|
---
|
|
200
200
|
|
|
@@ -325,6 +325,3 @@ Python 3.11 or newer. The moto/aiobotocore incompatibility around async response
|
|
|
325
325
|
|
|
326
326
|
---
|
|
327
327
|
|
|
328
|
-
## License
|
|
329
|
-
|
|
330
|
-
MIT
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<p align="center">
|
|
6
6
|
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-green.svg" alt="License: MIT"></a>
|
|
7
7
|
<img src="https://img.shields.io/badge/python-3.11%2B-blue.svg" alt="Python 3.11+">
|
|
8
|
-
<img src="https://img.shields.io/badge/version-0.3.
|
|
8
|
+
<img src="https://img.shields.io/badge/version-0.3.1-4c1.svg" alt="Version 0.3.1">
|
|
9
9
|
<a href="https://github.com/astral-sh/uv"><img src="https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json" alt="uv"></a>
|
|
10
10
|
</p>
|
|
11
11
|
|
|
@@ -124,7 +124,7 @@ Collection runs all providers concurrently with asyncio, iterating accounts and
|
|
|
124
124
|
|
|
125
125
|
The same inventory feeds three other exports. The ontology module infers about 62 typed relations (`exposed_to_internet`, `assumes_role`, `encrypted_by`, `hosted_in_vpc` and so on) and writes RDF you can query with SPARQL. The RAG exporter chunks the graph three ways (per asset, per Louvain community, per relation domain) into JSONL for retrieval pipelines. The Terraform exporter maps 25+ asset types to `.tf.json` resources with an `import.sh` to adopt them into state.
|
|
126
126
|
|
|
127
|
-
Scanner findings are deduplicated by resource and title
|
|
127
|
+
Scanner findings are deduplicated in two passes — within a scanner by (scanner, check ID, resource), and across scanners only when both the normalised title and the underlying check semantics (`rules/check_equivalence.yaml`) match — then rescored against CVSS and mapped to compliance controls.
|
|
128
128
|
|
|
129
129
|
---
|
|
130
130
|
|
|
@@ -255,6 +255,3 @@ Python 3.11 or newer. The moto/aiobotocore incompatibility around async response
|
|
|
255
255
|
|
|
256
256
|
---
|
|
257
257
|
|
|
258
|
-
## License
|
|
259
|
-
|
|
260
|
-
MIT
|
|
@@ -43,6 +43,34 @@ from cloudg.schema.models import (
|
|
|
43
43
|
logger = logging.getLogger(__name__)
|
|
44
44
|
|
|
45
45
|
|
|
46
|
+
def resolve_iac_dirs(
|
|
47
|
+
iac_dir: str | None,
|
|
48
|
+
config_dirs: list[str] | None,
|
|
49
|
+
terraform_dir: str | Path | None = None,
|
|
50
|
+
) -> tuple[list[str], str | None]:
|
|
51
|
+
"""Resolve which directories the IaC scanners (Checkov, Trivy fs) target.
|
|
52
|
+
|
|
53
|
+
Priority: explicit dir -> configured dirs -> the generated Terraform
|
|
54
|
+
recreation of the live infrastructure. There is deliberately no fallback
|
|
55
|
+
to "." any more: scanning whatever directory cloudg happens to run from
|
|
56
|
+
is not a scan of the cloud, and its zero findings read like a clean bill
|
|
57
|
+
of health.
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
(dirs, source) where source is "cli", "config", "terraform", or
|
|
61
|
+
None when there is nothing for the IaC scanners to target.
|
|
62
|
+
"""
|
|
63
|
+
if iac_dir:
|
|
64
|
+
return [iac_dir], "cli"
|
|
65
|
+
if config_dirs:
|
|
66
|
+
return list(config_dirs), "config"
|
|
67
|
+
if terraform_dir:
|
|
68
|
+
tf_path = Path(terraform_dir)
|
|
69
|
+
if tf_path.is_dir() and any(tf_path.glob("*.tf.json")):
|
|
70
|
+
return [str(tf_path)], "terraform"
|
|
71
|
+
return [], None
|
|
72
|
+
|
|
73
|
+
|
|
46
74
|
# ---------------------------------------------------------------------------
|
|
47
75
|
# Result dataclasses
|
|
48
76
|
# ---------------------------------------------------------------------------
|
|
@@ -285,14 +313,37 @@ class CloudGEngine:
|
|
|
285
313
|
logger.error("Graph analysis failed: %s", exc)
|
|
286
314
|
self._emit_error("graph_analysis", exc)
|
|
287
315
|
|
|
288
|
-
# Resolve IaC directories
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
316
|
+
# Resolve IaC directories. When nothing is configured but Terraform
|
|
317
|
+
# recreation is enabled, generate it now and scan that: the IaC
|
|
318
|
+
# scanners then audit the live infrastructure via its Terraform
|
|
319
|
+
# representation instead of an unrelated local directory.
|
|
320
|
+
tf_dir: str | None = None
|
|
321
|
+
if (
|
|
322
|
+
not iac_dir
|
|
323
|
+
and not self.config.scanners.iac_directories
|
|
324
|
+
and self.config.terraform.enabled
|
|
325
|
+
):
|
|
326
|
+
tf_dir = self.config.terraform.output_dir or str(out / "terraform")
|
|
327
|
+
try:
|
|
328
|
+
from cloudg.renderers.terraform_export import TerraformExporter
|
|
329
|
+
|
|
330
|
+
TerraformExporter(output_dir=tf_dir).export(assets, edges)
|
|
331
|
+
except Exception as exc:
|
|
332
|
+
logger.error("Terraform export for IaC scanning failed: %s", exc)
|
|
333
|
+
self._emit_error("terraform", exc)
|
|
334
|
+
tf_dir = None
|
|
335
|
+
|
|
336
|
+
resolved_iac_dirs, iac_source = resolve_iac_dirs(
|
|
337
|
+
iac_dir, self.config.scanners.iac_directories, tf_dir
|
|
338
|
+
)
|
|
339
|
+
if iac_source == "terraform":
|
|
340
|
+
logger.info("IaC scanners target the Terraform recreation at %s", resolved_iac_dirs[0])
|
|
341
|
+
elif not resolved_iac_dirs and "checkov" in scanner_list:
|
|
342
|
+
logger.warning(
|
|
343
|
+
"Skipping Checkov: no IaC directory configured. "
|
|
344
|
+
"Pass iac_dir, set scanners.iac_directories, or enable terraform "
|
|
345
|
+
"so the recreated infrastructure can be scanned."
|
|
346
|
+
)
|
|
296
347
|
|
|
297
348
|
# Resolve images
|
|
298
349
|
resolved_images: list[str] = images or list(self.config.scanners.trivy_images)
|