cloudg 0.3.0__tar.gz → 0.3.1__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.1}/PKG-INFO +2 -5
- {cloudg-0.3.0 → cloudg-0.3.1}/README.md +1 -4
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/__init__.py +1 -1
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/api.py +59 -8
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/cli.py +31 -14
- {cloudg-0.3.0 → cloudg-0.3.1}/pyproject.toml +1 -1
- {cloudg-0.3.0 → cloudg-0.3.1}/tests/test_scanner_orchestration.py +40 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/.gitignore +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/LICENSE +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/collectors/__init__.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/collectors/aws.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/collectors/azure.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/collectors/base.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/collectors/gcp.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/collectors/multi.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/config.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/coverage.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/credentials.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/graph/__init__.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/graph/builder.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/graph/ontology.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/graph/rag_export.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/graph/reachability.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/normaliser.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/policies/custodian-aws-security.yml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/policies/custodian-azure.yml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/policies/custodian-gcp.yml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/policies/custodian.yml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/region_discovery.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/registry.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/renderers/__init__.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/renderers/html_report.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/renderers/json_export.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/renderers/svg.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/renderers/terraform_export.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/retry.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/cis_aws_v3.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/cis_azure_v2.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/cis_gcp_v3.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/frameworks/aws_foundational_security_best_practices_aws.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/frameworks/cis_5.0_aws.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/frameworks/cis_5.0_azure.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/frameworks/cis_5.0_gcp.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/frameworks/gdpr_aws.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/frameworks/hipaa_aws.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/frameworks/hipaa_azure.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/frameworks/hipaa_gcp.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/frameworks/iso27001_2022_aws.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/frameworks/iso27001_2022_azure.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/frameworks/iso27001_2022_gcp.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/frameworks/mitre_attack_aws.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/frameworks/mitre_attack_azure.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/frameworks/mitre_attack_gcp.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/frameworks/nist_800_53_revision_5_aws.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/frameworks/nist_csf_2.0_aws.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/frameworks/pci_4.0_aws.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/frameworks/pci_4.0_azure.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/frameworks/pci_4.0_gcp.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/frameworks/soc2_aws.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/frameworks/soc2_azure.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/frameworks/soc2_gcp.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/gdpr.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/hipaa_security_rule.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/iso_27001_2022.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/nist_800_53.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/pci_dss_v4.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/rules/soc2_tsc.yaml +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/scanners/__init__.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/scanners/checkov.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/scanners/iam_linter.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/scanners/prowler.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/scanners/scoutsuite.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/scanners/trivy.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/schema/__init__.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/schema/models.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/cloudg/templates/report.html.j2 +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/tests/__init__.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/tests/conftest.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/tests/test_api.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/tests/test_collectors.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/tests/test_normaliser.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/tests/test_ontology.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/tests/test_rag_export.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/tests/test_region_discovery.py +0 -0
- {cloudg-0.3.0 → cloudg-0.3.1}/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.1
|
|
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
|
|
|
@@ -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
|
|
|
@@ -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)
|
|
@@ -567,15 +567,6 @@ def run(
|
|
|
567
567
|
if "gcp" in cfg.providers:
|
|
568
568
|
console.print(f"[bold]GCP regions:[/] {cfg.gcp.regions}")
|
|
569
569
|
|
|
570
|
-
# ── Resolve IaC directories: CLI flag → config → default "." ──
|
|
571
|
-
resolved_iac_dirs: list[str] = []
|
|
572
|
-
if iac_dir:
|
|
573
|
-
resolved_iac_dirs = [iac_dir]
|
|
574
|
-
elif cfg.scanners.iac_directories:
|
|
575
|
-
resolved_iac_dirs = list(cfg.scanners.iac_directories)
|
|
576
|
-
else:
|
|
577
|
-
resolved_iac_dirs = ["."]
|
|
578
|
-
|
|
579
570
|
# ── Resolve container images: CLI flag → config ──
|
|
580
571
|
resolved_images: list[str] = []
|
|
581
572
|
if images:
|
|
@@ -653,6 +644,7 @@ def run(
|
|
|
653
644
|
console.print(f" [red]✗ RAG export failed: {exc}[/]")
|
|
654
645
|
|
|
655
646
|
# Phase 2d: Terraform Recreation
|
|
647
|
+
tf_dir: str | None = None
|
|
656
648
|
if terraform or cfg.terraform.enabled:
|
|
657
649
|
console.print("\n[bold]Phase 2d: Terraform Recreation[/]")
|
|
658
650
|
try:
|
|
@@ -673,6 +665,7 @@ def run(
|
|
|
673
665
|
console.print(f" [green]✓ Import: {tf_paths['import_commands']}[/]")
|
|
674
666
|
except Exception as exc:
|
|
675
667
|
console.print(f" [red]✗ Terraform export failed: {exc}[/]")
|
|
668
|
+
tf_dir = None
|
|
676
669
|
|
|
677
670
|
import concurrent.futures
|
|
678
671
|
|
|
@@ -680,6 +673,18 @@ def run(
|
|
|
680
673
|
console.print("\n[bold]Phase 3: Security Scanning[/bold] (Running in parallel)")
|
|
681
674
|
scanner_findings: list[Any] = []
|
|
682
675
|
|
|
676
|
+
# ── Resolve IaC scan targets: CLI flag → config → Terraform recreation ──
|
|
677
|
+
# No fallback to "." — scanning the directory cloudg runs from is not a
|
|
678
|
+
# scan of the cloud, and its zero findings look like a clean result.
|
|
679
|
+
from cloudg.api import resolve_iac_dirs
|
|
680
|
+
|
|
681
|
+
resolved_iac_dirs, iac_source = resolve_iac_dirs(iac_dir, cfg.scanners.iac_directories, tf_dir)
|
|
682
|
+
if iac_source == "terraform":
|
|
683
|
+
console.print(
|
|
684
|
+
" [dim]IaC scanners target the Terraform recreation of the live "
|
|
685
|
+
f"infrastructure ({resolved_iac_dirs[0]})[/dim]"
|
|
686
|
+
)
|
|
687
|
+
|
|
683
688
|
def run_prowler(prov: str) -> list[Any]:
|
|
684
689
|
from cloudg.scanners.prowler import ProwlerScanner
|
|
685
690
|
|
|
@@ -780,24 +785,36 @@ def run(
|
|
|
780
785
|
else:
|
|
781
786
|
console.print(" [dim]⊘ ScoutSuite: not enabled[/dim]")
|
|
782
787
|
|
|
783
|
-
# Checkov —
|
|
788
|
+
# Checkov — runs against resolved IaC directories
|
|
784
789
|
if "checkov" in scanner_list:
|
|
785
|
-
|
|
786
|
-
|
|
790
|
+
if resolved_iac_dirs:
|
|
791
|
+
for d in resolved_iac_dirs:
|
|
792
|
+
future_to_scanner[executor.submit(run_checkov, d)] = f"Checkov ({d})"
|
|
793
|
+
else:
|
|
794
|
+
console.print(
|
|
795
|
+
" [yellow]⊘ Checkov: nothing to scan — pass --iac-dir, set "
|
|
796
|
+
"scanners.iac_directories, or enable --terraform to scan the "
|
|
797
|
+
"recreated infrastructure[/yellow]"
|
|
798
|
+
)
|
|
787
799
|
else:
|
|
788
800
|
console.print(" [dim]⊘ Checkov: not enabled[/dim]")
|
|
789
801
|
|
|
790
|
-
# Trivy —
|
|
802
|
+
# Trivy — scans container images if configured, else the IaC targets
|
|
791
803
|
if "trivy" in scanner_list:
|
|
792
804
|
if resolved_images:
|
|
793
805
|
future_to_scanner[executor.submit(run_trivy, resolved_images)] = "Trivy (images)"
|
|
794
|
-
|
|
806
|
+
elif resolved_iac_dirs:
|
|
795
807
|
console.print(
|
|
796
808
|
" [yellow]⊘ Trivy: no images configured, falling back to filesystem scan[/yellow]"
|
|
797
809
|
)
|
|
798
810
|
future_to_scanner[executor.submit(run_trivy_fs, resolved_iac_dirs)] = (
|
|
799
811
|
"Trivy (filesystem)"
|
|
800
812
|
)
|
|
813
|
+
else:
|
|
814
|
+
console.print(
|
|
815
|
+
" [yellow]⊘ Trivy: nothing to scan — configure --images, "
|
|
816
|
+
"--iac-dir, or enable --terraform[/yellow]"
|
|
817
|
+
)
|
|
801
818
|
else:
|
|
802
819
|
console.print(" [dim]⊘ Trivy: not enabled[/dim]")
|
|
803
820
|
|
|
@@ -252,3 +252,43 @@ class TestIaCDirResolution:
|
|
|
252
252
|
resolved = ["."]
|
|
253
253
|
|
|
254
254
|
assert resolved == ["."]
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
class TestResolveIacDirs:
|
|
258
|
+
"""IaC target resolution: CLI dir -> config dirs -> terraform recreation, never '.'."""
|
|
259
|
+
|
|
260
|
+
def test_cli_dir_wins(self, tmp_path):
|
|
261
|
+
from cloudg.api import resolve_iac_dirs
|
|
262
|
+
|
|
263
|
+
dirs, source = resolve_iac_dirs("./infra", ["./other"], str(tmp_path))
|
|
264
|
+
assert dirs == ["./infra"]
|
|
265
|
+
assert source == "cli"
|
|
266
|
+
|
|
267
|
+
def test_config_dirs_used_when_no_cli_dir(self):
|
|
268
|
+
from cloudg.api import resolve_iac_dirs
|
|
269
|
+
|
|
270
|
+
dirs, source = resolve_iac_dirs(None, ["./a", "./b"], None)
|
|
271
|
+
assert dirs == ["./a", "./b"]
|
|
272
|
+
assert source == "config"
|
|
273
|
+
|
|
274
|
+
def test_terraform_recreation_used_as_fallback(self, tmp_path):
|
|
275
|
+
from cloudg.api import resolve_iac_dirs
|
|
276
|
+
|
|
277
|
+
(tmp_path / "main.tf.json").write_text("{}")
|
|
278
|
+
dirs, source = resolve_iac_dirs(None, [], tmp_path)
|
|
279
|
+
assert dirs == [str(tmp_path)]
|
|
280
|
+
assert source == "terraform"
|
|
281
|
+
|
|
282
|
+
def test_terraform_dir_without_tf_json_is_ignored(self, tmp_path):
|
|
283
|
+
from cloudg.api import resolve_iac_dirs
|
|
284
|
+
|
|
285
|
+
dirs, source = resolve_iac_dirs(None, [], tmp_path)
|
|
286
|
+
assert dirs == []
|
|
287
|
+
assert source is None
|
|
288
|
+
|
|
289
|
+
def test_no_targets_means_skip_not_cwd(self):
|
|
290
|
+
from cloudg.api import resolve_iac_dirs
|
|
291
|
+
|
|
292
|
+
dirs, source = resolve_iac_dirs(None, [], None)
|
|
293
|
+
assert dirs == []
|
|
294
|
+
assert source is None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|