cloudwright-ai 0.3.2__tar.gz → 0.3.4__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 (203) hide show
  1. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/PKG-INFO +1 -1
  2. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/__init__.py +1 -1
  3. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/cost.py +206 -10
  4. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/importer/__init__.py +23 -2
  5. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/importer/cloudformation.py +40 -0
  6. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/importer/terraform_state.py +77 -1
  7. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_cfn_importer.py +2 -2
  8. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/.gitignore +0 -0
  9. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/README.md +0 -0
  10. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/adapters/__init__.py +0 -0
  11. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/adapters/aws.py +0 -0
  12. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/adapters/azure.py +0 -0
  13. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/adapters/databricks.py +0 -0
  14. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/adapters/gcp.py +0 -0
  15. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/analyzer.py +0 -0
  16. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/architect.py +0 -0
  17. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/ascii_diagram.py +0 -0
  18. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/catalog/__init__.py +0 -0
  19. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/catalog/formula.py +0 -0
  20. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/catalog/refresh.py +0 -0
  21. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/catalog/store.py +0 -0
  22. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/catalog.db +0 -0
  23. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/_generate_icons.py +0 -0
  24. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/alb.svg +0 -0
  25. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/api_gateway.svg +0 -0
  26. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/cloudfront.svg +0 -0
  27. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/cloudtrail.svg +0 -0
  28. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/cloudwatch.svg +0 -0
  29. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/cognito.svg +0 -0
  30. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/dynamodb.svg +0 -0
  31. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/ebs.svg +0 -0
  32. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/ec2.svg +0 -0
  33. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/ecr.svg +0 -0
  34. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/ecs.svg +0 -0
  35. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/eks.svg +0 -0
  36. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/elasticache.svg +0 -0
  37. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/emr.svg +0 -0
  38. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/glue.svg +0 -0
  39. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/guardduty.svg +0 -0
  40. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/kinesis.svg +0 -0
  41. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/kms.svg +0 -0
  42. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/lambda.svg +0 -0
  43. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/nlb.svg +0 -0
  44. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/rds.svg +0 -0
  45. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/redshift.svg +0 -0
  46. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/route53.svg +0 -0
  47. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/s3.svg +0 -0
  48. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/sagemaker.svg +0 -0
  49. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/sns.svg +0 -0
  50. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/sqs.svg +0 -0
  51. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/step_functions.svg +0 -0
  52. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/aws/waf.svg +0 -0
  53. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/azure/aks.svg +0 -0
  54. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/azure/app_gateway.svg +0 -0
  55. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/azure/azure_cache.svg +0 -0
  56. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/azure/azure_functions.svg +0 -0
  57. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/azure/azure_sql.svg +0 -0
  58. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/azure/blob_storage.svg +0 -0
  59. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/azure/cosmos_db.svg +0 -0
  60. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/azure/service_bus.svg +0 -0
  61. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/azure/virtual_machines.svg +0 -0
  62. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/gcp/bigquery.svg +0 -0
  63. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/gcp/cloud_cdn.svg +0 -0
  64. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/gcp/cloud_functions.svg +0 -0
  65. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/gcp/cloud_load_balancing.svg +0 -0
  66. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/gcp/cloud_run.svg +0 -0
  67. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/gcp/cloud_sql.svg +0 -0
  68. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/gcp/cloud_storage.svg +0 -0
  69. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/gcp/compute_engine.svg +0 -0
  70. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/gcp/gke.svg +0 -0
  71. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/gcp/memorystore.svg +0 -0
  72. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/gcp/pub_sub.svg +0 -0
  73. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/generic/cache.svg +0 -0
  74. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/generic/cdn.svg +0 -0
  75. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/generic/compute.svg +0 -0
  76. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/generic/database.svg +0 -0
  77. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/generic/firewall.svg +0 -0
  78. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/generic/internet.svg +0 -0
  79. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/generic/load_balancer.svg +0 -0
  80. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/generic/queue.svg +0 -0
  81. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/generic/storage.svg +0 -0
  82. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/icons/generic/user.svg +0 -0
  83. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/registry/analytics.yaml +0 -0
  84. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/registry/cache.yaml +0 -0
  85. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/registry/compute.yaml +0 -0
  86. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/registry/containers.yaml +0 -0
  87. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/registry/database_nosql.yaml +0 -0
  88. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/registry/database_relational.yaml +0 -0
  89. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/registry/messaging.yaml +0 -0
  90. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/registry/ml.yaml +0 -0
  91. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/registry/networking_api.yaml +0 -0
  92. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/registry/networking_cdn.yaml +0 -0
  93. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/registry/networking_dns.yaml +0 -0
  94. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/registry/networking_lb.yaml +0 -0
  95. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/registry/orchestration.yaml +0 -0
  96. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/registry/security_auth.yaml +0 -0
  97. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/registry/security_waf.yaml +0 -0
  98. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/registry/serverless.yaml +0 -0
  99. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/registry/storage_block.yaml +0 -0
  100. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/registry/storage_object.yaml +0 -0
  101. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/registry/streaming.yaml +0 -0
  102. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/templates/_index.yaml +0 -0
  103. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/templates/azure-microservices.yaml +0 -0
  104. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/templates/azure-serverless-api.yaml +0 -0
  105. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/templates/azure-three-tier-web.yaml +0 -0
  106. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/templates/batch-processing.yaml +0 -0
  107. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/templates/data-lake.yaml +0 -0
  108. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/templates/databricks-lakehouse.yaml +0 -0
  109. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/templates/databricks-ml-platform.yaml +0 -0
  110. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/templates/event-driven.yaml +0 -0
  111. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/templates/gcp-microservices.yaml +0 -0
  112. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/templates/gcp-serverless-api.yaml +0 -0
  113. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/templates/gcp-three-tier-web.yaml +0 -0
  114. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/templates/microservices.yaml +0 -0
  115. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/templates/ml_pipeline.yaml +0 -0
  116. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/templates/serverless_api.yaml +0 -0
  117. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/templates/static-site.yaml +0 -0
  118. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/data/templates/three_tier_web.yaml +0 -0
  119. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/differ.py +0 -0
  120. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/drift.py +0 -0
  121. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/evolution.py +0 -0
  122. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/exporter/__init__.py +0 -0
  123. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/exporter/aibom.py +0 -0
  124. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/exporter/ascii.py +0 -0
  125. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/exporter/c4.py +0 -0
  126. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/exporter/cloudformation.py +0 -0
  127. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/exporter/compliance_report.py +0 -0
  128. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/exporter/d2.py +0 -0
  129. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/exporter/diff_diagram.py +0 -0
  130. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/exporter/mermaid.py +0 -0
  131. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/exporter/presentation.py +0 -0
  132. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/exporter/renderer.py +0 -0
  133. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/exporter/sbom.py +0 -0
  134. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/exporter/terraform.py +0 -0
  135. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/icons.py +0 -0
  136. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/importer/utils.py +0 -0
  137. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/layout.py +0 -0
  138. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/linter.py +0 -0
  139. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/llm/__init__.py +0 -0
  140. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/llm/anthropic.py +0 -0
  141. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/llm/base.py +0 -0
  142. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/llm/openai.py +0 -0
  143. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/plugins.py +0 -0
  144. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/policy.py +0 -0
  145. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/providers/__init__.py +0 -0
  146. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/providers/aws.py +0 -0
  147. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/providers/azure.py +0 -0
  148. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/providers/databricks.py +0 -0
  149. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/providers/gcp.py +0 -0
  150. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/py.typed +0 -0
  151. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/registry.py +0 -0
  152. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/scorer.py +0 -0
  153. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/security.py +0 -0
  154. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/spec.py +0 -0
  155. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/templates.py +0 -0
  156. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/cloudwright/validator.py +0 -0
  157. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/pyproject.toml +0 -0
  158. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/conftest.py +0 -0
  159. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/fixtures/aws.tfstate +0 -0
  160. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/fixtures/aws_serverless.tfstate +0 -0
  161. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/fixtures/azure.tfstate +0 -0
  162. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/fixtures/cloudformation_template.json +0 -0
  163. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/fixtures/gcp.tfstate +0 -0
  164. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/fixtures/serverless_api.json +0 -0
  165. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/fixtures/three_tier.yaml +0 -0
  166. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_adapter_aws.py +0 -0
  167. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_adapter_azure.py +0 -0
  168. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_adapter_databricks.py +0 -0
  169. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_adapter_gcp.py +0 -0
  170. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_adr.py +0 -0
  171. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_analyzer.py +0 -0
  172. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_architect.py +0 -0
  173. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_architect_chat.py +0 -0
  174. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_ascii_diagram.py +0 -0
  175. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_c4_exporter.py +0 -0
  176. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_catalog.py +0 -0
  177. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_constraint_propagation.py +0 -0
  178. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_cost.py +0 -0
  179. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_databricks.py +0 -0
  180. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_diff_viz.py +0 -0
  181. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_differ.py +0 -0
  182. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_drift.py +0 -0
  183. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_e2e.py +0 -0
  184. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_evolution.py +0 -0
  185. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_exporter.py +0 -0
  186. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_formula.py +0 -0
  187. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_icons.py +0 -0
  188. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_importer.py +0 -0
  189. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_importer_cfn.py +0 -0
  190. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_layout_engine.py +0 -0
  191. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_linter.py +0 -0
  192. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_packaging.py +0 -0
  193. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_plugins.py +0 -0
  194. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_policy.py +0 -0
  195. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_presentation.py +0 -0
  196. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_refresh.py +0 -0
  197. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_registry.py +0 -0
  198. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_renderer.py +0 -0
  199. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_scorer.py +0 -0
  200. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_security.py +0 -0
  201. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_spec.py +0 -0
  202. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_validator.py +0 -0
  203. {cloudwright_ai-0.3.2 → cloudwright_ai-0.3.4}/tests/test_validator_fedramp_gdpr.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cloudwright-ai
3
- Version: 0.3.2
3
+ Version: 0.3.4
4
4
  Summary: Architecture intelligence for cloud engineers — design, cost, compare, export
5
5
  Project-URL: Homepage, https://github.com/xmpuspus/cloudwright
6
6
  Project-URL: Repository, https://github.com/xmpuspus/cloudwright
@@ -17,7 +17,7 @@ from cloudwright.spec import (
17
17
  ValidationResult,
18
18
  )
19
19
 
20
- __version__ = "0.3.2"
20
+ __version__ = "0.3.4"
21
21
 
22
22
  __all__ = [
23
23
  "Alternative",
@@ -4,6 +4,7 @@ from __future__ import annotations
4
4
 
5
5
  import logging
6
6
  from datetime import date
7
+ from typing import Any
7
8
 
8
9
  from cloudwright.catalog import _PRICING_MULTIPLIERS, Catalog
9
10
  from cloudwright.catalog.formula import PRICING_FORMULAS, default_managed_price
@@ -40,20 +41,202 @@ _SERVICE_EGRESS_OVERRIDES = {
40
41
  }
41
42
  _DEFAULT_EGRESS_RATE = 0.09
42
43
 
44
+ # ---------------------------------------------------------------------------
45
+ # Workload profiles — realistic sizing defaults per environment tier
46
+ # ---------------------------------------------------------------------------
47
+
48
+ # Config overrides applied to components when a workload profile is active.
49
+ # Only fills in missing config keys; never overwrites explicit values.
50
+ _PROFILE_DEFAULTS: dict[str, dict[str, dict[str, Any]]] = {
51
+ "small": {
52
+ # Serverless
53
+ "lambda": {"monthly_requests": 5_000_000, "avg_duration_ms": 300, "memory_mb": 512},
54
+ "cloud_functions": {"monthly_requests": 5_000_000, "avg_duration_ms": 300, "memory_mb": 512},
55
+ "azure_functions": {"monthly_requests": 5_000_000, "avg_duration_ms": 300, "memory_mb": 512},
56
+ # Databases
57
+ "rds": {"storage_gb": 50},
58
+ "aurora": {"storage_gb": 50},
59
+ "cloud_sql": {"storage_gb": 50},
60
+ "azure_sql": {"storage_gb": 50},
61
+ "dynamodb": {"monthly_requests": 5_000_000},
62
+ # Storage
63
+ "s3": {"storage_gb": 100},
64
+ "cloud_storage": {"storage_gb": 100},
65
+ "blob_storage": {"storage_gb": 100},
66
+ # CDN
67
+ "cloudfront": {"estimated_gb": 200},
68
+ "cloud_cdn": {"estimated_gb": 200},
69
+ "azure_cdn": {"estimated_gb": 200},
70
+ # Analytics
71
+ "bigquery": {"monthly_query_tb": 2, "storage_gb": 200},
72
+ "redshift": {"num_nodes": 2, "storage_gb": 500},
73
+ "synapse": {"num_nodes": 2, "storage_gb": 500},
74
+ },
75
+ "medium": {
76
+ # Serverless
77
+ "lambda": {"monthly_requests": 50_000_000, "avg_duration_ms": 400, "memory_mb": 1024},
78
+ "cloud_functions": {"monthly_requests": 50_000_000, "avg_duration_ms": 400, "memory_mb": 1024},
79
+ "azure_functions": {"monthly_requests": 50_000_000, "avg_duration_ms": 400, "memory_mb": 1024},
80
+ # Databases
81
+ "rds": {"storage_gb": 200, "multi_az": True},
82
+ "aurora": {"storage_gb": 200, "multi_az": True},
83
+ "cloud_sql": {"storage_gb": 200},
84
+ "azure_sql": {"storage_gb": 200},
85
+ "dynamodb": {"monthly_requests": 50_000_000},
86
+ # Storage
87
+ "s3": {"storage_gb": 500},
88
+ "cloud_storage": {"storage_gb": 500},
89
+ "blob_storage": {"storage_gb": 500},
90
+ # Compute
91
+ "ec2": {"count": 3},
92
+ "compute_engine": {"count": 3},
93
+ "virtual_machines": {"count": 3},
94
+ # Container orchestration
95
+ "eks": {"node_count": 6},
96
+ "gke": {"node_count": 6},
97
+ "aks": {"node_count": 6},
98
+ "ecs": {"count": 4},
99
+ # CDN
100
+ "cloudfront": {"estimated_gb": 1000},
101
+ "cloud_cdn": {"estimated_gb": 1000},
102
+ "azure_cdn": {"estimated_gb": 1000},
103
+ # Analytics
104
+ "bigquery": {"monthly_query_tb": 10, "storage_gb": 1000},
105
+ "redshift": {"num_nodes": 4, "storage_gb": 2000},
106
+ "synapse": {"num_nodes": 4, "storage_gb": 2000},
107
+ # Cache
108
+ "elasticache": {"memory_gb": 13},
109
+ "memorystore": {"memory_gb": 13},
110
+ "azure_cache": {"memory_gb": 13},
111
+ },
112
+ "large": {
113
+ # Serverless
114
+ "lambda": {"monthly_requests": 500_000_000, "avg_duration_ms": 500, "memory_mb": 2048},
115
+ "cloud_functions": {"monthly_requests": 500_000_000, "avg_duration_ms": 500, "memory_mb": 2048},
116
+ "azure_functions": {"monthly_requests": 500_000_000, "avg_duration_ms": 500, "memory_mb": 2048},
117
+ # Databases
118
+ "rds": {"storage_gb": 1000, "multi_az": True},
119
+ "aurora": {"storage_gb": 1000, "multi_az": True},
120
+ "cloud_sql": {"storage_gb": 1000},
121
+ "azure_sql": {"storage_gb": 1000},
122
+ "dynamodb": {"monthly_requests": 200_000_000},
123
+ # Storage
124
+ "s3": {"storage_gb": 5000},
125
+ "cloud_storage": {"storage_gb": 5000},
126
+ "blob_storage": {"storage_gb": 5000},
127
+ # Compute
128
+ "ec2": {"count": 6},
129
+ "compute_engine": {"count": 6},
130
+ "virtual_machines": {"count": 6},
131
+ # Container orchestration
132
+ "eks": {"node_count": 15},
133
+ "gke": {"node_count": 15},
134
+ "aks": {"node_count": 15},
135
+ "ecs": {"count": 10},
136
+ # CDN
137
+ "cloudfront": {"estimated_gb": 5000},
138
+ "cloud_cdn": {"estimated_gb": 5000},
139
+ "azure_cdn": {"estimated_gb": 5000},
140
+ # Analytics
141
+ "bigquery": {"monthly_query_tb": 50, "storage_gb": 5000},
142
+ "redshift": {"num_nodes": 8, "storage_gb": 10000},
143
+ "synapse": {"num_nodes": 8, "storage_gb": 10000},
144
+ # Cache
145
+ "elasticache": {"memory_gb": 52},
146
+ "memorystore": {"memory_gb": 52},
147
+ "azure_cache": {"memory_gb": 52},
148
+ },
149
+ "enterprise": {
150
+ # Serverless
151
+ "lambda": {"monthly_requests": 2_000_000_000, "avg_duration_ms": 600, "memory_mb": 3072},
152
+ "cloud_functions": {"monthly_requests": 2_000_000_000, "avg_duration_ms": 600, "memory_mb": 3072},
153
+ "azure_functions": {"monthly_requests": 2_000_000_000, "avg_duration_ms": 600, "memory_mb": 3072},
154
+ # Databases
155
+ "rds": {"storage_gb": 5000, "multi_az": True},
156
+ "aurora": {"storage_gb": 5000, "multi_az": True},
157
+ "cloud_sql": {"storage_gb": 5000},
158
+ "azure_sql": {"storage_gb": 5000},
159
+ "dynamodb": {"monthly_requests": 1_000_000_000},
160
+ # Storage
161
+ "s3": {"storage_gb": 50000},
162
+ "cloud_storage": {"storage_gb": 50000},
163
+ "blob_storage": {"storage_gb": 50000},
164
+ # Compute
165
+ "ec2": {"count": 20},
166
+ "compute_engine": {"count": 20},
167
+ "virtual_machines": {"count": 20},
168
+ # Container orchestration
169
+ "eks": {"node_count": 50},
170
+ "gke": {"node_count": 50},
171
+ "aks": {"node_count": 50},
172
+ "ecs": {"count": 30},
173
+ # CDN
174
+ "cloudfront": {"estimated_gb": 50000},
175
+ "cloud_cdn": {"estimated_gb": 50000},
176
+ "azure_cdn": {"estimated_gb": 50000},
177
+ # Analytics
178
+ "bigquery": {"monthly_query_tb": 200, "storage_gb": 50000},
179
+ "redshift": {"num_nodes": 16, "storage_gb": 50000},
180
+ "synapse": {"num_nodes": 16, "storage_gb": 50000},
181
+ # Cache
182
+ "elasticache": {"memory_gb": 200},
183
+ "memorystore": {"memory_gb": 200},
184
+ "azure_cache": {"memory_gb": 200},
185
+ },
186
+ }
187
+
188
+ # Default data transfer (GB/month) per connection when a workload profile is active
189
+ # but the connection has no explicit estimated_monthly_gb.
190
+ _PROFILE_TRANSFER_DEFAULTS: dict[str, float] = {
191
+ "small": 50.0,
192
+ "medium": 200.0,
193
+ "large": 1000.0,
194
+ "enterprise": 5000.0,
195
+ }
196
+
197
+ VALID_WORKLOAD_PROFILES = set(_PROFILE_DEFAULTS.keys())
198
+
199
+
200
+ def _apply_profile(comp: Component, profile: str) -> Component:
201
+ """Return a copy of the component with profile defaults merged into its config.
202
+
203
+ Profile defaults only fill in missing keys — explicit config always wins.
204
+ """
205
+ svc_defaults = _PROFILE_DEFAULTS.get(profile, {}).get(comp.service)
206
+ if not svc_defaults:
207
+ return comp
208
+ merged = dict(svc_defaults)
209
+ merged.update(comp.config or {})
210
+ return comp.model_copy(update={"config": merged})
211
+
43
212
 
44
213
  class CostEngine:
45
214
  def __init__(self, catalog: Catalog | None = None, registry: ServiceRegistry | None = None):
46
215
  self.catalog = catalog or Catalog()
47
216
  self.registry = registry or get_registry()
48
217
 
49
- def estimate(self, spec: ArchSpec, pricing_tier: str = "on_demand") -> CostEstimate:
50
- """Price every component in an ArchSpec and return a full breakdown."""
218
+ def estimate(
219
+ self,
220
+ spec: ArchSpec,
221
+ pricing_tier: str = "on_demand",
222
+ workload_profile: str | None = None,
223
+ ) -> CostEstimate:
224
+ """Price every component in an ArchSpec and return a full breakdown.
225
+
226
+ Args:
227
+ spec: The architecture specification to price.
228
+ pricing_tier: Pricing model — on_demand, reserved_1yr, reserved_3yr, spot.
229
+ workload_profile: Optional sizing profile — small, medium, large, enterprise.
230
+ When set, applies realistic defaults for request volumes, storage sizes,
231
+ node counts, and data transfer that match production workloads.
232
+ """
51
233
  breakdown: list[ComponentCost] = []
52
234
 
53
235
  for comp in spec.components:
54
- monthly = self._price_component(comp, spec.provider, spec.region, pricing_tier)
236
+ effective = _apply_profile(comp, workload_profile) if workload_profile else comp
237
+ monthly = self._price_component(effective, spec.provider, spec.region, pricing_tier)
55
238
  hourly = round(monthly / 730, 4) if monthly > 0 else None
56
- notes = self._cost_notes(comp)
239
+ notes = self._cost_notes(effective)
57
240
  breakdown.append(
58
241
  ComponentCost(
59
242
  component_id=comp.id,
@@ -65,7 +248,7 @@ class CostEngine:
65
248
  )
66
249
 
67
250
  component_total = round(sum(c.monthly for c in breakdown), 2)
68
- data_transfer = self._estimate_data_transfer(spec)
251
+ data_transfer = self._estimate_data_transfer(spec, workload_profile=workload_profile)
69
252
  total = round(component_total + data_transfer, 2)
70
253
 
71
254
  return CostEstimate(
@@ -76,12 +259,22 @@ class CostEngine:
76
259
  as_of=date.today().isoformat(),
77
260
  )
78
261
 
79
- def price(self, spec: ArchSpec, pricing_tier: str = "on_demand") -> ArchSpec:
262
+ def price(
263
+ self,
264
+ spec: ArchSpec,
265
+ pricing_tier: str = "on_demand",
266
+ workload_profile: str | None = None,
267
+ ) -> ArchSpec:
80
268
  """Estimate costs and return a new ArchSpec with cost_estimate attached."""
81
- estimate = self.estimate(spec, pricing_tier=pricing_tier)
269
+ estimate = self.estimate(spec, pricing_tier=pricing_tier, workload_profile=workload_profile)
82
270
  return spec.model_copy(update={"cost_estimate": estimate})
83
271
 
84
- def compare_providers(self, spec: ArchSpec, providers: list[str]) -> list[Alternative]:
272
+ def compare_providers(
273
+ self,
274
+ spec: ArchSpec,
275
+ providers: list[str],
276
+ workload_profile: str | None = None,
277
+ ) -> list[Alternative]:
85
278
  """Price the architecture across multiple cloud providers."""
86
279
  alternatives: list[Alternative] = []
87
280
 
@@ -117,7 +310,7 @@ class CostEngine:
117
310
  "components": mapped_components,
118
311
  }
119
312
  )
120
- alt_estimate = self.estimate(alt_spec)
313
+ alt_estimate = self.estimate(alt_spec, workload_profile=workload_profile)
121
314
 
122
315
  alternatives.append(
123
316
  Alternative(
@@ -216,13 +409,16 @@ class CostEngine:
216
409
 
217
410
  return round(base, 2)
218
411
 
219
- def _estimate_data_transfer(self, spec: ArchSpec) -> float:
412
+ def _estimate_data_transfer(self, spec: ArchSpec, workload_profile: str | None = None) -> float:
220
413
  """Estimate monthly data transfer (egress) costs from connections."""
221
414
  total = 0.0
222
415
  component_map = {c.id: c for c in spec.components}
416
+ profile_default_gb = _PROFILE_TRANSFER_DEFAULTS.get(workload_profile or "", 0.0)
223
417
 
224
418
  for conn in spec.connections:
225
419
  gb = conn.estimated_monthly_gb
420
+ if not gb and profile_default_gb:
421
+ gb = profile_default_gb
226
422
  if not gb:
227
423
  continue
228
424
  source = component_map.get(conn.source)
@@ -30,6 +30,25 @@ class ImporterPlugin(ABC):
30
30
  ...
31
31
 
32
32
 
33
+ def _apply_import_defaults(spec: "ArchSpec") -> "ArchSpec":
34
+ _ENCRYPT_SERVICES = {"rds", "aurora", "cloud_sql", "azure_sql", "s3", "cloud_storage", "blob_storage"}
35
+
36
+ updated = []
37
+ changed = False
38
+ for comp in spec.components:
39
+ if comp.service in _ENCRYPT_SERVICES and not comp.config.get("encryption"):
40
+ new_config = dict(comp.config)
41
+ new_config["encryption"] = True
42
+ updated.append(comp.model_copy(update={"config": new_config}))
43
+ changed = True
44
+ else:
45
+ updated.append(comp)
46
+
47
+ if changed:
48
+ return spec.model_copy(update={"components": updated})
49
+ return spec
50
+
51
+
33
52
  def import_spec(path: str, fmt: str = "auto", design_spec: "ArchSpec | None" = None) -> ArchSpec:
34
53
  """Import an ArchSpec from an infrastructure state file.
35
54
 
@@ -46,12 +65,14 @@ def import_spec(path: str, fmt: str = "auto", design_spec: "ArchSpec | None" = N
46
65
  if fmt == "terraform":
47
66
  from cloudwright.importer.terraform_state import TerraformStateImporter
48
67
 
49
- return TerraformStateImporter().do_import(path, design_spec=design_spec)
68
+ spec = TerraformStateImporter().do_import(path, design_spec=design_spec)
69
+ return _apply_import_defaults(spec)
50
70
 
51
71
  if fmt in ("cloudformation", "cfn"):
52
72
  from cloudwright.importer.cloudformation import CloudFormationImporter
53
73
 
54
- return CloudFormationImporter().do_import(path, design_spec=design_spec)
74
+ spec = CloudFormationImporter().do_import(path, design_spec=design_spec)
75
+ return _apply_import_defaults(spec)
55
76
 
56
77
  raise ValueError(f"Unknown import format: {fmt!r}. Supported: terraform, cloudformation")
57
78
 
@@ -61,6 +61,34 @@ _CFN_TYPE_MAP: dict[str, str] = {
61
61
  # ML
62
62
  "AWS::SageMaker::Endpoint": "sagemaker",
63
63
  "AWS::SageMaker::Model": "sagemaker",
64
+ # IAM
65
+ "AWS::IAM::Role": "iam",
66
+ "AWS::IAM::Policy": "iam",
67
+ "AWS::IAM::InstanceProfile": "iam",
68
+ # Networking
69
+ "AWS::EC2::VPC": "vpc",
70
+ "AWS::EC2::Subnet": "vpc",
71
+ "AWS::EC2::SecurityGroup": "vpc",
72
+ "AWS::EC2::NatGateway": "nat_gateway",
73
+ "AWS::EC2::InternetGateway": "vpc",
74
+ "AWS::EC2::RouteTable": "vpc",
75
+ # Monitoring
76
+ "AWS::CloudWatch::Alarm": "cloudwatch",
77
+ "AWS::Logs::LogGroup": "cloudwatch",
78
+ "AWS::CloudTrail::Trail": "cloudtrail",
79
+ # Kinesis
80
+ "AWS::Kinesis::Stream": "kinesis",
81
+ # Step Functions
82
+ "AWS::StepFunctions::StateMachine": "step_functions",
83
+ # Secrets
84
+ "AWS::SecretsManager::Secret": "secrets_manager",
85
+ "AWS::KMS::Key": "kms",
86
+ # ECR
87
+ "AWS::ECR::Repository": "ecr",
88
+ # MSK
89
+ "AWS::MSK::Cluster": "msk",
90
+ # EventBridge (additional)
91
+ "AWS::Scheduler::Schedule": "eventbridge",
64
92
  }
65
93
 
66
94
  _TIER = {
@@ -70,10 +98,15 @@ _TIER = {
70
98
  "route53": 1,
71
99
  "api_gateway": 1,
72
100
  "cognito": 1,
101
+ "iam": 1,
102
+ "vpc": 1,
103
+ "nat_gateway": 1,
73
104
  "ec2": 2,
74
105
  "lambda": 2,
75
106
  "ecs": 2,
76
107
  "eks": 2,
108
+ "step_functions": 2,
109
+ "sagemaker": 2,
77
110
  "rds": 3,
78
111
  "aurora": 3,
79
112
  "dynamodb": 3,
@@ -82,8 +115,15 @@ _TIER = {
82
115
  "sns": 3,
83
116
  "eventbridge": 3,
84
117
  "redshift": 3,
118
+ "kinesis": 3,
119
+ "msk": 3,
85
120
  "s3": 4,
86
121
  "ebs": 4,
122
+ "cloudwatch": 4,
123
+ "cloudtrail": 4,
124
+ "secrets_manager": 4,
125
+ "kms": 4,
126
+ "ecr": 4,
87
127
  }
88
128
 
89
129
 
@@ -81,6 +81,81 @@ _TIER = {
81
81
  "managed_disks": 4,
82
82
  }
83
83
 
84
+ _HARDCODED_TF_MAP: dict[str, str] = {
85
+ # AWS
86
+ "aws_instance": "ec2",
87
+ "aws_launch_template": "ec2",
88
+ "aws_autoscaling_group": "ec2",
89
+ "aws_ecs_cluster": "ecs",
90
+ "aws_ecs_service": "ecs",
91
+ "aws_ecs_task_definition": "ecs",
92
+ "aws_eks_cluster": "eks",
93
+ "aws_eks_node_group": "eks",
94
+ "aws_lambda_function": "lambda",
95
+ "aws_db_instance": "rds",
96
+ "aws_rds_cluster": "aurora",
97
+ "aws_dynamodb_table": "dynamodb",
98
+ "aws_s3_bucket": "s3",
99
+ "aws_lb": "alb",
100
+ "aws_alb": "alb",
101
+ "aws_lb_target_group": "alb",
102
+ "aws_cloudfront_distribution": "cloudfront",
103
+ "aws_route53_zone": "route53",
104
+ "aws_api_gateway_rest_api": "api_gateway",
105
+ "aws_apigatewayv2_api": "api_gateway",
106
+ "aws_wafv2_web_acl": "waf",
107
+ "aws_cognito_user_pool": "cognito",
108
+ "aws_elasticache_cluster": "elasticache",
109
+ "aws_elasticache_replication_group": "elasticache",
110
+ "aws_sqs_queue": "sqs",
111
+ "aws_sns_topic": "sns",
112
+ "aws_kinesis_stream": "kinesis",
113
+ "aws_redshift_cluster": "redshift",
114
+ "aws_sagemaker_endpoint": "sagemaker",
115
+ "aws_nat_gateway": "nat_gateway",
116
+ "aws_iam_role": "iam",
117
+ "aws_iam_policy": "iam",
118
+ "aws_kms_key": "kms",
119
+ "aws_secretsmanager_secret": "secrets_manager",
120
+ "aws_ecr_repository": "ecr",
121
+ "aws_msk_cluster": "msk",
122
+ "aws_sfn_state_machine": "step_functions",
123
+ "aws_cloudwatch_log_group": "cloudwatch",
124
+ "aws_cloudtrail": "cloudtrail",
125
+ "aws_ebs_volume": "ebs",
126
+ # GCP
127
+ "google_compute_instance": "compute_engine",
128
+ "google_container_cluster": "gke",
129
+ "google_container_node_pool": "gke",
130
+ "google_cloud_run_service": "cloud_run",
131
+ "google_cloudfunctions_function": "cloud_functions",
132
+ "google_cloudfunctions2_function": "cloud_functions",
133
+ "google_sql_database_instance": "cloud_sql",
134
+ "google_storage_bucket": "cloud_storage",
135
+ "google_compute_backend_service": "cloud_load_balancing",
136
+ "google_pubsub_topic": "pub_sub",
137
+ "google_bigquery_dataset": "bigquery",
138
+ "google_redis_instance": "memorystore",
139
+ "google_spanner_instance": "spanner",
140
+ "google_compute_address": "compute_engine",
141
+ # Azure
142
+ "azurerm_virtual_machine": "virtual_machines",
143
+ "azurerm_linux_virtual_machine": "virtual_machines",
144
+ "azurerm_windows_virtual_machine": "virtual_machines",
145
+ "azurerm_kubernetes_cluster": "aks",
146
+ "azurerm_function_app": "azure_functions",
147
+ "azurerm_mssql_server": "azure_sql",
148
+ "azurerm_mssql_database": "azure_sql",
149
+ "azurerm_cosmosdb_account": "cosmos_db",
150
+ "azurerm_storage_account": "blob_storage",
151
+ "azurerm_redis_cache": "azure_cache",
152
+ "azurerm_application_gateway": "app_gateway",
153
+ "azurerm_lb": "azure_lb",
154
+ "azurerm_cdn_profile": "azure_cdn",
155
+ "azurerm_servicebus_namespace": "service_bus",
156
+ "azurerm_eventhub_namespace": "event_hubs",
157
+ }
158
+
84
159
  _REGISTRY_DIR = Path(__file__).parent.parent / "data" / "registry"
85
160
 
86
161
 
@@ -120,7 +195,8 @@ class TerraformStateImporter:
120
195
  """Parses Terraform state files (v3 and v4) into ArchSpec."""
121
196
 
122
197
  def __init__(self) -> None:
123
- self._tf_map = _build_terraform_map()
198
+ self._tf_map = dict(_HARDCODED_TF_MAP) # start with hardcoded fallbacks
199
+ self._tf_map.update(_build_terraform_map()) # registry overrides take precedence
124
200
 
125
201
  @property
126
202
  def format_name(self) -> str:
@@ -166,7 +166,7 @@ class TestInlineTemplate:
166
166
  "AWSTemplateFormatVersion": "2010-09-09",
167
167
  "Resources": {
168
168
  "CustomResource": {"Type": "Custom::MyThing", "Properties": {}},
169
- "IamRole": {"Type": "AWS::IAM::Role", "Properties": {}},
169
+ "UnknownWidget": {"Type": "AWS::Foo::Bar", "Properties": {}},
170
170
  "Web": {"Type": "AWS::EC2::Instance", "Properties": {}},
171
171
  },
172
172
  }
@@ -174,6 +174,6 @@ class TestInlineTemplate:
174
174
  p.write_text(json.dumps(template))
175
175
 
176
176
  spec = import_spec(str(p), fmt="cloudformation")
177
- # Only ec2 should be imported
177
+ # Custom::* and unknown AWS types should be skipped
178
178
  assert len(spec.components) == 1
179
179
  assert spec.components[0].service == "ec2"
File without changes