ic-code 1.6.1__tar.gz → 1.7.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (280) hide show
  1. {ic_code-1.6.1/src/ic_code.egg-info → ic_code-1.7.1}/PKG-INFO +5 -10
  2. {ic_code-1.6.1 → ic_code-1.7.1}/docs/aws/README.md +28 -27
  3. {ic_code-1.6.1 → ic_code-1.7.1}/docs/tencent/README.md +5 -2
  4. {ic_code-1.6.1 → ic_code-1.7.1}/pyproject.toml +4 -4
  5. {ic_code-1.6.1 → ic_code-1.7.1}/requirements.txt +3 -1
  6. {ic_code-1.6.1 → ic_code-1.7.1}/scripts/ci-detect-platforms.py +103 -49
  7. {ic_code-1.6.1 → ic_code-1.7.1}/scripts/ci-generate-matrix.py +30 -11
  8. ic_code-1.7.1/scripts/ci-smoke-test.sh +111 -0
  9. ic_code-1.7.1/setup.py +9 -0
  10. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/__init__.py +2 -2
  11. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/cli.py +5 -0
  12. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/core/dependency_validator.py +7 -6
  13. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/core/platform_discovery.py +11 -2
  14. ic_code-1.7.1/src/ic/platforms/aws/iam/_helpers.py +531 -0
  15. ic_code-1.7.1/src/ic/platforms/aws/iam/check.py +556 -0
  16. ic_code-1.7.1/src/ic/platforms/aws/iam/policy.py +828 -0
  17. ic_code-1.7.1/src/ic/platforms/aws/iam/role.py +643 -0
  18. ic_code-1.7.1/src/ic/platforms/aws/iam/user.py +836 -0
  19. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/compute/mock_data.json +6 -6
  20. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/dns/mock_data.json +2 -2
  21. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/gke/mock_data.json +3 -3
  22. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/lb/mock_data.json +2 -2
  23. ic_code-1.7.1/src/ic/platforms/tencent/cam/_helpers.py +454 -0
  24. ic_code-1.6.1/src/ic/platforms/tencent/cam/user.py → ic_code-1.7.1/src/ic/platforms/tencent/cam/check.py +176 -213
  25. ic_code-1.7.1/src/ic/platforms/tencent/cam/policy.py +683 -0
  26. ic_code-1.7.1/src/ic/platforms/tencent/cam/role.py +639 -0
  27. ic_code-1.7.1/src/ic/platforms/tencent/cam/user.py +872 -0
  28. {ic_code-1.6.1 → ic_code-1.7.1/src/ic_code.egg-info}/PKG-INFO +5 -10
  29. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic_code.egg-info/SOURCES.txt +8 -0
  30. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic_code.egg-info/requires.txt +1 -1
  31. ic_code-1.6.1/scripts/ci-smoke-test.sh +0 -83
  32. ic_code-1.6.1/setup.py +0 -237
  33. ic_code-1.6.1/src/ic/platforms/aws/iam/user.py +0 -559
  34. {ic_code-1.6.1 → ic_code-1.7.1}/LICENSE +0 -0
  35. {ic_code-1.6.1 → ic_code-1.7.1}/MANIFEST.in +0 -0
  36. {ic_code-1.6.1 → ic_code-1.7.1}/README.md +0 -0
  37. {ic_code-1.6.1 → ic_code-1.7.1}/SECURITY.md +0 -0
  38. {ic_code-1.6.1 → ic_code-1.7.1}/config/default.yaml +0 -0
  39. {ic_code-1.6.1 → ic_code-1.7.1}/docs/README.md +0 -0
  40. {ic_code-1.6.1 → ic_code-1.7.1}/docs/cloudflare/README.md +0 -0
  41. {ic_code-1.6.1 → ic_code-1.7.1}/docs/gcp/README.md +0 -0
  42. {ic_code-1.6.1 → ic_code-1.7.1}/docs/installation.md +0 -0
  43. {ic_code-1.6.1 → ic_code-1.7.1}/docs/oci/README.md +0 -0
  44. {ic_code-1.6.1 → ic_code-1.7.1}/docs/release-guide.md +0 -0
  45. {ic_code-1.6.1 → ic_code-1.7.1}/docs/security.md +0 -0
  46. {ic_code-1.6.1 → ic_code-1.7.1}/docs/ssh/README.md +0 -0
  47. {ic_code-1.6.1 → ic_code-1.7.1}/docs/troubleshooting.md +0 -0
  48. {ic_code-1.6.1 → ic_code-1.7.1}/docs/user_guide.md +0 -0
  49. {ic_code-1.6.1 → ic_code-1.7.1}/scripts/bump-version.sh +0 -0
  50. {ic_code-1.6.1 → ic_code-1.7.1}/scripts/cf_edge_nsg_make/cf_edge_nsg_make.py +0 -0
  51. {ic_code-1.6.1 → ic_code-1.7.1}/scripts/deploy.sh +0 -0
  52. {ic_code-1.6.1 → ic_code-1.7.1}/scripts/oracle-policy/user_policy.py +0 -0
  53. {ic_code-1.6.1 → ic_code-1.7.1}/setup.cfg +0 -0
  54. {ic_code-1.6.1 → ic_code-1.7.1}/src/common/__init__.py +0 -0
  55. {ic_code-1.6.1 → ic_code-1.7.1}/src/common/gather_env.py +0 -0
  56. {ic_code-1.6.1 → ic_code-1.7.1}/src/common/gcp_config_validator.py +0 -0
  57. {ic_code-1.6.1 → ic_code-1.7.1}/src/common/gcp_monitoring.py +0 -0
  58. {ic_code-1.6.1 → ic_code-1.7.1}/src/common/gcp_utils.py +0 -0
  59. {ic_code-1.6.1 → ic_code-1.7.1}/src/common/log.py +0 -0
  60. {ic_code-1.6.1 → ic_code-1.7.1}/src/common/progress_decorator.py +0 -0
  61. {ic_code-1.6.1 → ic_code-1.7.1}/src/common/slack.py +0 -0
  62. {ic_code-1.6.1 → ic_code-1.7.1}/src/common/utils.py +0 -0
  63. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/commands/__init__.py +0 -0
  64. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/commands/config.py +0 -0
  65. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/commands/security.py +0 -0
  66. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/compat/__init__.py +0 -0
  67. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/compat/cli.py +0 -0
  68. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/compat/common.py +0 -0
  69. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/config/__init__.py +0 -0
  70. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/config/cleanup.py +0 -0
  71. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/config/docs_organizer.py +0 -0
  72. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/config/external.py +0 -0
  73. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/config/installer.py +0 -0
  74. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/config/manager.py +0 -0
  75. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/config/migration.py +0 -0
  76. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/config/migration_utils.py +0 -0
  77. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/config/path_manager.py +0 -0
  78. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/config/schema.py +0 -0
  79. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/config/secrets.py +0 -0
  80. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/config/security.py +0 -0
  81. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/core/__init__.py +0 -0
  82. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/core/desc_helper.py +0 -0
  83. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/core/interfaces/__init__.py +0 -0
  84. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/core/interfaces/command.py +0 -0
  85. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/core/interfaces/formatter.py +0 -0
  86. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/core/interfaces/result.py +0 -0
  87. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/core/logging.py +0 -0
  88. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/core/session.py +0 -0
  89. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/core/silence_logging.py +0 -0
  90. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/__init__.py +0 -0
  91. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/__init__.py +0 -0
  92. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/cloudfront/__init__.py +0 -0
  93. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/cloudfront/info.py +0 -0
  94. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/codepipeline/__init__.py +0 -0
  95. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/codepipeline/build.py +0 -0
  96. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/codepipeline/deploy.py +0 -0
  97. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/disk/__init__.py +0 -0
  98. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/disk/info.py +0 -0
  99. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/ebs/__init__.py +0 -0
  100. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/ebs/info.py +0 -0
  101. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/ebs/mock_data.json +0 -0
  102. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/ec2/__init__.py +0 -0
  103. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/ec2/desc.py +0 -0
  104. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/ec2/info.py +0 -0
  105. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/ec2/list_tags.py +0 -0
  106. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/ec2/tag_check.py +0 -0
  107. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/ecs/__init__.py +0 -0
  108. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/ecs/info.py +0 -0
  109. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/ecs/service.py +0 -0
  110. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/ecs/task.py +0 -0
  111. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/eks/__init__.py +0 -0
  112. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/eks/addons.py +0 -0
  113. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/eks/fargate.py +0 -0
  114. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/eks/info.py +0 -0
  115. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/eks/nodes.py +0 -0
  116. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/eks/pods.py +0 -0
  117. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/eks/update_config.py +0 -0
  118. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/fargate/__init__.py +0 -0
  119. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/fargate/info.py +0 -0
  120. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/healthdashboard/__init__.py +0 -0
  121. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/healthdashboard/reboot.py +0 -0
  122. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/iam/__init__.py +0 -0
  123. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/lb/__init__.py +0 -0
  124. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/lb/desc.py +0 -0
  125. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/lb/info.py +0 -0
  126. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/lb/list_tags.py +0 -0
  127. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/lb/tag_check.py +0 -0
  128. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/msk/__init__.py +0 -0
  129. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/msk/broker.py +0 -0
  130. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/msk/info.py +0 -0
  131. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/nat/__init__.py +0 -0
  132. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/nat/list_tags.py +0 -0
  133. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/nat/tag_check.py +0 -0
  134. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/profile/__init__.py +0 -0
  135. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/profile/info.py +0 -0
  136. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/profile/switch.py +0 -0
  137. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/rds/__init__.py +0 -0
  138. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/rds/info.py +0 -0
  139. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/rds/list_tags.py +0 -0
  140. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/rds/tag_check.py +0 -0
  141. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/s3/__init__.py +0 -0
  142. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/s3/info.py +0 -0
  143. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/s3/list_tags.py +0 -0
  144. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/s3/tag_check.py +0 -0
  145. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/sg/__init__.py +0 -0
  146. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/sg/info.py +0 -0
  147. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/vpc/__init__.py +0 -0
  148. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/vpc/info.py +0 -0
  149. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/vpc/list_tags.py +0 -0
  150. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/vpc/tag_check.py +0 -0
  151. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/vpn/__init__.py +0 -0
  152. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/vpn/info.py +0 -0
  153. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/__init__.py +0 -0
  154. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/account/__init__.py +0 -0
  155. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/account/info.py +0 -0
  156. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/client.py +0 -0
  157. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/dns/__init__.py +0 -0
  158. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/dns/info.py +0 -0
  159. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/dns/list_info.py +0 -0
  160. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/rules/__init__.py +0 -0
  161. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/rules/info.py +0 -0
  162. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/traffic/__init__.py +0 -0
  163. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/traffic/info.py +0 -0
  164. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/waf/__init__.py +0 -0
  165. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/waf/info.py +0 -0
  166. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/zone/__init__.py +0 -0
  167. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/zone/info.py +0 -0
  168. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/__init__.py +0 -0
  169. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/billing/__init__.py +0 -0
  170. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/billing/info.py +0 -0
  171. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/billing/mock_data.json +0 -0
  172. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/compute/__init__.py +0 -0
  173. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/compute/desc.py +0 -0
  174. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/compute/info.py +0 -0
  175. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/disk/__init__.py +0 -0
  176. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/disk/info.py +0 -0
  177. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/disk/mock_data.json +0 -0
  178. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/dns/__init__.py +0 -0
  179. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/dns/info.py +0 -0
  180. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/firewall/__init__.py +0 -0
  181. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/firewall/info.py +0 -0
  182. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/firewall/mock_data.json +0 -0
  183. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/functions/__init__.py +0 -0
  184. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/functions/info.py +0 -0
  185. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/functions/mock_data.json +0 -0
  186. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/gke/__init__.py +0 -0
  187. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/gke/info.py +0 -0
  188. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/lb/__init__.py +0 -0
  189. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/lb/desc.py +0 -0
  190. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/lb/info.py +0 -0
  191. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/profile/__init__.py +0 -0
  192. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/profile/info.py +0 -0
  193. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/profile/mock_data.json +0 -0
  194. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/project/__init__.py +0 -0
  195. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/project/info.py +0 -0
  196. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/project/mock_data.json +0 -0
  197. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/run/__init__.py +0 -0
  198. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/run/info.py +0 -0
  199. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/run/mock_data.json +0 -0
  200. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/sql/__init__.py +0 -0
  201. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/sql/info.py +0 -0
  202. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/sql/mock_data.json +0 -0
  203. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/storage/__init__.py +0 -0
  204. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/storage/info.py +0 -0
  205. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/storage/mock_data.json +0 -0
  206. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/vpc/__init__.py +0 -0
  207. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/vpc/info.py +0 -0
  208. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/vpc/mock_data.json +0 -0
  209. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/__init__.py +0 -0
  210. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/common/__init__.py +0 -0
  211. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/common/utils.py +0 -0
  212. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/compartment/__init__.py +0 -0
  213. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/compartment/info.py +0 -0
  214. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/cost/__init__.py +0 -0
  215. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/cost/credit.py +0 -0
  216. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/cost/usage.py +0 -0
  217. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/info/__init__.py +0 -0
  218. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/info/oci_info.py +0 -0
  219. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/lb/__init__.py +0 -0
  220. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/lb/info.py +0 -0
  221. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/nsg/__init__.py +0 -0
  222. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/nsg/info.py +0 -0
  223. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/obj/__init__.py +0 -0
  224. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/obj/info.py +0 -0
  225. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/policy/__init__.py +0 -0
  226. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/policy/info.py +0 -0
  227. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/policy/search.py +0 -0
  228. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/vcn/__init__.py +0 -0
  229. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/vcn/info.py +0 -0
  230. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/vm/__init__.py +0 -0
  231. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/vm/info.py +0 -0
  232. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/volume/__init__.py +0 -0
  233. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/volume/info.py +0 -0
  234. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/ssh/__init__.py +0 -0
  235. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/ssh/auto/__init__.py +0 -0
  236. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/ssh/auto/scan.py +0 -0
  237. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/ssh/auto_ssh.py +0 -0
  238. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/ssh/policy.py +0 -0
  239. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/ssh/server/__init__.py +0 -0
  240. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/ssh/server/info.py +0 -0
  241. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/ssh/server_info.py +0 -0
  242. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/__init__.py +0 -0
  243. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/cam/__init__.py +0 -0
  244. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/cbs/__init__.py +0 -0
  245. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/cbs/info.py +0 -0
  246. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/cbs/mock_data.json +0 -0
  247. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/clb/__init__.py +0 -0
  248. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/clb/desc.py +0 -0
  249. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/clb/info.py +0 -0
  250. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/clb/traffic.py +0 -0
  251. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/client.py +0 -0
  252. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/cvm/__init__.py +0 -0
  253. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/cvm/desc.py +0 -0
  254. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/cvm/info.py +0 -0
  255. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/disk/__init__.py +0 -0
  256. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/disk/info.py +0 -0
  257. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/lighthouse/__init__.py +0 -0
  258. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/lighthouse/firewall.py +0 -0
  259. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/lighthouse/info.py +0 -0
  260. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/nat/__init__.py +0 -0
  261. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/nat/info.py +0 -0
  262. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/profile/__init__.py +0 -0
  263. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/profile/info.py +0 -0
  264. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/profile/switch.py +0 -0
  265. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/sg/__init__.py +0 -0
  266. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/sg/info.py +0 -0
  267. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/tke/__init__.py +0 -0
  268. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/tke/info.py +0 -0
  269. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/vpc/__init__.py +0 -0
  270. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/vpc/info.py +0 -0
  271. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/security/__init__.py +0 -0
  272. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/security/config.py +0 -0
  273. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/security/detector.py +0 -0
  274. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/security/guidance.py +0 -0
  275. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/security/hooks.py +0 -0
  276. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/security/patterns.py +0 -0
  277. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/security/scanner.py +0 -0
  278. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic_code.egg-info/dependency_links.txt +0 -0
  279. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic_code.egg-info/entry_points.txt +0 -0
  280. {ic_code-1.6.1 → ic_code-1.7.1}/src/ic_code.egg-info/top_level.txt +0 -0
@@ -1,10 +1,9 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ic-code
3
- Version: 1.6.1
4
- Summary: Infrastructure CLI tool for managing AWS, GCP, OCI, CloudFlare, SSH, and more
5
- Home-page: https://github.com/dgr009/ic
6
- Author: SangYun Kim
3
+ Version: 1.7.1
4
+ Summary: Infrastructure CLI tool for managing AWS, Tencent Cloud, GCP, OCI, CloudFlare, SSH, and more
7
5
  Author-email: sykim <cruiser594@gmail.com>
6
+ License: MIT
8
7
  Project-URL: Homepage, https://github.com/dgr009/ic
9
8
  Project-URL: Bug Reports, https://github.com/dgr009/ic/issues
10
9
  Project-URL: Source, https://github.com/dgr009/ic
@@ -13,7 +12,6 @@ Keywords: cli,infrastructure,aws,oci,gcp,cloudflare,ssh,devops,multi-cloud
13
12
  Classifier: Development Status :: 5 - Production/Stable
14
13
  Classifier: Intended Audience :: Developers
15
14
  Classifier: Intended Audience :: System Administrators
16
- Classifier: License :: OSI Approved :: MIT License
17
15
  Classifier: Operating System :: OS Independent
18
16
  Classifier: Programming Language :: Python :: 3
19
17
  Classifier: Programming Language :: Python :: 3.9
@@ -25,7 +23,7 @@ Classifier: Topic :: System :: Systems Administration
25
23
  Classifier: Topic :: Utilities
26
24
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
27
25
  Classifier: Environment :: Console
28
- Requires-Python: >=3.9,<3.15
26
+ Requires-Python: <3.14,>=3.9
29
27
  Description-Content-Type: text/markdown
30
28
  License-File: LICENSE
31
29
  Requires-Dist: requests<3.0.0,>=2.31.0
@@ -91,7 +89,7 @@ Requires-Dist: paramiko<5.0.0,>=3.4.0; extra == "all"
91
89
  Requires-Dist: netifaces<1.0.0,>=0.11.0; extra == "all"
92
90
  Requires-Dist: kubernetes<32.0.0,>=29.0.0; extra == "all"
93
91
  Provides-Extra: dev
94
- Requires-Dist: pytest<9.0.0,>=8.0.0; extra == "dev"
92
+ Requires-Dist: pytest<10.0.0,>=8.0.0; extra == "dev"
95
93
  Requires-Dist: pytest-cov<8.0.0,>=5.0.0; extra == "dev"
96
94
  Requires-Dist: types-PyYAML>=6.0.0; extra == "dev"
97
95
  Requires-Dist: black<25.0.0,>=24.0.0; extra == "dev"
@@ -99,10 +97,7 @@ Requires-Dist: flake8<8.0.0,>=7.0.0; extra == "dev"
99
97
  Requires-Dist: mypy<2.0.0,>=1.10.0; extra == "dev"
100
98
  Requires-Dist: pyrefly>=1.2.0; extra == "dev"
101
99
  Requires-Dist: pre-commit<4.0.0,>=3.7.0; extra == "dev"
102
- Dynamic: author
103
- Dynamic: home-page
104
100
  Dynamic: license-file
105
- Dynamic: requires-python
106
101
 
107
102
  # IC CLI Tool (Infrastructure Commander)
108
103
 
@@ -11,7 +11,7 @@ This directory contains documentation for the AWS (Amazon Web Services) integrat
11
11
  ## Services Supported
12
12
 
13
13
  - EC2 (Elastic Compute Cloud)
14
- - IAM (Identity and Access Management - Users, Console Login Type, Password Age, Last Login, Last Key Used, Policies: `ic aws iam user`)
14
+ - IAM (Identity and Access Management - Credentials Check, Users, Policies, Roles: `ic aws iam check|user|policy|role`)
15
15
  - AWS Health Dashboard (Scheduled EC2 reboot maintenance checks: `ic aws healthdashboard reboot`)
16
16
  - S3 (Simple Storage Service)
17
17
  - VPC & Security Groups (VPC, Subnets, Gateways, Security Group Tree view)
@@ -60,36 +60,37 @@ ic aws sg info
60
60
  ic aws sg info -o tree
61
61
  ```
62
62
 
63
- ### 4. IAM 사용자 정보 및 보안 점검 (`ic aws iam user`)
63
+ ### 4. IAM 자격증명 수명 점검 및 권한/정책/역할 관리 (`ic aws iam check|user|policy|role`)
64
64
 
65
- AWS 계정 내 IAM 사용자들의 콘솔 로그인 여부(user/service), 암호 수명, 마지막 로그인 일자, 마지막 Access Key 사용 일자, 부여된 권한 정책(Managed, Inline, Group) 목록을 일목요연한 테이블로 출력합니다.
66
-
67
- - **색상 규칙**: 90일 이상(빨강), 60~89일(노랑), 60일 이하(초록)
68
- - **테이블 스타일**: 동일 계정 내 중복 셀 줄 삭제 및 프로필 명칭 그룹화 (`box.HORIZONTALS`)
65
+ AWS 계정 내 IAM 자격증명 수명 검사(`check`), 사용자별 적용된 그룹/정책/역할 매핑(`user`), 정책 및 연결 엔티티 조회(`policy`), 역할 및 신뢰 주체 조회(`role`) 기능을 제공합니다.
69
66
 
70
67
  ```bash
71
- # 전체 계정 IAM 사용자 조회
72
- ic aws iam user
73
-
74
- # 90일 이상(빨간색) 경고 항목이 있는 사용자만 필터링
75
- ic aws iam user -w
76
- ic aws iam user -a prod-account -w
77
-
78
- # 특정 계정 및 사용자 필터
79
- ic aws iam user -a prod-account -n admin
68
+ # 1) IAM 자격증명 수명 및 보안 점검 (암호수명, MFA, 마지막 로그인, 마지막 키 사용일)
69
+ ic aws iam check
70
+ ic aws iam check -w # 90일 이상(빨간색) 경고 항목만 필터링
71
+ ic aws iam check --mfa disabled # 콘솔 로그인 사용자 중 MFA 미설정 계정 필터링
72
+ ic aws iam check -c ">=2025-01-01"
80
73
 
81
- # 유형별 필터 (user 또는 service)
82
- ic aws iam user -t user
83
- ic aws iam user -t service
84
-
85
- # 상세 정보 (User ID, Access Key 목록 포함)
86
- ic aws iam user -v
87
-
88
- # 스프레드시트 복사용 텍스트 출력
89
- ic aws iam user -p
90
-
91
- # JSON 출력
92
- ic aws iam user -o json
74
+ # 2) IAM 사용자별 그룹, 권한 정책(Managed/Inline/Group), 연관 역할(Role), 제한 조건(Resources/Conditions) 조회
75
+ ic aws iam user
76
+ ic aws iam user -a prod-account -n admin,dev
77
+ ic aws iam user -g sre-group --policy Admin --role Deploy
78
+ ic aws iam user --resource s3 --condition 203.0.113.10
79
+ ic aws iam user -o tree
80
+
81
+ # 3) IAM 정책(Managed & Inline Policy), 연결 엔티티(User/Group/Role), Resource/Condition 조회
82
+ ic aws iam policy
83
+ ic aws iam policy -t custom # 사용자 정의 Managed 정책만 조회
84
+ ic aws iam policy -t inline # User/Group/Role에 내장된 Inline 정책만 조회
85
+ ic aws iam policy --attached # 엔티티에 연결된 정책만 조회
86
+ ic aws iam policy --unattached # 미사용 정책 필터링
87
+ ic aws iam policy --resource bucket --condition SourceIp -d
88
+
89
+ # 4) IAM 역할(Role), 신뢰 주체(Trusted Principal & Trust Conditions), 연결 정책(Managed & Inline) 조회
90
+ ic aws iam role
91
+ ic aws iam role -t user # AWS 계정/사용자 신뢰 역할만 조회
92
+ ic aws iam role --trust ec2,eks --policy Admin
93
+ ic aws iam role --condition ExternalId --no-slr -v
93
94
  ```
94
95
 
95
96
  ### 5. Profile 및 인증 모드 전환 (`ic aws profile switch`, `ic aws profile info`)
@@ -46,8 +46,11 @@ IC CLI provides comprehensive, production-grade management for **Tencent Cloud**
46
46
  - **Features**: Ingress/Egress rule inspection and visual tree representation of security group relations.
47
47
 
48
48
  ### 7. CAM (Cloud Access Management)
49
- - **Command**: `ic tencent cam user`
50
- - **Features**: List CAM sub-account users and collaborators (협력자/외부계정), console login type (user vs service vs collaborator), password age, last login timestamp, last SecretId key usage date, and attached policy names with clear color codes (90+ days red, 60-89 yellow, <60 green) and duplicate account cell grouping (`-w / --warn` to filter 90+ days alerts, `-t / --type` to filter user/service/collaborator).
49
+ - **Commands**:
50
+ - `ic tencent cam check`: Inspect CAM sub-account users and collaborators password age, last login timestamp, and last SecretId key usage date with 90-day warning filter (`-w / --warn`, `-t / --type`, `-c / --created`).
51
+ - `ic tencent cam user`: Inspect CAM users and collaborators with their attached Groups, Policies (Direct & Group-inherited), Scoped Resources / Conditions (e.g., `qcs:ip`), and Trusted/Linked Roles (`-g / --group`, `--policy`, `--role`, `--resource`, `--condition`, `-c / --created`, `-o tree`).
52
+ - `ic tencent cam policy`: List CAM policies (`Custom` and `QCS` preset), their attached Users/Groups/Roles, and Statement Resources/Conditions (`-t custom|qcs`, `--service`, `--attached`, `--unattached`, `--entity`, `--resource`, `--condition`, `-d / --document`, `-o tree`).
53
+ - `ic tencent cam role`: List CAM roles (`user`, `system`, `service_linked`), console login flag, trusted principals & trust conditions (`PolicyDocument`), and attached policies (`-t`, `--trust`, `--condition`, `--policy`, `--no-slr`, `-c / --created`, `-o tree`).
51
54
 
52
55
  ### 8. Profile & Authentication Management
53
56
  - **Commands**:
@@ -4,18 +4,18 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ic-code"
7
- version = "1.6.1"
7
+ version = "1.7.1"
8
8
  authors = [
9
9
  {name = "sykim", email = "cruiser594@gmail.com"},
10
10
  ]
11
- description = "Infrastructure CLI tool for managing AWS, GCP, OCI, CloudFlare, SSH, and more"
11
+ description = "Infrastructure CLI tool for managing AWS, Tencent Cloud, GCP, OCI, CloudFlare, SSH, and more"
12
12
  readme = "README.md"
13
+ license = {text = "MIT"}
13
14
  requires-python = ">=3.9,<3.14"
14
15
  classifiers = [
15
16
  "Development Status :: 5 - Production/Stable",
16
17
  "Intended Audience :: Developers",
17
18
  "Intended Audience :: System Administrators",
18
- "License :: OSI Approved :: MIT License",
19
19
  "Operating System :: OS Independent",
20
20
  "Programming Language :: Python :: 3",
21
21
  "Programming Language :: Python :: 3.9",
@@ -112,7 +112,7 @@ all = [
112
112
  "kubernetes>=29.0.0,<32.0.0",
113
113
  ]
114
114
  dev = [
115
- "pytest>=8.0.0,<9.0.0",
115
+ "pytest>=8.0.0,<10.0.0",
116
116
  "pytest-cov>=5.0.0,<8.0.0",
117
117
  "types-PyYAML>=6.0.0",
118
118
  "black>=24.0.0,<25.0.0",
@@ -5,6 +5,7 @@
5
5
  # Core Cloud SDKs
6
6
  boto3>=1.34.0,<2.0.0 # AWS SDK for Python
7
7
  botocore>=1.34.0,<2.0.0 # AWS SDK core library
8
+ tencentcloud-sdk-python>=3.0.0,<4.0.0 # Tencent Cloud SDK for Python
8
9
  oci>=2.149.0,<3.0.0 # Oracle Cloud Infrastructure SDK
9
10
  requests>=2.31.0,<3.0.0 # HTTP library for API calls
10
11
  kubernetes>=29.0.0,<32.0.0 # Kubernetes Python client
@@ -17,6 +18,7 @@ google-cloud-storage>=2.18.0,<3.0.0 # Google Cloud Storage API
17
18
  google-cloud-functions>=1.16.0,<2.0.0 # Google Cloud Functions API
18
19
  google-cloud-run>=0.11.0,<1.0.0 # Google Cloud Run API
19
20
  google-cloud-billing>=1.13.0,<2.0.0 # Google Cloud Billing API
21
+ google-cloud-dns>=0.34.0,<1.0.0 # Google Cloud DNS API
20
22
  google-cloud-resource-manager>=1.12.0,<2.0.0 # Google Cloud Resource Manager API
21
23
  google-auth>=2.29.0,<3.0.0 # Google authentication library
22
24
  google-auth-oauthlib>=1.2.0,<2.0.0 # Google OAuth2 authentication
@@ -53,7 +55,7 @@ packaging>=24.0,<25.0 # Version parsing and comparison
53
55
  setuptools>=69.0.0,<76.0.0 # Package building tools
54
56
 
55
57
  # Development and Testing
56
- pytest>=8.0.0,<9.0.0
58
+ pytest>=8.0.0,<10.0.0
57
59
  pytest-cov>=5.0.0,<8.0.0
58
60
  types-PyYAML>=6.0.0
59
61
  pyrefly>=1.2.0
@@ -40,75 +40,132 @@ def get_changed_files(event_name, base_sha=None, head_sha=None):
40
40
  return []
41
41
 
42
42
 
43
+ PLATFORM_ALIASES = {
44
+ "cf": "cloudflare",
45
+ "cloudflare": "cloudflare",
46
+ "aws": "aws",
47
+ "tencent": "tencent",
48
+ "gcp": "gcp",
49
+ "oci": "oci",
50
+ "ssh": "ssh",
51
+ }
52
+
53
+ CORE_PATHS = (
54
+ "src/ic/core/",
55
+ "src/ic/config/",
56
+ "src/ic/cli.py",
57
+ "src/common/",
58
+ "pyproject.toml",
59
+ "requirements.txt",
60
+ ".github/workflows/",
61
+ )
62
+
63
+
64
+ def normalize_platform(name: str) -> str:
65
+ return PLATFORM_ALIASES.get(name.lower().strip(), name.lower().strip())
66
+
67
+
43
68
  def detect_platforms_from_commit(commit_msg, all_platforms):
44
- """Detect platforms from commit message tags."""
69
+ """Detect platforms from explicit CI tags in the commit subject line."""
45
70
  detected = []
46
-
71
+ subject = commit_msg.splitlines()[0] if commit_msg else ""
72
+
47
73
  # Check for [all] or [test-all] tag
48
- if re.search(r'\[(all|test-all)\]', commit_msg, re.IGNORECASE):
74
+ if re.search(r"\[(all|test-all)\]", commit_msg, re.IGNORECASE):
49
75
  return list(all_platforms)
50
-
51
- # Check for platform tags: [platform], (platform), or platform:
52
- for platform in all_platforms:
53
- pattern = rf'\[{platform}\]|\({platform}\)|{platform}:'
54
- if re.search(pattern, commit_msg, re.IGNORECASE):
55
- detected.append(platform)
56
-
76
+
77
+ # Only filter by commit message if explicit bracket tag [aws], [tencent], etc. is in subject
78
+ search_tokens = list(all_platforms) + ["cf"]
79
+ for token in search_tokens:
80
+ pattern = rf"\[(?:ci:|test:)?{token}\]"
81
+ if re.search(pattern, subject, re.IGNORECASE):
82
+ norm = normalize_platform(token)
83
+ if norm in all_platforms and norm not in detected:
84
+ detected.append(norm)
85
+
57
86
  return detected
58
87
 
59
88
 
60
89
  def detect_platforms_from_files(changed_files, all_platforms):
61
90
  """Detect platforms from changed files."""
62
91
  detected = set()
63
-
92
+
64
93
  for file_path in changed_files:
94
+ if any(file_path.startswith(core_prefix) for core_prefix in CORE_PATHS):
95
+ return list(all_platforms)
96
+
65
97
  for platform in all_platforms:
66
- if f"src/ic/platforms/{platform}/" in file_path or \
67
- f"tests/platforms/{platform}/" in file_path or \
68
- f"test_{platform}" in file_path or \
69
- f"_{platform}_" in file_path:
98
+ if (
99
+ f"src/ic/platforms/{platform}/" in file_path
100
+ or f"tests/platforms/{platform}/" in file_path
101
+ or f"test_{platform}" in file_path
102
+ or f"_{platform}_" in file_path
103
+ ):
70
104
  detected.add(platform)
71
-
105
+
106
+ if "cf" in file_path or "cloudflare" in file_path:
107
+ if "src/ic/platforms/cloudflare/" in file_path or "tests/platforms/cloudflare/" in file_path:
108
+ detected.add("cloudflare")
109
+
72
110
  return list(detected)
73
111
 
74
112
 
75
113
  def filter_platforms_with_tests(platforms):
76
114
  """Filter platforms that have actual test files."""
77
115
  platforms_with_tests = []
78
-
116
+
79
117
  for platform in platforms:
80
- test_dir = Path(f"tests/platforms/{platform}")
118
+ norm = normalize_platform(platform)
119
+ test_dir = Path(f"tests/platforms/{norm}")
81
120
  platform_tests = list(test_dir.rglob("test_*.py")) if test_dir.exists() else []
82
- unit_tests = list(Path("tests").rglob(f"test_*{platform}*.py"))
83
-
121
+ unit_tests = list(Path("tests/unit").rglob(f"test_*{norm}*.py"))
122
+
84
123
  all_tests = set(platform_tests + unit_tests)
85
124
  if all_tests:
86
- platforms_with_tests.append(platform)
87
- print(f"✓ Platform {platform} has {len(all_tests)} test files")
125
+ platforms_with_tests.append(norm)
126
+ print(f"Platform {norm} has {len(all_tests)} test files")
88
127
  else:
89
- print(f"⚠ Platform {platform} has no test files")
90
-
128
+ print(f"Platform {norm} has no dedicated test files")
129
+
91
130
  return platforms_with_tests
92
131
 
93
132
 
133
+ def discover_all_platforms():
134
+ """Auto-discover platforms that have a directory under tests/platforms/."""
135
+ canonical_order = ["aws", "tencent", "gcp", "oci", "cloudflare", "ssh"]
136
+ platforms_root = Path("tests/platforms")
137
+ discovered = []
138
+ if platforms_root.exists():
139
+ for child in sorted(platforms_root.iterdir()):
140
+ if child.is_dir() and child.name != "__pycache__":
141
+ if list(child.rglob("test_*.py")):
142
+ discovered.append(child.name)
143
+ # Return in canonical order first, followed by any newly added platforms
144
+ ordered = [p for p in canonical_order if p in discovered]
145
+ for p in discovered:
146
+ if p not in ordered:
147
+ ordered.append(p)
148
+ return ordered or canonical_order
149
+
150
+
94
151
  def main():
95
- # All available platforms
96
- ALL_PLATFORMS = ["aws", "tencent", "gcp", "oci", "cf", "ssh"]
97
-
152
+ # Auto-discover all available platforms with tests
153
+ ALL_PLATFORMS = discover_all_platforms()
154
+
98
155
  # Get environment variables
99
156
  event_name = os.environ.get("GITHUB_EVENT_NAME", "")
100
157
  base_sha = os.environ.get("BASE_SHA", "")
101
158
  head_sha = os.environ.get("HEAD_SHA", "")
102
-
159
+
103
160
  # Get commit message
104
161
  commit_msg = os.environ.get("COMMIT_MSG", "") or get_commit_message()
105
162
  print(f"Commit message: {commit_msg}")
106
-
163
+
107
164
  # Detect platforms from commit message
108
165
  detected_platforms = detect_platforms_from_commit(commit_msg, ALL_PLATFORMS)
109
-
166
+
110
167
  if detected_platforms:
111
- print(f"✓ Found platforms from commit message: {detected_platforms}")
168
+ print(f"Found platforms from commit message: {detected_platforms}")
112
169
  else:
113
170
  # Detect from changed files
114
171
  print("No platform tags in commit message, checking changed files...")
@@ -117,28 +174,26 @@ def main():
117
174
  print(f"Changed files: {len(changed_files)} files")
118
175
  detected_platforms = detect_platforms_from_files(changed_files, ALL_PLATFORMS)
119
176
  if detected_platforms:
120
- print(f"✓ Found platforms from changed files: {detected_platforms}")
121
-
122
- # Use defaults if nothing detected
177
+ print(f"Found platforms from changed files: {detected_platforms}")
178
+
179
+ # Default to all platforms when no specific platform subset was detected
123
180
  if not detected_platforms:
124
- print("No platforms detected, using default: aws")
125
- detected_platforms = ["aws"]
126
-
181
+ print("No specific platform filter detected, testing all platforms")
182
+ detected_platforms = list(ALL_PLATFORMS)
183
+
127
184
  # Filter platforms that have tests
128
185
  platforms_with_tests = filter_platforms_with_tests(detected_platforms)
129
-
130
- # Remove duplicates and sort
131
- platforms_with_tests = sorted(set(platforms_with_tests))
132
-
133
- # If no platforms with tests detected, fallback to aws
186
+
187
+ # Remove duplicates and preserve canonical order
188
+ platforms_with_tests = [p for p in ALL_PLATFORMS if p in set(platforms_with_tests)]
189
+
134
190
  if not platforms_with_tests:
135
- print("⚠ No platforms with tests detected, falling back to: aws")
136
- platforms_with_tests = ["aws"]
137
-
191
+ platforms_with_tests = list(ALL_PLATFORMS)
192
+
138
193
  # Output as JSON (compact, single line)
139
- platforms_json = json.dumps(platforms_with_tests, separators=(',', ':'))
194
+ platforms_json = json.dumps(platforms_with_tests, separators=(",", ":"))
140
195
  print(f"\nFinal platforms to test: {platforms_json}")
141
-
196
+
142
197
  # Write to GitHub output if in CI
143
198
  github_output = os.environ.get("GITHUB_OUTPUT")
144
199
  if github_output:
@@ -146,10 +201,9 @@ def main():
146
201
  f.write(f"platforms={platforms_json}\n")
147
202
  f.write(f"should-run-tests={'true' if platforms_with_tests else 'false'}\n")
148
203
  else:
149
- # For local testing
150
204
  print(f"platforms={platforms_json}")
151
205
  print(f"should-run-tests={'true' if platforms_with_tests else 'false'}")
152
-
206
+
153
207
  return 0
154
208
 
155
209
 
@@ -9,21 +9,40 @@ import os
9
9
  import sys
10
10
 
11
11
 
12
+ PLATFORM_ALIASES = {
13
+ "cf": "cloudflare",
14
+ "cloudflare": "cloudflare",
15
+ "aws": "aws",
16
+ "tencent": "tencent",
17
+ "gcp": "gcp",
18
+ "oci": "oci",
19
+ "ssh": "ssh",
20
+ }
21
+
22
+
12
23
  def main():
13
24
  # Get inputs
14
- test_types_str = os.environ.get("TEST_TYPES", '["unit", "integration", "performance"]')
15
- platforms_str = os.environ.get("PLATFORMS", '["aws", "tencent", "gcp", "oci", "cf", "ssh"]')
16
-
25
+ test_types_str = os.environ.get("TEST_TYPES", '["unit"]')
26
+ platforms_str = os.environ.get(
27
+ "PLATFORMS", '["aws", "tencent", "gcp", "oci", "cloudflare", "ssh"]'
28
+ )
29
+
17
30
  try:
18
31
  test_types = json.loads(test_types_str)
19
- platforms = json.loads(platforms_str)
32
+ raw_platforms = json.loads(platforms_str)
20
33
  except json.JSONDecodeError as e:
21
34
  print(f"Error parsing JSON: {e}", file=sys.stderr)
22
35
  return 1
23
-
24
- # Python versions to test
25
- python_versions = ["3.9", "3.11", "3.13"]
26
-
36
+
37
+ platforms = []
38
+ for p in raw_platforms:
39
+ norm = PLATFORM_ALIASES.get(str(p).lower().strip(), str(p).lower().strip())
40
+ if norm not in platforms:
41
+ platforms.append(norm)
42
+
43
+ # Supported Python versions in CI
44
+ python_versions = ["3.11", "3.13"]
45
+
27
46
  # Generate matrix
28
47
  matrix = []
29
48
  for python_version in python_versions:
@@ -33,11 +52,11 @@ def main():
33
52
  "python-version": python_version,
34
53
  "platform": platform,
35
54
  "test-type": test_type,
36
- "os": "ubuntu-latest"
55
+ "os": "ubuntu-latest",
37
56
  })
38
-
57
+
39
58
  # Output as compact JSON
40
- matrix_json = json.dumps({"include": matrix}, separators=(',', ':'))
59
+ matrix_json = json.dumps({"include": matrix}, separators=(",", ":"))
41
60
 
42
61
  print(f"Generated matrix with {len(matrix)} jobs")
43
62
  print(f"Platforms: {platforms}")
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env bash
2
+ # CI Clean Environment Smoke Test Script
3
+ # Verifies that built wheel packages install and run without runtime crashes in a clean environment.
4
+
5
+ set -euo pipefail
6
+
7
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
8
+ REPO_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
9
+
10
+ # Ensure true isolation from source tree PYTHONPATH during wheel installation and execution
11
+ unset PYTHONPATH
12
+
13
+ echo "=================================================="
14
+ echo "[SMOKE] Running IC CLI Clean Environment Smoke Test"
15
+ echo "=================================================="
16
+
17
+ # Check if dist/ contains a wheel
18
+ DIST_DIR="${REPO_ROOT}/dist"
19
+ WHEEL_FILE=$(find "${DIST_DIR}" -name "ic_code-*.whl" 2>/dev/null | sort -V | tail -n 1 || true)
20
+
21
+ if [ -z "${WHEEL_FILE}" ] || [ ! -f "${WHEEL_FILE}" ]; then
22
+ echo "[BUILD] No built wheel found in ${DIST_DIR}. Building package..."
23
+ mkdir -p "${DIST_DIR}"
24
+ if python3 -m build --version >/dev/null 2>&1; then
25
+ python3 -m build --wheel "${REPO_ROOT}"
26
+ else
27
+ python3 -m pip wheel --no-deps -w "${DIST_DIR}" "${REPO_ROOT}"
28
+ fi
29
+ WHEEL_FILE=$(find "${DIST_DIR}" -name "ic_code-*.whl" | sort -V | tail -n 1)
30
+ fi
31
+
32
+ echo "[SMOKE] Target wheel: ${WHEEL_FILE}"
33
+
34
+ # Create isolated temporary virtual environment
35
+ TEMP_VENV=$(mktemp -d -t ic-smoke-venv-XXXXXX)
36
+ echo "[SMOKE] Creating temporary virtualenv in ${TEMP_VENV}..."
37
+ python3 -m venv "${TEMP_VENV}"
38
+
39
+ cleanup() {
40
+ echo "[SMOKE] Cleaning up temporary test environment..."
41
+ rm -rf "${TEMP_VENV}"
42
+ }
43
+ trap cleanup EXIT
44
+
45
+ VENV_PYTHON="${TEMP_VENV}/bin/python"
46
+ IC_BIN="${TEMP_VENV}/bin/ic"
47
+ export PATH="${TEMP_VENV}/bin:${PATH}"
48
+
49
+ "${VENV_PYTHON}" -m pip install --upgrade --quiet pip
50
+
51
+ # 1. Test Core Installation (NO cloud extras)
52
+ echo "--------------------------------------------------"
53
+ echo "[1/3] Testing Minimal Core Installation (No extras)..."
54
+ "${VENV_PYTHON}" -m pip install --quiet "${WHEEL_FILE}"
55
+ hash -r
56
+
57
+ if [ ! -x "${IC_BIN}" ]; then
58
+ echo "[ERROR] Expected console script not found at ${IC_BIN}"
59
+ exit 1
60
+ fi
61
+
62
+ echo " - Checking 'ic --help'..."
63
+ "${IC_BIN}" --help > /dev/null
64
+
65
+ echo " - Checking 'ic --version'..."
66
+ "${IC_BIN}" version > /dev/null || "${IC_BIN}" --version > /dev/null
67
+
68
+ echo " - Checking lazy platform help without cloud SDKs..."
69
+ "${IC_BIN}" aws --help > /dev/null
70
+ "${IC_BIN}" aws iam --help > /dev/null
71
+ "${IC_BIN}" aws iam check --help > /dev/null
72
+ "${IC_BIN}" aws iam user --help > /dev/null
73
+ "${IC_BIN}" aws iam policy --help > /dev/null
74
+ "${IC_BIN}" aws iam role --help > /dev/null
75
+ "${IC_BIN}" tencent --help > /dev/null
76
+ "${IC_BIN}" tencent cam --help > /dev/null
77
+ "${IC_BIN}" tencent cam check --help > /dev/null
78
+ "${IC_BIN}" tencent cam user --help > /dev/null
79
+ "${IC_BIN}" tencent cam policy --help > /dev/null
80
+ "${IC_BIN}" tencent cam role --help > /dev/null
81
+ "${IC_BIN}" gcp --help > /dev/null
82
+ "${IC_BIN}" oci --help > /dev/null
83
+ "${IC_BIN}" cloudflare --help > /dev/null
84
+ "${IC_BIN}" ssh --help > /dev/null
85
+
86
+ # 2. Test Output formatting in core
87
+ echo "--------------------------------------------------"
88
+ echo "[2/3] Testing Core Output Formatting & Stderr Separation..."
89
+ HELP_OUTPUT=$("${IC_BIN}" --help)
90
+ if [[ -z "${HELP_OUTPUT}" ]]; then
91
+ echo "[ERROR] 'ic --help' produced empty output"
92
+ exit 1
93
+ fi
94
+
95
+ if echo "${HELP_OUTPUT}" | grep -i "traceback"; then
96
+ echo "[ERROR] Traceback detected in 'ic --help' output"
97
+ exit 1
98
+ fi
99
+
100
+ echo " - Zero-crash parser & lazy-loading validated in isolated venv."
101
+
102
+ # 3. Test Extras Installation syntax
103
+ echo "--------------------------------------------------"
104
+ echo "[3/3] Testing Extras Resolution (dry-run/compatibility check)..."
105
+ "${VENV_PYTHON}" -m pip install --dry-run "${WHEEL_FILE}[aws]" > /dev/null 2>&1 || {
106
+ echo "[WARN] pip dry-run not fully supported on this pip version, skipping dry-run."
107
+ }
108
+
109
+ echo "=================================================="
110
+ echo "[PASS] All Clean Environment Smoke Tests PASSED!"
111
+ echo "=================================================="
ic_code-1.7.1/setup.py ADDED
@@ -0,0 +1,9 @@
1
+ """
2
+ Setup script for IC (Infra Resource Management CLI).
3
+ All package metadata, dependencies, and entry points are defined in pyproject.toml (PEP 621).
4
+ """
5
+
6
+ from setuptools import setup
7
+
8
+ if __name__ == "__main__":
9
+ setup()
@@ -4,8 +4,8 @@ IC (Infra Resource Management CLI) - A comprehensive tool for managing cloud inf
4
4
  This package provides CLI tools and libraries for managing AWS, GCP, OCI, CloudFlare, and SSH resources.
5
5
  """
6
6
 
7
- __version__ = "1.6.1"
8
- __author__ = "SangYun"
7
+ __version__ = "1.7.1"
8
+ __author__ = "sykim"
9
9
  __email__ = "cruiser594@gmail.com"
10
10
 
11
11
  # Core components
@@ -396,8 +396,13 @@ def setup_platform_parsers(platform_subparsers):
396
396
  # Add commands for this service
397
397
  commands = discovery.get_service_commands(platform_name, service_name)
398
398
  for command_name, command_module in commands.items():
399
+ try:
400
+ aliases = getattr(command_module, 'ALIASES', []) or []
401
+ except Exception:
402
+ aliases = []
399
403
  command_parser = command_subparsers.add_parser(
400
404
  command_name,
405
+ aliases=aliases,
401
406
  help=f"{command_name} 명령어"
402
407
  )
403
408