cloudg 0.5.0__tar.gz → 0.5.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.
Files changed (235) hide show
  1. {cloudg-0.5.0 → cloudg-0.5.2}/PKG-INFO +206 -17
  2. {cloudg-0.5.0 → cloudg-0.5.2}/README.md +14 -7
  3. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/__init__.py +1 -1
  4. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/cli.py +4 -152
  5. cloudg-0.5.2/cloudg/cli_inventory.py +487 -0
  6. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/collectors/aws.py +25 -17
  7. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/collectors/aws_services.py +14 -6
  8. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/collectors/aws_services_extended.py +13 -7
  9. cloudg-0.5.2/cloudg/collectors/azure.py +400 -0
  10. cloudg-0.5.2/cloudg/collectors/gcp.py +554 -0
  11. cloudg-0.5.2/cloudg/collectors/gcp_assets.py +466 -0
  12. cloudg-0.5.2/cloudg/collectors/multi.py +507 -0
  13. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/config.py +124 -1
  14. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/graph/builder.py +5 -0
  15. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/graph/ontology.py +68 -0
  16. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/graph/ontology_rules.py +38 -3
  17. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/inventory/__init__.py +9 -2
  18. cloudg-0.5.2/cloudg/inventory/_util.py +29 -0
  19. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/inventory/aws_deep.py +222 -102
  20. cloudg-0.5.2/cloudg/inventory/aws_deep_tasks.py +180 -0
  21. cloudg-0.5.2/cloudg/inventory/aws_services/__init__.py +31 -0
  22. cloudg-0.5.2/cloudg/inventory/aws_services/_base.py +379 -0
  23. cloudg-0.5.2/cloudg/inventory/aws_services/_policy_grants.py +46 -0
  24. cloudg-0.5.2/cloudg/inventory/aws_services/application/__init__.py +103 -0
  25. cloudg-0.5.2/cloudg/inventory/aws_services/application/_common.py +255 -0
  26. cloudg-0.5.2/cloudg/inventory/aws_services/application/alarms.py +199 -0
  27. cloudg-0.5.2/cloudg/inventory/aws_services/application/backup.py +237 -0
  28. cloudg-0.5.2/cloudg/inventory/aws_services/application/batch.py +244 -0
  29. cloudg-0.5.2/cloudg/inventory/aws_services/application/build_deploy.py +367 -0
  30. cloudg-0.5.2/cloudg/inventory/aws_services/application/cicd.py +306 -0
  31. cloudg-0.5.2/cloudg/inventory/aws_services/application/compute.py +356 -0
  32. cloudg-0.5.2/cloudg/inventory/aws_services/application/containers_ext.py +252 -0
  33. cloudg-0.5.2/cloudg/inventory/aws_services/application/firehose.py +246 -0
  34. cloudg-0.5.2/cloudg/inventory/aws_services/application/integration.py +285 -0
  35. cloudg-0.5.2/cloudg/inventory/aws_services/application/logs.py +287 -0
  36. cloudg-0.5.2/cloudg/inventory/aws_services/application/operations.py +389 -0
  37. cloudg-0.5.2/cloudg/inventory/aws_services/application/serverless_ext.py +105 -0
  38. cloudg-0.5.2/cloudg/inventory/aws_services/cloudcontrol.py +295 -0
  39. cloudg-0.5.2/cloudg/inventory/aws_services/containers/__init__.py +38 -0
  40. cloudg-0.5.2/cloudg/inventory/aws_services/containers/ecr.py +134 -0
  41. cloudg-0.5.2/cloudg/inventory/aws_services/containers/ecs.py +280 -0
  42. cloudg-0.5.2/cloudg/inventory/aws_services/containers/eks.py +434 -0
  43. cloudg-0.5.2/cloudg/inventory/aws_services/data_ml/__init__.py +122 -0
  44. cloudg-0.5.2/cloudg/inventory/aws_services/data_ml/_common.py +235 -0
  45. cloudg-0.5.2/cloudg/inventory/aws_services/data_ml/analytics.py +217 -0
  46. cloudg-0.5.2/cloudg/inventory/aws_services/data_ml/bedrock.py +408 -0
  47. cloudg-0.5.2/cloudg/inventory/aws_services/data_ml/databases.py +241 -0
  48. cloudg-0.5.2/cloudg/inventory/aws_services/data_ml/glue.py +205 -0
  49. cloudg-0.5.2/cloudg/inventory/aws_services/data_ml/glue_etl.py +326 -0
  50. cloudg-0.5.2/cloudg/inventory/aws_services/data_ml/lakeformation.py +144 -0
  51. cloudg-0.5.2/cloudg/inventory/aws_services/data_ml/messaging.py +204 -0
  52. cloudg-0.5.2/cloudg/inventory/aws_services/data_ml/registry.py +34 -0
  53. cloudg-0.5.2/cloudg/inventory/aws_services/data_ml/sagemaker.py +282 -0
  54. cloudg-0.5.2/cloudg/inventory/aws_services/data_ml/serverless_data.py +315 -0
  55. cloudg-0.5.2/cloudg/inventory/aws_services/data_ml/transfer.py +427 -0
  56. cloudg-0.5.2/cloudg/inventory/aws_services/governance/__init__.py +150 -0
  57. cloudg-0.5.2/cloudg/inventory/aws_services/governance/_common.py +202 -0
  58. cloudg-0.5.2/cloudg/inventory/aws_services/governance/cognito.py +220 -0
  59. cloudg-0.5.2/cloudg/inventory/aws_services/governance/data_protection.py +408 -0
  60. cloudg-0.5.2/cloudg/inventory/aws_services/governance/iam_extras.py +187 -0
  61. cloudg-0.5.2/cloudg/inventory/aws_services/governance/identity_center.py +531 -0
  62. cloudg-0.5.2/cloudg/inventory/aws_services/governance/ram.py +154 -0
  63. cloudg-0.5.2/cloudg/inventory/aws_services/governance/s3_access_points.py +192 -0
  64. cloudg-0.5.2/cloudg/inventory/aws_services/governance/service_catalog.py +267 -0
  65. cloudg-0.5.2/cloudg/inventory/aws_services/governance/sharing.py +302 -0
  66. cloudg-0.5.2/cloudg/inventory/aws_services/governance/stack_sets.py +175 -0
  67. cloudg-0.5.2/cloudg/inventory/aws_services/identity.py +384 -0
  68. cloudg-0.5.2/cloudg/inventory/aws_services/network_ext/__init__.py +135 -0
  69. cloudg-0.5.2/cloudg/inventory/aws_services/network_ext/_common.py +182 -0
  70. cloudg-0.5.2/cloudg/inventory/aws_services/network_ext/apigateway.py +408 -0
  71. cloudg-0.5.2/cloudg/inventory/aws_services/network_ext/cloudfront.py +325 -0
  72. cloudg-0.5.2/cloudg/inventory/aws_services/network_ext/direct_connect.py +308 -0
  73. cloudg-0.5.2/cloudg/inventory/aws_services/network_ext/elb_rules.py +224 -0
  74. cloudg-0.5.2/cloudg/inventory/aws_services/network_ext/global_accelerator.py +126 -0
  75. cloudg-0.5.2/cloudg/inventory/aws_services/network_ext/lattice.py +218 -0
  76. cloudg-0.5.2/cloudg/inventory/aws_services/network_ext/network_manager.py +144 -0
  77. cloudg-0.5.2/cloudg/inventory/aws_services/network_ext/privatelink.py +226 -0
  78. cloudg-0.5.2/cloudg/inventory/aws_services/network_ext/resolver.py +268 -0
  79. cloudg-0.5.2/cloudg/inventory/aws_services/network_ext/tgw.py +228 -0
  80. cloudg-0.5.2/cloudg/inventory/aws_services/network_ext/vpn.py +184 -0
  81. cloudg-0.5.2/cloudg/inventory/aws_services/platform/__init__.py +57 -0
  82. cloudg-0.5.2/cloudg/inventory/aws_services/platform/compute_fabric.py +209 -0
  83. cloudg-0.5.2/cloudg/inventory/aws_services/platform/data.py +294 -0
  84. cloudg-0.5.2/cloudg/inventory/aws_services/platform/dns_iac_ops.py +285 -0
  85. cloudg-0.5.2/cloudg/inventory/aws_services/platform/load_balancing.py +181 -0
  86. cloudg-0.5.2/cloudg/inventory/aws_services/platform/storage.py +252 -0
  87. cloudg-0.5.2/cloudg/inventory/aws_services/security/__init__.py +60 -0
  88. cloudg-0.5.2/cloudg/inventory/aws_services/security/_common.py +71 -0
  89. cloudg-0.5.2/cloudg/inventory/aws_services/security/detection.py +266 -0
  90. cloudg-0.5.2/cloudg/inventory/aws_services/security/network_protection.py +185 -0
  91. cloudg-0.5.2/cloudg/inventory/aws_services/security/posture.py +200 -0
  92. cloudg-0.5.2/cloudg/inventory/aws_services/serverless/__init__.py +45 -0
  93. cloudg-0.5.2/cloudg/inventory/aws_services/serverless/apigateway.py +165 -0
  94. cloudg-0.5.2/cloudg/inventory/aws_services/serverless/functions.py +207 -0
  95. cloudg-0.5.2/cloudg/inventory/aws_services/serverless/messaging.py +293 -0
  96. cloudg-0.5.2/cloudg/inventory/azure_deep.py +229 -0
  97. cloudg-0.5.2/cloudg/inventory/azure_graph/__init__.py +163 -0
  98. cloudg-0.5.2/cloudg/inventory/azure_graph/arm_types.py +31 -0
  99. cloudg-0.5.2/cloudg/inventory/azure_graph/builder.py +483 -0
  100. cloudg-0.5.2/cloudg/inventory/azure_graph/compute.py +283 -0
  101. cloudg-0.5.2/cloudg/inventory/azure_graph/data_security.py +357 -0
  102. cloudg-0.5.2/cloudg/inventory/azure_graph/edge.py +254 -0
  103. cloudg-0.5.2/cloudg/inventory/azure_graph/helpers.py +316 -0
  104. cloudg-0.5.2/cloudg/inventory/azure_graph/network.py +396 -0
  105. cloudg-0.5.2/cloudg/inventory/azure_graph/query.py +161 -0
  106. cloudg-0.5.2/cloudg/inventory/azure_graph/registry.py +229 -0
  107. cloudg-0.5.2/cloudg/inventory/azure_graph/web_containers.py +253 -0
  108. cloudg-0.5.2/cloudg/inventory/azure_hierarchy.py +410 -0
  109. cloudg-0.5.2/cloudg/inventory/catalogs/__init__.py +79 -0
  110. cloudg-0.5.2/cloudg/inventory/catalogs/aws_arn_types.yaml +159 -0
  111. cloudg-0.5.2/cloudg/inventory/catalogs/aws_cloudcontrol.yaml +334 -0
  112. cloudg-0.5.2/cloudg/inventory/catalogs/azure_arm_types.yaml +133 -0
  113. cloudg-0.5.2/cloudg/inventory/catalogs/gcp_asset_types.yaml +157 -0
  114. cloudg-0.5.2/cloudg/inventory/dependencies.py +319 -0
  115. cloudg-0.5.2/cloudg/inventory/gcp_deep.py +81 -0
  116. cloudg-0.5.2/cloudg/inventory/gcp_hierarchy.py +272 -0
  117. cloudg-0.5.2/cloudg/inventory/gcp_relations/__init__.py +118 -0
  118. cloudg-0.5.2/cloudg/inventory/gcp_relations/compute.py +191 -0
  119. cloudg-0.5.2/cloudg/inventory/gcp_relations/context.py +152 -0
  120. cloudg-0.5.2/cloudg/inventory/gcp_relations/data_logging.py +258 -0
  121. cloudg-0.5.2/cloudg/inventory/gcp_relations/gke.py +211 -0
  122. cloudg-0.5.2/cloudg/inventory/gcp_relations/iam.py +473 -0
  123. cloudg-0.5.2/cloudg/inventory/gcp_relations/load_balancing.py +247 -0
  124. cloudg-0.5.2/cloudg/inventory/gcp_relations/messaging.py +99 -0
  125. cloudg-0.5.2/cloudg/inventory/gcp_relations/names.py +367 -0
  126. cloudg-0.5.2/cloudg/inventory/gcp_relations/network.py +415 -0
  127. cloudg-0.5.2/cloudg/inventory/gcp_relations/pipelines.py +166 -0
  128. cloudg-0.5.2/cloudg/inventory/gcp_relations/resource_manager.py +178 -0
  129. cloudg-0.5.2/cloudg/inventory/gcp_relations/serverless.py +434 -0
  130. cloudg-0.5.2/cloudg/inventory/kubernetes.py +434 -0
  131. cloudg-0.5.2/cloudg/inventory/linker.py +518 -0
  132. cloudg-0.5.2/cloudg/inventory/linker_index.py +265 -0
  133. cloudg-0.5.2/cloudg/inventory/mapper.py +592 -0
  134. cloudg-0.5.2/cloudg/inventory/mapper_result.py +282 -0
  135. cloudg-0.5.2/cloudg/inventory/organization.py +464 -0
  136. cloudg-0.5.2/cloudg/inventory/organization_assets.py +239 -0
  137. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/schema/models.py +155 -0
  138. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/ui.py +48 -0
  139. {cloudg-0.5.0 → cloudg-0.5.2}/docs/DOCUMENTATION.md +203 -16
  140. {cloudg-0.5.0 → cloudg-0.5.2}/pyproject.toml +2 -1
  141. {cloudg-0.5.0 → cloudg-0.5.2}/tests/conftest.py +36 -0
  142. cloudg-0.5.2/tests/test_aws_application.py +1450 -0
  143. cloudg-0.5.2/tests/test_aws_data_ml.py +1027 -0
  144. cloudg-0.5.2/tests/test_aws_governance.py +1131 -0
  145. cloudg-0.5.2/tests/test_aws_network_ext.py +1161 -0
  146. cloudg-0.5.2/tests/test_azure_inventory.py +1401 -0
  147. cloudg-0.5.2/tests/test_catalogs_cloudcontrol.py +280 -0
  148. cloudg-0.5.2/tests/test_gcp_inventory.py +1220 -0
  149. {cloudg-0.5.0 → cloudg-0.5.2}/tests/test_inventory.py +10 -2
  150. cloudg-0.5.2/tests/test_inventory_deep.py +1251 -0
  151. cloudg-0.5.0/cloudg/collectors/azure.py +0 -363
  152. cloudg-0.5.0/cloudg/collectors/gcp.py +0 -170
  153. cloudg-0.5.0/cloudg/collectors/multi.py +0 -340
  154. cloudg-0.5.0/cloudg/inventory/azure_deep.py +0 -336
  155. cloudg-0.5.0/cloudg/inventory/gcp_deep.py +0 -97
  156. cloudg-0.5.0/cloudg/inventory/linker.py +0 -345
  157. cloudg-0.5.0/cloudg/inventory/mapper.py +0 -334
  158. {cloudg-0.5.0 → cloudg-0.5.2}/.gitignore +0 -0
  159. {cloudg-0.5.0 → cloudg-0.5.2}/LICENSE +0 -0
  160. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/api.py +0 -0
  161. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/cli_commands.py +0 -0
  162. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/cli_helpers.py +0 -0
  163. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/cli_run_helpers.py +0 -0
  164. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/collectors/__init__.py +0 -0
  165. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/collectors/base.py +0 -0
  166. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/coverage.py +0 -0
  167. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/credentials.py +0 -0
  168. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/graph/__init__.py +0 -0
  169. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/graph/rag_export.py +0 -0
  170. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/graph/reachability.py +0 -0
  171. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/ingest.py +0 -0
  172. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/normaliser.py +0 -0
  173. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/policies/custodian-aws-security.yml +0 -0
  174. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/policies/custodian-azure.yml +0 -0
  175. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/policies/custodian-gcp.yml +0 -0
  176. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/policies/custodian.yml +0 -0
  177. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/region_discovery.py +0 -0
  178. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/registry.py +0 -0
  179. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/renderers/__init__.py +0 -0
  180. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/renderers/html_report.py +0 -0
  181. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/renderers/json_export.py +0 -0
  182. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/renderers/svg.py +0 -0
  183. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/renderers/svg_layout.py +0 -0
  184. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/renderers/terraform_export.py +0 -0
  185. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/retry.py +0 -0
  186. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/check_equivalence.yaml +0 -0
  187. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/cis_aws_v3.yaml +0 -0
  188. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/cis_azure_v2.yaml +0 -0
  189. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/cis_gcp_v3.yaml +0 -0
  190. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/aws_foundational_security_best_practices_aws.yaml +0 -0
  191. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/cis_5.0_aws.yaml +0 -0
  192. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/cis_5.0_azure.yaml +0 -0
  193. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/cis_5.0_gcp.yaml +0 -0
  194. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/gdpr_aws.yaml +0 -0
  195. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/hipaa_aws.yaml +0 -0
  196. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/hipaa_azure.yaml +0 -0
  197. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/hipaa_gcp.yaml +0 -0
  198. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/iso27001_2022_aws.yaml +0 -0
  199. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/iso27001_2022_azure.yaml +0 -0
  200. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/iso27001_2022_gcp.yaml +0 -0
  201. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/mitre_attack_aws.yaml +0 -0
  202. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/mitre_attack_azure.yaml +0 -0
  203. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/mitre_attack_gcp.yaml +0 -0
  204. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/nist_800_53_revision_5_aws.yaml +0 -0
  205. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/nist_csf_2.0_aws.yaml +0 -0
  206. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/pci_4.0_aws.yaml +0 -0
  207. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/pci_4.0_azure.yaml +0 -0
  208. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/pci_4.0_gcp.yaml +0 -0
  209. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/soc2_aws.yaml +0 -0
  210. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/soc2_azure.yaml +0 -0
  211. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/frameworks/soc2_gcp.yaml +0 -0
  212. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/gdpr.yaml +0 -0
  213. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/hipaa_security_rule.yaml +0 -0
  214. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/iso_27001_2022.yaml +0 -0
  215. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/nist_800_53.yaml +0 -0
  216. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/pci_dss_v4.yaml +0 -0
  217. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/rules/soc2_tsc.yaml +0 -0
  218. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/scanners/__init__.py +0 -0
  219. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/scanners/checkov.py +0 -0
  220. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/scanners/iam_linter.py +0 -0
  221. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/scanners/prowler.py +0 -0
  222. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/scanners/scoutsuite.py +0 -0
  223. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/scanners/trivy.py +0 -0
  224. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/schema/__init__.py +0 -0
  225. {cloudg-0.5.0 → cloudg-0.5.2}/cloudg/templates/report.html.j2 +0 -0
  226. {cloudg-0.5.0 → cloudg-0.5.2}/tests/__init__.py +0 -0
  227. {cloudg-0.5.0 → cloudg-0.5.2}/tests/test_api.py +0 -0
  228. {cloudg-0.5.0 → cloudg-0.5.2}/tests/test_collectors.py +0 -0
  229. {cloudg-0.5.0 → cloudg-0.5.2}/tests/test_ingest.py +0 -0
  230. {cloudg-0.5.0 → cloudg-0.5.2}/tests/test_normaliser.py +0 -0
  231. {cloudg-0.5.0 → cloudg-0.5.2}/tests/test_ontology.py +0 -0
  232. {cloudg-0.5.0 → cloudg-0.5.2}/tests/test_rag_export.py +0 -0
  233. {cloudg-0.5.0 → cloudg-0.5.2}/tests/test_region_discovery.py +0 -0
  234. {cloudg-0.5.0 → cloudg-0.5.2}/tests/test_scanner_orchestration.py +0 -0
  235. {cloudg-0.5.0 → cloudg-0.5.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.5.0
3
+ Version: 0.5.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
@@ -38,6 +38,7 @@ Requires-Dist: azure-mgmt-compute>=30.0; extra == 'all'
38
38
  Requires-Dist: azure-mgmt-keyvault>=10.0; extra == 'all'
39
39
  Requires-Dist: azure-mgmt-network>=25.0; extra == 'all'
40
40
  Requires-Dist: azure-mgmt-resource>=23.0; extra == 'all'
41
+ Requires-Dist: azure-mgmt-resourcegraph>=8.0.0; extra == 'all'
41
42
  Requires-Dist: azure-mgmt-sql>=3.0; extra == 'all'
42
43
  Requires-Dist: azure-mgmt-storage>=21.0; extra == 'all'
43
44
  Requires-Dist: boto3>=1.28; extra == 'all'
@@ -52,6 +53,7 @@ Requires-Dist: azure-mgmt-compute>=30.0; extra == 'azure'
52
53
  Requires-Dist: azure-mgmt-keyvault>=10.0; extra == 'azure'
53
54
  Requires-Dist: azure-mgmt-network>=25.0; extra == 'azure'
54
55
  Requires-Dist: azure-mgmt-resource>=23.0; extra == 'azure'
56
+ Requires-Dist: azure-mgmt-resourcegraph>=8.0.0; extra == 'azure'
55
57
  Requires-Dist: azure-mgmt-sql>=3.0; extra == 'azure'
56
58
  Requires-Dist: azure-mgmt-storage>=21.0; extra == 'azure'
57
59
  Provides-Extra: dev
@@ -80,6 +82,12 @@ cloudg (cloud graphing) maps AWS, Azure and GCP infrastructure into a graph, run
80
82
 
81
83
  This is the complete reference: every CLI command, the exact input and output formats, the data models, the full Python API with integration examples, configuration, plugins and authentication. Release history lives in the [changelog](https://github.com/morpheuslord/cloudg/blob/main/CHANGELOG.md).
82
84
 
85
+ The inventory mapper (`cloudg map`, `cloudg deps`, `cloudg.inventory`) has three deeper companion documents:
86
+
87
+ - [Inventory reference](INVENTORY_REFERENCE.md): the structure of every return value and exported file, field by field, with annotated examples (`CloudAsset`, `NetworkEdge`, relation objects, `InventoryResult`, `summary`, coverage records, dependency trees, blast radius, security coverage, `inventory-map.json`, `inventory-graph.json`, GraphML, `inventory-organization.json`, `asset-map.json`, `compliance-map.json`, `cloudg deps --json`).
88
+ - [Inventory catalog](INVENTORY_CATALOG.md): all 156 asset types with the native resource types mapped to each, the metadata keys and relations each one carries, and the full relationship matrix.
89
+ - [Inventory internals](INVENTORY_INTERNALS.md): how a mapping run works, every module, the 133 AWS collector tasks, the linker's resolution rules, the Azure and GCP extractor frameworks, dependency semantics, catalogs, and recipes for adding collectors, extractors and asset types.
90
+
83
91
  Contents:
84
92
 
85
93
  - [Installation](#installation)
@@ -177,12 +185,15 @@ cloudg collect -p gcp --project-id <id>
177
185
 
178
186
  ### cloudg map
179
187
 
180
- Scanner-independent inventory mapping: everything deployed or default, linked into one map. No scanner runs and none needs to be installed.
188
+ Scanner-independent inventory mapping: everything deployed or default, linked into one map of typed interdependencies. No scanner runs and none needs to be installed.
181
189
 
182
190
  ```bash
183
191
  cloudg map -p aws --regions all
184
192
  cloudg map -p all --regions all
185
- cloudg map -p aws --findings ./reports/raw-findings.json # merge scanner output
193
+ cloudg map -p aws --org --regions all # every account in the Organization / Control Tower
194
+ cloudg map -p aws --org --ou Workloads --exclude-account 111122223333
195
+ cloudg map -p aws --services containers,serverless,security # narrow the run
196
+ cloudg map -p aws --findings ./reports/raw-findings.json # merge scanner output
186
197
  ```
187
198
 
188
199
  | Flag | Meaning |
@@ -190,18 +201,93 @@ cloudg map -p aws --findings ./reports/raw-findings.json # merge scanner outpu
190
201
  | `-p, --provider` | `aws`, `azure`, `gcp` or `all`; repeatable |
191
202
  | `--regions` | `all` for auto-discovery, or a comma-separated list |
192
203
  | `--profile` | AWS CLI profile |
204
+ | `--accounts`, `--role-name` | AWS: explicit account list and the role to assume in each |
205
+ | `--org / --no-org` | AWS: discover and map every account of the Organization (run from the management account or a delegated administrator) |
206
+ | `--org-role` | AWS: role assumed in member accounts; defaults to `AWSControlTowerExecution` |
207
+ | `--ou` | AWS: only accounts under this OU (ID, ARN or name, nested OUs included); repeatable |
208
+ | `--exclude-account` | AWS: skip an account; repeatable |
209
+ | `--ct-home-region` | AWS: Control Tower home region, auto-detected when omitted |
210
+ | `--services`, `--exclude-services` | service families or collector names, comma-separated (see below) |
211
+ | `--kubernetes / --no-kubernetes` | map workloads inside EKS clusters through the Kubernetes API |
212
+ | `--cloud-control / --no-cloud-control` | AWS Cloud Control breadth sweep, on by default |
193
213
  | `--subscription-id`, `--project-id` | Azure / GCP identity |
194
214
  | `--findings` | existing cloudg findings JSON (`raw-findings.json` or a report); repeatable |
195
215
  | `--sweep / --no-sweep` | catch-all sweep, on by default |
196
216
  | `-o, --output` | output directory |
197
217
 
198
- Coverage comes in three layers:
218
+ Coverage comes in four layers.
219
+
220
+ 1. Dedicated deep collectors. On AWS, 133 collectors grouped into service families you can select with `--services` / `--exclude-services` (family or collector names):
221
+
222
+ | Family | Collected |
223
+ |---|---|
224
+ | `network` | VPCs, subnets, security groups, route tables, internet / NAT / egress-only gateways, ENIs, Elastic IPs, NACLs, VPC peering, transit gateways, attachments, route tables and peering, VPC endpoints and endpoint services (PrivateLink, allowed principals, consumers), managed prefix lists, ALB/NLB listeners, rules, certificates and target groups, classic ELB, CloudFront (origins, aliases, certificates, Lambda@Edge, functions, OAC, logging), Global Accelerator, VPC Lattice |
225
+ | `hybrid` | site-to-site VPN, customer and virtual private gateways, Direct Connect connections, VIFs and gateways, Cloud WAN / Network Manager |
226
+ | `compute` | EC2, Auto Scaling groups, launch templates, AMIs (with sharing), Batch, App Runner, Elastic Beanstalk |
227
+ | `containers` | ECR (+ public), ECS clusters, services, task definitions, capacity providers, container instances, Cloud Map, EKS clusters, nodegroups, Fargate profiles, addons, access entries, pod identity |
228
+ | `kubernetes` | inside EKS clusters: namespaces, Deployments, StatefulSets, DaemonSets, CronJobs, Services, Ingresses, ServiceAccounts |
229
+ | `serverless` | Lambda (triggers, URLs, images, layers, DLQs, aliases), API Gateway REST / HTTP APIs, authorizers, VPC links and custom domains, Step Functions |
230
+ | `integration` | SQS, SNS, EventBridge buses, rules, archives, API destinations, Scheduler, Pipes, Kinesis, Firehose, MSK, Amazon MQ |
231
+ | `storage` | S3 (notifications, replication, logging, account and bucket Block Public Access), access points and multi-region access points, EBS volumes and snapshots, EFS, FSx, Transfer Family, DataSync |
232
+ | `data` | RDS, Aurora, proxies, global clusters, manual snapshot sharing, DynamoDB (KMS, streams, replicas, PITR, policies), ElastiCache, MemoryDB, DAX, OpenSearch (+ Serverless), Redshift (+ Serverless) |
233
+ | `analytics`, `ml` | Glue, Lake Formation permissions, EMR (+ Serverless), Athena; SageMaker, Bedrock agents, knowledge bases, guardrails and invocation logging |
234
+ | `identity` | the IAM graph (users, groups, roles, trust, grants, instance profiles, OIDC and SAML providers, access key metadata), IAM Identity Center (instances, permission sets, assignments, users, groups), Roles Anywhere, Cognito user and identity pools, KMS (aliases, rotation, key policy and grant principals), Secrets Manager, ACM |
235
+ | `governance` | RAM resource shares, Service Catalog portfolios and provisioned products (Account Factory), CloudFormation StackSets |
236
+ | `security` | GuardDuty, Security Hub, Inspector (per-resource coverage), Macie, AWS Config, IAM Access Analyzer, Detective, WAF, Network Firewall, Shield Advanced |
237
+ | `logging`, `operations`, `backup` | CloudTrail, flow logs, log groups, subscription filters and destinations, cross-account observability (OAM); CloudWatch alarms, SSM parameters (metadata only), managed instances, documents, associations, maintenance windows; AWS Backup plans, selections and vaults |
238
+ | `dns`, `iac`, `cicd` | Route 53 zones and records, Resolver endpoints, rules and DNS Firewall; CloudFormation stacks and the resources they manage; CodePipeline, CodeBuild, CodeDeploy, CodeConnections |
239
+
240
+ Account-wide services are collected once per account, in the primary region, so `--regions all` does not repeat them. Security services that are not enabled appear as placeholder nodes with `enabled: false`, so detection gaps show on the map. Values that could be secret (parameter values, environment variables, passwords, VPN pre-shared keys, Direct Connect auth keys) are never collected.
199
241
 
200
- 1. Dedicated deep collectors. Everything the standard collectors know, plus the network fabric: route tables, internet and NAT gateways, network interfaces, EBS volumes and managed disks, Elastic and public IPs, NACLs, VPC peering connections, transit gateways, and customer-managed IAM policies (AWS); NICs, public IPs, disks, load balancers and route tables (Azure).
201
- 2. Catch-all sweeps. The AWS Resource Groups Tagging API, Azure Resource Manager's full `resources.list()`, and GCP Cloud Asset Inventory each enumerate every resource in scope, so services without a dedicated collector still appear on the map (classified by ARN/ARM/asset type, or `OTHER`). A sweep hit that duplicates a dedicated collector's asset is dropped; the richer asset wins.
202
- 3. The relationship linker. A post-collection pass that derives edges purely from asset metadata: instance → security group (`ATTACHED_TO`), subnet ⊃ resource (`CONTAINS`), route table → gateway (`ROUTE`), Lambda → execution role, secret → KMS key, CloudFront → origin (`REFERENCES`), VPC peering (`PEERING`), Azure VM → NIC → NSG/subnet/public IP chains, GCP parent containment and IAM policy bindings, and finally a generic pass that resolves any ARN, Azure resource ID or GCP resource name found in one asset's metadata to another collected asset.
242
+ Azure is collected through Azure Resource Graph (`azure-mgmt-resourcegraph`, in the `azure` extra) with every resource's full properties, so PaaS services get real relationships: managed identities and role assignments (principal → scope, with role names), private endpoints, AKS node pools, kubelet identity and ACR pulls, App Service plans, VNet integration and container images, Container Apps, subnets, peering, NICs, disks and disk encryption sets, firewalls and route-table next hops, Application Gateway and Front Door backends and WAF policies, Key Vault access policies, storage and SQL network rules, Defender for Cloud plans per subscription. Every Enabled subscription is collected when none are configured (`azure.all_subscriptions`), and the management group → subscription → resource group hierarchy, Azure Landing Zone archetypes and Azure Policy assignments and exemptions are mapped (`azure.map_management_groups`). Without the Resource Graph SDK, cloudg falls back to the per-service SDK collectors plus the ARM sweep. Permissions: Reader at the tenant root management group (Resource Graph scopes to what the credential can read).
203
243
 
204
- Outputs: `inventory-map.json` (assets, edges, and a summary covering services, types, regions, accounts, internet exposure and unlinked assets), `inventory-map.graphml`, `inventory-graph.json` (D3). With `--findings`, additionally `asset-map.json` (per-asset finding counts and severity breakdowns, riskiest first) and `compliance-map.json` (framework → findings and affected assets). The map does not depend on the scanners; findings from any earlier run merge in whenever they exist.
244
+ GCP is collected through Cloud Asset Inventory `list_assets` with the full resource JSON, once at `organizations/<organization_id>` when that is set (`gcp.collection_scope`), otherwise per project. Relations cover instances (service accounts, subnets, disks, external IPs), firewall semantics (target tags and service accounts, source ranges, priorities), the load-balancing chain down to NEGs and Cloud Armor, managed instance groups and templates, GKE clusters and node pools with Workload Identity, Cloud Run and Functions v2 (service accounts, images in Artifact Registry, secrets, VPC connectors, triggers), Pub/Sub (subscriptions, push endpoints, dead-letter and export targets), Eventarc, logging sinks, CMEK keys, Shared VPC, Cloud SQL / Redis / Filestore networks and DNS zones. IAM bindings resolve to service accounts or to principal nodes (users, groups, workload identity pools); only `allUsers` / `allAuthenticatedUsers` mark a resource internet-exposed. With an organization ID, the organization → folder → project tree, organization policies and VPC Service Controls perimeters are mapped too (`gcp.map_hierarchy`, `org_policies`, `vpc_service_controls`). Permissions: `roles/cloudasset.viewer` on the organization (or each project) and the Cloud Asset API enabled on the quota project.
245
+ 2. Breadth sweeps, so services without a dedicated collector still appear on the map.
246
+ - AWS Cloud Control API: every CloudFormation resource type with a list handler (800+ types) is listed, tagged or not. Types already mapped by a deep collector are skipped, account-wide types run once per account, types that need a parent identifier or fail are skipped and counted in coverage (`cloud_control_skipped_types`). The listable-type catalogue is discovered once and cached for a week (`$CLOUDG_CACHE_DIR`, default `~/.cache/cloudg`). Secret-bearing properties (passwords, tokens, SSM parameter values, environment variables, user data) are never copied. Turn it off with `--no-cloud-control`, or narrow it with `inventory.cloud_control_types` / `cloud_control_exclude` (type names or prefixes such as `AWS::Glue::`).
247
+ - AWS Resource Groups Tagging API: tagged resources only (AWS never returns resources that were never tagged), kept for tag enrichment.
248
+ - Azure Resource Manager's full `resources.list()` and GCP Cloud Asset Inventory enumerate their scopes.
249
+
250
+ Precedence when the same resource is found twice: dedicated collector, then Cloud Control, then the tagging API.
251
+ 3. The relationship linker. Collectors declare what each asset talks to; the linker resolves those identifiers across services, regions and accounts into typed edges, then applies provider rules and a generic reference pass. See [Relationships](#relationships) below.
252
+ 4. Account hierarchy. Every account gets a `CLOUD_ACCOUNT` node that contains its top-level resources. With `--org`, accounts hang under the OU tree, next to SCPs, the Control Tower landing zone and its enabled controls.
253
+
254
+ Outputs: `inventory-map.json` (assets, edges, unresolved references, and a summary covering services, types, regions, accounts, relationship counts, cross-account edges, external accounts, security service gaps, internet exposure and unlinked assets), `inventory-map.graphml`, `inventory-graph.json` (D3, with account and relationship attributes), `inventory-dependencies.json` (most shared dependencies, largest blast radius, cross-account edges, security coverage including workloads no vulnerability scanner covers and internet-facing endpoints without a WAF), and with `--org` `inventory-organization.json`. With `--findings`, additionally `asset-map.json` (per-asset finding counts and severity breakdowns, riskiest first) and `compliance-map.json` (framework → findings and affected assets). The map does not depend on the scanners; findings from any earlier run merge in whenever they exist.
255
+
256
+ #### Relationships
257
+
258
+ Every edge has a coarse `edge_type` and, when known, a fine-grained `relationship` (an ontology relation name) plus `properties`. Direction always reads "source verb target".
259
+
260
+ | Edge type | Example |
261
+ |---|---|
262
+ | `INVOKES` | S3 bucket → Lambda (notification), SQS → Lambda (`TRIGGERED_BY`, event source mapping), SNS → SQS (`STREAMS_TO`), EventBridge rule → target, API Gateway → Lambda, Step Functions → anything its definition calls |
263
+ | `USES_IMAGE` | task definition / Kubernetes workload / Lambda → ECR repository |
264
+ | `ASSUMES_ROLE` | Lambda, task definition, nodegroup, Kubernetes service account (IRSA or Pod Identity), instance profile → IAM role |
265
+ | `IAM_TRUST` | principal / external account / OIDC provider → role it may assume (`CROSS_ACCOUNT_TRUST` across accounts) |
266
+ | `GRANTS_ACCESS` | principal → resource its policy names; principal → EKS cluster (access entry, with access policies); bucket / queue / repository policy grants |
267
+ | `IAM_POLICY_ATTACHMENT` | user, group or role → managed policy |
268
+ | `PROTECTS` | WAF → ALB / API Gateway / CloudFront, Network Firewall → VPC, Shield → resource |
269
+ | `MONITORS` | Inspector → each scanned EC2 / ECR / Lambda, GuardDuty / Config / CloudTrail / Macie → account, Security Hub → the services it ingests from, flow log → VPC/subnet/ENI |
270
+ | `MANAGES` | CloudFormation stack → resource, ASG → instance, nodegroup → ASG, landing zone → OUs and shared accounts |
271
+ | `GOVERNS` | SCP / RCP / tag policy and Control Tower control or baseline → OU or account |
272
+ | `LOGS_TO` | trail, flow log, load balancer, API stage, task definition, function → log destination |
273
+ | `LOAD_BALANCER_TARGET` | load balancer → target group → instance / IP / Lambda, Kubernetes Service → workload |
274
+ | `ROUTE` | route table → gateway, DNS record → load balancer / distribution, transit gateway → attached VPC, Ingress → Service |
275
+ | `CONTAINS`, `ATTACHED_TO`, `PEERING`, `REFERENCES` | containment, security-group attachment, VPC peering, everything else (KMS keys, secrets, DLQs, layers, ...) |
276
+
277
+ Identifier resolution is scoped: an ambiguous name such as `default` resolves within the referencing asset's account and region, and is left unresolved rather than guessed when it could belong to several accounts. References into accounts that were not mapped become `CLOUD_ACCOUNT` nodes with `external: true`, so a role trusted by a vendor account or a bucket replicating to another account stays visible. References that resolve to nothing (a deleted queue still configured as a DLQ) are listed under `unresolved_references`.
278
+
279
+ ### cloudg deps
280
+
281
+ Interdependency queries over a saved map; no cloud access needed.
282
+
283
+ ```bash
284
+ cloudg deps arn:aws:iam::123456789012:role/app-role # both directions
285
+ cloudg deps jobs-queue --direction down --depth 5 # blast radius
286
+ cloudg deps --map ./reports # overview
287
+ cloudg deps my-function --direction up --json # machine-readable
288
+ ```
289
+
290
+ Each edge is read as "dependent needs dependency": a function needs its role, image, key and the queue that triggers it; an ALB needs the WAF protecting it; a resource needs the stack managing it. `--direction up` shows what an asset needs, `down` what needs it (what breaks or changes with it), `both` the two trees. Without an asset, `deps` prints the most shared dependencies (one KMS key behind forty resources), the largest blast radius, and every cross-account edge. Assets are matched by ARN or resource ID, internal ID, or a unique name.
205
291
 
206
292
  ### cloudg scan
207
293
 
@@ -318,8 +404,12 @@ All commands write into the output directory (`./reports` by default).
318
404
  | `rag_chunks.jsonl`, `rag_metadata_index.json` | retrieval-ready chunks, one JSON object per line |
319
405
  | `terraform/*.tf.json`, `terraform/import.sh` | Terraform recreation of live infrastructure, 25+ asset types |
320
406
  | `inventory-map.json`, `inventory-map.graphml`, `inventory-graph.json` | scanner-independent inventory map: assets, interconnections, summary (`cloudg map`) |
407
+ | `inventory-dependencies.json` | shared dependencies, blast radius, cross-account edges, security service coverage (`cloudg map`) |
408
+ | `inventory-organization.json` | AWS Organization / Control Tower topology (`cloudg map --org`) |
321
409
  | `asset-map.json`, `compliance-map.json` | inventory overlaid with scanner findings (`cloudg map --findings`) |
322
410
 
411
+ The inventory files are specified field by field in the [inventory reference](INVENTORY_REFERENCE.md).
412
+
323
413
  `findings.json` has this shape:
324
414
 
325
415
  ```json
@@ -381,17 +471,44 @@ The unit every scanner and parser produces.
381
471
  | `id` | `str` | auto UUID |
382
472
  | `arn` | `str \| None` | native identifier |
383
473
  | `name` | `str` | |
384
- | `asset_type` | `AssetType` | 45-value taxonomy: `EC2`, `S3_BUCKET`, `IAM_ROLE`, `VPC`, `KMS_KEY`, ... |
474
+ | `asset_type` | `AssetType` | 156-value taxonomy covering compute, networking, storage, databases, IAM and identity federation, keys and secrets, logging, containers and Kubernetes, integration, data and ML platforms, DNS and deployment, security services and scanners, organization and governance, hybrid networking, `OTHER`; the full list with what maps to each is in the [inventory catalog](INVENTORY_CATALOG.md#asset-types-by-category) |
385
475
  | `provider` | `CloudProvider` | `AWS`, `AZURE`, `GCP` |
386
476
  | `region` | `str` | `"global"` for regionless resources |
387
477
  | `account_id` | `str \| None` | |
388
478
  | `tags` | `dict[str, str]` | |
389
- | `metadata` | `dict[str, Any]` | normalised extra attributes |
390
- | `is_internet_exposed` | `bool` | set by the graph analysis |
479
+ | `metadata` | `dict[str, Any]` | normalised extra attributes; inventory assets also carry declared `relations` and identifier `aliases` |
480
+ | `collected_at` | `datetime` | when the asset was built |
481
+ | `is_internet_exposed` | `bool` | set by the collector or the graph analysis |
482
+ | `raw_data` | `dict[str, Any]` | raw API payload, never serialised |
483
+ | `display_id` | computed `str` | `arn` or `id` |
484
+
485
+ `id` is regenerated on every run; correlate assets across runs by `arn`.
391
486
 
392
487
  ### NetworkEdge
393
488
 
394
- Directed edge between two asset IDs. `edge_type` is one of `SECURITY_GROUP_RULE`, `NACL_RULE`, `ROUTE`, `IAM_TRUST`, `IAM_POLICY_ATTACHMENT`, `CONTAINS`, `PEERING`, `LOAD_BALANCER_TARGET`, `INTERNET_EXPOSED`, `ATTACHED_TO`, `REFERENCES`; the model also carries `ports`, `port_range`, `protocol`, `cidr` and `direction`. `ATTACHED_TO` and `REFERENCES` are produced by the inventory relationship linker (attachment and generic cross-service dependency respectively).
489
+ Directed edge between two asset IDs (`source_id`, `target_id`); direction always reads "source verb target".
490
+
491
+ | Field | Type | Notes |
492
+ |---|---|---|
493
+ | `id` | `str` | auto UUID |
494
+ | `source_id`, `target_id` | `str` | asset IDs; network rule edges can use a CIDR or native security group ID as an endpoint |
495
+ | `edge_type` | `EdgeType` | coarse class, below |
496
+ | `relationship` | `str \| None` | fine-grained ontology relation (`TRIGGERED_BY`, `RUNS_ON`, `CROSS_ACCOUNT_TRUST`, `ENCRYPTED_BY_KMS`, ...) |
497
+ | `properties` | `dict[str, Any]` | relation detail: trust conditions, granted actions, EKS access policies, notification events, `cross_account`, `external_reference`, `hierarchy` |
498
+ | `description` | `str \| None` | human-readable explanation |
499
+ | `ports`, `port_range`, `protocol`, `cidr`, `direction` | | network rule edges |
500
+
501
+ `edge_type` values:
502
+
503
+ | Group | Values |
504
+ |---|---|
505
+ | Network | `SECURITY_GROUP_RULE`, `NACL_RULE`, `ROUTE`, `PEERING`, `LOAD_BALANCER_TARGET`, `INTERNET_EXPOSED` |
506
+ | Structure | `CONTAINS`, `ATTACHED_TO`, `REFERENCES` |
507
+ | Identity | `IAM_TRUST`, `IAM_POLICY_ATTACHMENT`, `ASSUMES_ROLE`, `GRANTS_ACCESS` |
508
+ | Workload | `INVOKES`, `USES_IMAGE`, `LOGS_TO` |
509
+ | Security and governance | `PROTECTS`, `MONITORS`, `MANAGES`, `GOVERNS` |
510
+
511
+ What each one means, its typical endpoints and how it counts for dependency analysis is in the [inventory reference](INVENTORY_REFERENCE.md#6-edge-types-and-direction); every observed source type → relationship → target type combination is in the [relationship matrix](INVENTORY_CATALOG.md#relationship-matrix).
395
512
 
396
513
  ### ComplianceResult
397
514
 
@@ -418,6 +535,17 @@ aws:
418
535
  profile: null
419
536
  max_retries: 10
420
537
  retry_mode: adaptive
538
+ organization: # AWS Organizations / Control Tower (cloudg map)
539
+ enabled: false
540
+ role_name: null # default AWSControlTowerExecution
541
+ include_ous: [] # IDs, ARNs or names; nested OUs included
542
+ exclude_accounts: []
543
+ include_management_account: true
544
+ include_suspended: false
545
+ use_governed_regions: true # regions [all] -> Control Tower governed regions
546
+ control_tower: true
547
+ home_region: null # auto-detected
548
+ map_structure: true # org, OU, account, SCP, control nodes
421
549
 
422
550
  azure:
423
551
  subscription_ids: []
@@ -427,10 +555,19 @@ azure:
427
555
  certificate_path: null
428
556
  federated_token_file: null
429
557
  use_managed_identity: false
558
+ all_subscriptions: true # every Enabled subscription when subscription_ids is empty
559
+ map_management_groups: true # management groups, subscriptions, Azure Policy
430
560
  regions: [ALL]
431
561
 
432
562
  gcp:
433
563
  project_ids: []
564
+ organization_id: null # set to collect org-wide and map folders / org policy
565
+ collection_scope: auto # auto | organization | project
566
+ skip_asset_types: [...] # high-churn types (Pods, ReplicaSets, Events, ...) by default
567
+ iam_policies: true
568
+ map_hierarchy: true
569
+ org_policies: true
570
+ vpc_service_controls: true
434
571
  credentials_file: null
435
572
  impersonate_service_account: null
436
573
  regions: [ALL]
@@ -446,6 +583,18 @@ scanners:
446
583
  inventory:
447
584
  tagging_sweep: true # AWS catch-all sweep (Resource Groups Tagging API)
448
585
  link_references: true # generic cross-service REFERENCES edges
586
+ services: [all] # families or collector names (see cloudg map)
587
+ exclude_services: []
588
+ kubernetes: true # workloads inside EKS clusters
589
+ kubernetes_timeout: 10
590
+ iam_resource_edges: true # principal -> granted resource edges
591
+ max_images_per_repository: 20
592
+ stack_resources: true # CloudFormation stack -> resource edges
593
+ account_hierarchy: true # account nodes containing top-level resources
594
+ cloud_control: true # AWS breadth sweep over every listable resource type
595
+ cloud_control_types: [] # only these CloudFormation types / prefixes
596
+ cloud_control_exclude: []
597
+ cloud_control_concurrency: 6
449
598
 
450
599
  graph:
451
600
  persist_graphml: true
@@ -550,7 +699,32 @@ print(inventory.summary) # services, types, regions, exposur
550
699
  inventory.export("./reports") # inventory-map.json / .graphml / graph
551
700
  ```
552
701
 
553
- `InventoryResult` carries `assets`, `edges`, `coverage`, `providers`, `regions` and a computed `summary` (totals, per-service/type/region/account breakdowns, edge types, internet-exposed and unlinked counts). `export(dir)` writes `inventory-map.json`, `inventory-map.graphml` and `inventory-graph.json`.
702
+ `InventoryResult` carries `assets`, `edges`, `coverage`, `providers`, `regions`, `organization` (the discovered topology, when mapped) and `unresolved_references`, plus a computed `summary` (totals, per-service/type/region/account breakdowns, edge types and relationships, cross-account edges, external accounts, security service gaps, internet-exposed and unlinked counts). `export(dir)` writes `inventory-map.json`, `inventory-map.graphml`, `inventory-graph.json`, `inventory-dependencies.json` and, for an organization, `inventory-organization.json`; `InventoryResult.load(dir_or_file)` reads a map back.
703
+
704
+ Interdependency questions go through `DependencyGraph`:
705
+
706
+ ```python
707
+ graph = inventory.dependency_graph()
708
+ role = graph.find("arn:aws:iam::123456789012:role/app-role")
709
+ needs = graph.depends_on(role.id) # upstream, breadth-first
710
+ needed_by = graph.dependents(role.id) # downstream: blast radius
711
+ view = graph.tree(role.id, direction="both", max_depth=3)
712
+ graph.shared_dependencies(top=25)
713
+ graph.blast_radius(top=25)
714
+ inventory.analysis() # everything above + coverage
715
+ ```
716
+
717
+ Organizations and Control Tower discovery is usable on its own:
718
+
719
+ ```python
720
+ import boto3
721
+ from cloudg.inventory import discover_organization
722
+
723
+ topology = discover_organization(boto3.Session())
724
+ topology.governed_regions, topology.shared_accounts # Control Tower
725
+ topology.target_accounts(include_ous=["Workloads"]) # nested OUs included
726
+ assets = topology.to_assets() # org, OUs, accounts, SCPs, controls
727
+ ```
554
728
 
555
729
  Merging scanner findings (from `scan()`, `ingest_reports()`, or a saved `raw-findings.json`) happens after the fact, so the mapper never touches the scanners:
556
730
 
@@ -565,10 +739,18 @@ mapper.export_merged(inventory, findings, "./reports") # asset-map.json
565
739
  ```python
566
740
  linker = RelationshipLinker(assets)
567
741
  linker.seed_existing(existing_edges) # don't duplicate edges you already have
568
- edges = linker.link() # ATTACHED_TO / CONTAINS / ROUTE / PEERING / REFERENCES
742
+ edges = linker.link() # typed edges, see Relationships
743
+ linker.external_assets # placeholder nodes for unmapped accounts
744
+ linker.unresolved # declared references that resolved to nothing
569
745
  ```
570
746
 
571
- The deep collectors are public too, when you want single-region, single-account control: `AWSDeepInventoryCollector(session, region, account_id, tagging_sweep=True)`, `AzureDeepInventoryCollector(credential, subscription_id)` and `GCPDeepInventoryCollector(project_id, credentials)` all implement the standard `collect()` / `collect_edges()` / `run()` collector interface.
747
+ Reference data lives in YAML catalogs under `cloudg/inventory/catalogs/` rather than in code: `aws_cloudcontrol.yaml` (types the deep collectors already cover, account-wide types, CloudFormation type → asset type, per-type secret fields), `aws_arn_types.yaml` (ARN → asset type for sweep hits), `azure_arm_types.yaml` (ARM resource type → asset type) and `gcp_asset_types.yaml` (Cloud Asset Inventory type → asset type). Point `$CLOUDG_CATALOG_DIR` at a directory holding files of the same names to extend or override them without touching cloudg: mappings merge key by key, lists are extended. Unknown asset type names are rejected at load time.
748
+
749
+ Your own collectors can declare relationships the same way the built-in ones do, by listing them in `metadata["relations"]`: `{"target": <any identifier>, "edge": "INVOKES", "relationship": "TRIGGERED_BY", "reverse": false}`.
750
+
751
+ The deep collectors are public too, when you want single-region, single-account control: `AWSDeepInventoryCollector(session, region="us-east-1", account_id=None, tagging_sweep=True, **options)` (keyword options `is_primary_region`, `services`, `exclude_services`, `kubernetes`, `kubernetes_timeout`, `iam_resource_edges`, `max_images_per_repository`, `stack_resources`, `cloud_control`, `cloud_control_types`, `cloud_control_exclude`, `cloud_control_concurrency`; an unknown option raises `TypeError`), `AzureDeepInventoryCollector(credential, subscription_id, graph_client_factory=None, use_resource_graph=True)` and `GCPDeepInventoryCollector(project_id, credentials=None, **options)` (keyword options `organization_id`, `scope`, `project_filter`, `skip_asset_types`, `page_size`, `include_iam`, `client`, `coverage`, `timeout`, `link_locally`) all implement the standard `collect()` / `collect_edges()` / `run()` collector interface. Their assets carry declared relations; pass them through `RelationshipLinker` for the typed edges.
752
+
753
+ Every structure above, from `summary` to the dependency tree, is specified field by field in the [inventory reference](INVENTORY_REFERENCE.md).
572
754
 
573
755
  ### The deeper toolkit
574
756
 
@@ -584,6 +766,11 @@ Modules the pipeline uses internally that are equally useful standalone:
584
766
  | `cloudg.normaliser` | `FindingsNormaliser` | the full dedupe / cross-scanner merge / CVSS rescore / compliance mapping pass, on any `list[Finding]` |
585
767
  | `cloudg.ingest` | `parse_report`, `ingest_reports` | every scanner's parser, standalone; no engine, no credentials |
586
768
  | `cloudg.coverage` | `CollectionCoverage` | per-service success/failure/asset-count records every collector produces |
769
+ | `cloudg.inventory.dependencies` | `DependencyGraph`, `cross_account_edges`, `security_coverage` | dependency walks, shared dependencies, blast radius, cross-account edges and security service coverage over any assets and edges |
770
+ | `cloudg.inventory.linker` | `RelationshipLinker` | resolve declared relations and identifiers across services, regions and accounts into typed edges |
771
+ | `cloudg.inventory.organization` | `discover_organization`, `OrganizationTopology` | AWS Organizations and Control Tower discovery, account selection, map nodes |
772
+ | `cloudg.inventory.kubernetes` | `collect_eks_workloads`, `KubernetesReader` | read-only Kubernetes object mapping for EKS clusters |
773
+ | `cloudg.inventory.catalogs` | `load_catalog`, `asset_type_map` | the YAML reference catalogs with `$CLOUDG_CATALOG_DIR` overlays |
587
774
  | `cloudg.registry` | `PluginRegistry` | entry-point discovery of collector and scanner plugins |
588
775
 
589
776
  ### PipelineResult
@@ -795,13 +982,15 @@ myscanner = "my_package.scanner:MyScanner"
795
982
  mycloud = "my_package.collector:MyCollector"
796
983
  ```
797
984
 
798
- After `pip install`, the name is available in `scanners.enabled` and `--scanners`. Collectors follow the base interface in `cloudg/collectors/base.py`. If your scanner emits a stable check ID in `source_finding_id`, you can add it to `rules/check_equivalence.yaml` so its findings merge with equivalent checks from other tools.
985
+ After `pip install`, the name is available in `scanners.enabled` and `--scanners`. Collectors follow the base interface in `cloudg/collectors/base.py`. A collector plugin's assets join the inventory map like the built-in ones: declare what each asset talks to in `metadata["relations"]` and extra identifiers in `metadata["aliases"]`, and the relationship linker resolves them (see [Inventory internals](INVENTORY_INTERNALS.md#156-declare-relations-from-your-own-collector-or-plugin)). If your scanner emits a stable check ID in `source_finding_id`, you can add it to `rules/check_equivalence.yaml` so its findings merge with equivalent checks from other tools.
799
986
 
800
987
  ## Authentication
801
988
 
802
989
  Every provider supports several methods, resolved in a fixed priority order, so the same config works on a laptop, in CI and on cloud compute.
803
990
 
804
- AWS, in priority order: direct keys (`--aws-key`, `--aws-secret`, `--aws-session-token` or the standard env vars); OIDC web identity federation (`--aws-role-arn` with `--aws-web-identity-token-file`, the GitHub Actions, GitLab CI and EKS pattern with no long-lived keys); a named CLI profile via `--profile`, SSO included; or nothing, letting the default chain pick up env vars, cached SSO or the instance role. On top of any of these, STS role assumption with `--aws-role-arn` and, for the third-party auditor pattern, `--aws-external-id`. Multi-account fan-out uses `accounts` plus `role_name` in the config, assuming that role in each account before collecting.
991
+ AWS, in priority order: direct keys (`--aws-key`, `--aws-secret`, `--aws-session-token` or the standard env vars); OIDC web identity federation (`--aws-role-arn` with `--aws-web-identity-token-file`, the GitHub Actions, GitLab CI and EKS pattern with no long-lived keys); a named CLI profile via `--profile`, SSO included; or nothing, letting the default chain pick up env vars, cached SSO or the instance role. On top of any of these, STS role assumption with `--aws-role-arn` and, for the third-party auditor pattern, `--aws-external-id`. Multi-account fan-out uses `accounts` plus `role_name` in the config, assuming that role in each account before collecting; the caller's own account is collected with the base credentials.
992
+
993
+ AWS Organizations and Control Tower: run `cloudg map --org` with credentials for the management account (Organizations APIs also work from a delegated administrator; the Control Tower APIs need the management account). cloudg lists the org read-only (`organizations:Describe*`/`List*`, `controltower:List*`/`Get*`) and then assumes the member role in each selected account. `AWSControlTowerExecution` exists in every account Control Tower enrolled, but it carries administrator permissions; the `aws-controltower-ReadOnlyExecutionRole` cannot be used directly because it only trusts a Lambda-only role in the audit account. For production, deploy a dedicated read-only role (for example `cloudg-readonly` with the `SecurityAudit` and `ViewOnlyAccess` managed policies, trusting the management account) to all accounts with a service-managed CloudFormation StackSet targeting your OUs, and pass it with `--org-role cloudg-readonly`. Mapping Kubernetes workloads additionally needs an EKS access entry for that role with `AmazonEKSViewPolicy`.
805
994
 
806
995
  Azure, in priority order: workload identity federation (`--azure-tenant-id`, `--azure-client-id`, `--azure-federated-token-file`); a service principal with a client secret (`--azure-client-secret`) or a certificate (`--azure-cert-path`); managed identity (`--azure-managed-identity`, with `managed_identity_client_id` in config for user-assigned identities); or the `DefaultAzureCredential` chain, which covers `az login`.
807
996
 
@@ -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.5.0-4c1.svg" alt="Version 0.5.0">
8
+ <img src="https://img.shields.io/badge/version-0.5.2-4c1.svg" alt="Version 0.5.2">
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
 
@@ -20,7 +20,7 @@ One command collects assets from every configured provider in parallel, feeds th
20
20
 
21
21
  Need the map without the security tooling? `cloudg map` is a scanner-independent inventory mapper: it deep-collects everything deployed (or default) in an account, down to the network fabric, sweeps every service for the rest, and links it all into one asset map you can overlay with scanner findings later. See [Inventory mapping](#inventory-mapping).
22
22
 
23
- **Full documentation:** the rendered handbook lives at [morpheuslord.github.io/cloudg](https://morpheuslord.github.io/cloudg/), with the same content as markdown in the [feature reference](https://github.com/morpheuslord/cloudg/blob/main/docs/DOCUMENTATION.md) and release notes in the [changelog](https://github.com/morpheuslord/cloudg/blob/main/CHANGELOG.md).
23
+ **Full documentation:** the rendered handbook lives at [morpheuslord.github.io/cloudg](https://morpheuslord.github.io/cloudg/), with the same content as markdown in the [feature reference](https://github.com/morpheuslord/cloudg/blob/main/docs/DOCUMENTATION.md) and release notes in the [changelog](https://github.com/morpheuslord/cloudg/blob/main/CHANGELOG.md). The inventory mapper has its own deep-dive documents: the [inventory reference](https://github.com/morpheuslord/cloudg/blob/main/docs/INVENTORY_REFERENCE.md) (every return structure and output file, field by field), the [inventory catalog](https://github.com/morpheuslord/cloudg/blob/main/docs/INVENTORY_CATALOG.md) (all 156 asset types, their metadata and relationships) and the [inventory internals](https://github.com/morpheuslord/cloudg/blob/main/docs/INVENTORY_INTERNALS.md) (how it works and how to extend it).
24
24
 
25
25
  ---
26
26
 
@@ -77,24 +77,31 @@ docker compose run --rm cloudg run -p aws --regions us-east-1
77
77
 
78
78
  ## Inventory mapping
79
79
 
80
- `cloudg map` answers a different question than `cloudg run`: what exists, and how is it wired together. Finding out what is wrong stays the scanners' job, and none of them runs here or even needs to be installed. Three things make the map complete:
80
+ `cloudg map` answers a different question than `cloudg run`: what exists, and how is it wired together. Finding out what is wrong stays the scanners' job, and none of them runs here or even needs to be installed. What makes the map complete:
81
81
 
82
- - Catch-all enumeration per provider. Beyond the dedicated collectors, the AWS Resource Groups Tagging API, Azure Resource Manager's full subscription listing, and GCP Cloud Asset Inventory each list every resource in scope, so a service without a hand-written collector still lands on the map instead of silently missing.
83
- - The network fabric: route tables, internet and NAT gateways, network interfaces, volumes, Elastic and public IPs, NACLs, VPC peering, transit gateways. These are the pieces that turn a resource list into a topology.
84
- - A relationship linker that walks every asset's metadata and derives attachment, containment, routing and reference edges: instance → security group, subnet ⊃ database, route table → gateway, Lambda → IAM role, secret → KMS key, CloudFront → origin bucket, VM → NIC → NSG, plus a generic pass that resolves any ARN or resource-ID reference between collected assets.
82
+ - Deep service collectors. Containers (ECR repositories, ECS services and task definitions, EKS clusters, nodegroups, Fargate profiles, addons, access entries) and the Kubernetes workloads running inside EKS; Lambda with its triggers, function URLs, images and layers; API Gateway, SQS, SNS, EventBridge, Step Functions, Kinesis; data stores; Route 53; CloudFormation stacks and the resources they manage; the whole IAM graph; and the security services and scanners watching the account (GuardDuty, Security Hub, Inspector, Macie, Config, Access Analyzer, WAF, Network Firewall, Shield, CloudTrail), including where they are not enabled.
83
+ - Breadth across every service. On AWS, a Cloud Control API sweep lists every resource type that supports listing (800+), tagged or not, next to 133 dedicated collectors. Azure is read through Azure Resource Graph across every subscription and management group, GCP through Cloud Asset Inventory across the whole organization, both with full resource properties.
84
+ - Every account at once. `--org` discovers the AWS Organization from the management account (OU tree, accounts, SCPs, and the Control Tower landing zone with its governed regions and enabled controls) and maps every member account.
85
+ - Typed interdependencies. Edges say what they mean: S3 `INVOKES` Lambda, task definition `USES_IMAGE` ECR repository, function `ASSUMES_ROLE` role, WAF `PROTECTS` ALB, Inspector `MONITORS` instance, stack `MANAGES` resource, SCP `GOVERNS` OU, plus cross-account trust to accounts you did not map. `cloudg deps` then answers "what does this need" and "what breaks if it goes".
85
86
 
86
87
  ```bash
87
88
  # map one provider
88
89
  cloudg map -p aws --regions all
89
90
 
91
+ # every account in the AWS Organization / Control Tower landing zone
92
+ cloudg map -p aws --org --regions all
93
+
90
94
  # map everything, everywhere
91
95
  cloudg map -p all --regions all
92
96
 
97
+ # what depends on this role, and what does it depend on?
98
+ cloudg deps arn:aws:iam::123456789012:role/app-role
99
+
93
100
  # overlay scanner findings you generated earlier -> asset map + compliance map
94
101
  cloudg map -p aws --regions all --findings ./reports/raw-findings.json
95
102
  ```
96
103
 
97
- Outputs: `inventory-map.json` (assets, interconnections, summary), `inventory-map.graphml`, and `inventory-graph.json` for viewers. With `--findings`, additionally `asset-map.json` (each asset with its findings and severity breakdown) and `compliance-map.json` (framework → affected assets). The map never depends on the scanners; you can map today and merge in findings from a scan you run next week.
104
+ Outputs: `inventory-map.json` (assets, interconnections, summary), `inventory-map.graphml`, `inventory-graph.json` for viewers, `inventory-dependencies.json` (shared dependencies, blast radius, cross-account edges, security coverage gaps) and, with `--org`, `inventory-organization.json`. With `--findings`, additionally `asset-map.json` (each asset with its findings and severity breakdown) and `compliance-map.json` (framework → affected assets). The map never depends on the scanners; you can map today and merge in findings from a scan you run next week. Every file is specified field by field, with annotated examples, in the [inventory reference](https://github.com/morpheuslord/cloudg/blob/main/docs/INVENTORY_REFERENCE.md).
98
105
 
99
106
  All of this is also a library API, see [Using it as a library](#using-it-as-a-library):
100
107
 
@@ -1,6 +1,6 @@
1
1
  """cloudg — cloud graphing: multi-cloud mapping and security intelligence."""
2
2
 
3
- __version__ = "0.5.0"
3
+ __version__ = "0.5.2"
4
4
 
5
5
  from cloudg.api import (
6
6
  AnalysisResult,
@@ -21,10 +21,10 @@ from cloudg.cli_helpers import (
21
21
  _build_scan_jobs,
22
22
  _gather_ingest_reports,
23
23
  _parse_ingest_reports,
24
- _parse_region_flag,
25
24
  _render_ingest_reports,
26
25
  _run_scan_jobs,
27
26
  )
27
+ from cloudg.cli_inventory import deps, map_inventory
28
28
  from cloudg.ui import console
29
29
 
30
30
  # Global config reference (set by CLI group)
@@ -169,157 +169,6 @@ def collect(
169
169
  ui.artifact("Inventory", inventory_path)
170
170
 
171
171
 
172
- # ─────────────────────────────────────────────────────────────────────
173
- # MAP command (scanner-independent inventory mapping)
174
- # ─────────────────────────────────────────────────────────────────────
175
-
176
-
177
- @cli.command(name="map")
178
- @click.option(
179
- "-p",
180
- "--provider",
181
- type=click.Choice(["aws", "azure", "gcp", "all"], case_sensitive=False),
182
- multiple=True,
183
- default=("aws",),
184
- show_default=True,
185
- help="Provider(s) to map. Use multiple times or 'all'.",
186
- )
187
- @click.option("--profile", default=None, help="AWS profile name")
188
- @click.option(
189
- "--regions",
190
- "scan_regions",
191
- default=None,
192
- help="Regions: 'all' for auto-discovery, or comma-separated list",
193
- )
194
- @click.option("--subscription-id", default=None, help="Azure subscription ID")
195
- @click.option("--project-id", default=None, help="GCP project ID")
196
- @click.option(
197
- "--findings",
198
- "findings_paths",
199
- multiple=True,
200
- help="Existing cloudg findings JSON (raw-findings.json or a cloudg report) "
201
- "to merge into asset/compliance maps. Repeatable.",
202
- )
203
- @click.option(
204
- "--sweep/--no-sweep",
205
- default=True,
206
- show_default=True,
207
- help="Catch-all sweep (AWS Resource Groups Tagging API) for resources "
208
- "without a dedicated collector",
209
- )
210
- @click.option("-o", "--output", default="./reports", help="Output directory")
211
- def map_inventory(
212
- provider: tuple[str, ...],
213
- profile: str | None,
214
- scan_regions: str | None,
215
- subscription_id: str | None,
216
- project_id: str | None,
217
- findings_paths: tuple[str, ...],
218
- sweep: bool,
219
- output: str,
220
- ) -> None:
221
- """Map the complete infrastructure inventory — no scanners involved.
222
-
223
- Deep-collects everything deployed (or default) across the configured
224
- providers, including the network fabric (route tables, gateways, ENIs,
225
- volumes, peering) and a catch-all sweep so services without a dedicated
226
- collector still appear. Every asset is then linked into an
227
- interconnected map: attachment, containment, routing, and
228
- cross-service references.
229
-
230
- Optionally merge previously generated scanner findings to produce an
231
- asset map and a compliance map:
232
-
233
- cloudg map -p aws --regions all --findings ./reports/raw-findings.json
234
- """
235
- ui.section("Inventory Mapping")
236
-
237
- from cloudg.config import CloudGConfig
238
- from cloudg.inventory import InventoryMapper
239
-
240
- cfg: CloudGConfig = _config or CloudGConfig()
241
-
242
- providers_list = list(provider)
243
- if "all" in providers_list:
244
- providers_list = ["aws", "azure", "gcp"]
245
- cfg.providers = providers_list
246
-
247
- if scan_regions:
248
- region_list = _parse_region_flag(scan_regions)
249
- cfg.aws.regions = region_list
250
- cfg.azure.regions = region_list
251
- cfg.gcp.regions = region_list
252
- if profile:
253
- cfg.aws.profile = profile
254
- if subscription_id:
255
- cfg.azure.subscription_ids = [subscription_id]
256
- if project_id:
257
- cfg.gcp.project_ids = [project_id]
258
-
259
- ui.config_panel(
260
- "Map Configuration",
261
- {
262
- "Providers": ", ".join(cfg.providers),
263
- "AWS regions": ", ".join(cfg.aws.regions),
264
- "Catch-all sweep": "enabled" if sweep else "disabled",
265
- "Scanners": "none (inventory mapping is scanner-independent)",
266
- },
267
- )
268
-
269
- mapper = InventoryMapper(cfg, tagging_sweep=sweep)
270
-
271
- try:
272
- with console.status("[accent]Mapping infrastructure inventory…[/]", spinner="dots"):
273
- result = mapper.map_inventory_sync()
274
- except Exception as exc:
275
- ui.error_panel("Inventory mapping failed", exc)
276
- sys.exit(1)
277
-
278
- output_dir = Path(output)
279
- paths = result.export(output_dir)
280
-
281
- summary = result.summary
282
- ui.stats_table(
283
- "Inventory Summary",
284
- {
285
- "Assets": summary["total_assets"],
286
- "Interconnections": summary["total_edges"],
287
- "Services": len(summary["assets_by_service"]),
288
- "Internet-exposed": summary["internet_exposed"],
289
- "Unlinked assets": summary["unlinked_assets"],
290
- },
291
- )
292
- for svc, count in list(summary["assets_by_service"].items())[:15]:
293
- ui.detail(f"{svc}: {count} assets")
294
-
295
- ui.artifact("Inventory map", paths["map"])
296
- ui.artifact("GraphML", paths["graphml"])
297
- ui.artifact("Graph JSON", paths["graph"])
298
-
299
- # Optional merge with existing scanner findings
300
- if findings_paths:
301
- from cloudg.schema.models import Finding
302
-
303
- findings: list[Any] = []
304
- for fpath in findings_paths:
305
- try:
306
- with open(fpath) as f:
307
- data = json.load(f)
308
- raw = data if isinstance(data, list) else data.get("findings", [])
309
- findings.extend(Finding.model_validate(item) for item in raw)
310
- except (OSError, ValueError) as exc:
311
- ui.warn(f"Skipping findings file {fpath}: {exc}")
312
-
313
- if findings:
314
- merged_paths = mapper.export_merged(result, findings, output_dir)
315
- ui.success(f"Merged [metric]{len(findings)}[/] findings into the inventory")
316
- ui.artifact("Asset map", merged_paths["asset_map"])
317
- ui.artifact("Compliance map", merged_paths["compliance_map"])
318
-
319
- console.print()
320
- ui.success(f"Inventory map saved to [path]{output_dir}[/]")
321
-
322
-
323
172
  # ─────────────────────────────────────────────────────────────────────
324
173
  # SCAN command
325
174
  # ─────────────────────────────────────────────────────────────────────
@@ -565,9 +414,12 @@ def ingest(
565
414
 
566
415
  # ─────────────────────────────────────────────────────────────────────
567
416
  # RUN command (full pipeline) — defined in cloudg.cli_commands
417
+ # MAP / DEPS commands (inventory mapping) — defined in cloudg.cli_inventory
568
418
  # ─────────────────────────────────────────────────────────────────────
569
419
 
570
420
  cli.add_command(run)
421
+ cli.add_command(map_inventory)
422
+ cli.add_command(deps)
571
423
 
572
424
 
573
425
  if __name__ == "__main__":