ic-code 1.5.0__tar.gz → 1.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 (248) hide show
  1. {ic_code-1.5.0/src/ic_code.egg-info → ic_code-1.5.2}/PKG-INFO +3 -3
  2. {ic_code-1.5.0 → ic_code-1.5.2}/README.md +2 -2
  3. {ic_code-1.5.0 → ic_code-1.5.2}/docs/gcp/README.md +2 -2
  4. {ic_code-1.5.0 → ic_code-1.5.2}/docs/user_guide.md +1 -1
  5. {ic_code-1.5.0 → ic_code-1.5.2}/pyproject.toml +1 -1
  6. {ic_code-1.5.0 → ic_code-1.5.2}/src/common/gcp_utils.py +38 -30
  7. {ic_code-1.5.0 → ic_code-1.5.2}/src/common/log.py +7 -0
  8. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/__init__.py +1 -1
  9. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/compat/common.py +18 -5
  10. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/core/logging.py +30 -32
  11. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/firewall/info.py +219 -20
  12. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/firewall/mock_data.json +7 -1
  13. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/lb/info.py +329 -53
  14. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/lb/mock_data.json +64 -0
  15. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/vpc/info.py +7 -6
  16. {ic_code-1.5.0 → ic_code-1.5.2/src/ic_code.egg-info}/PKG-INFO +3 -3
  17. {ic_code-1.5.0 → ic_code-1.5.2}/LICENSE +0 -0
  18. {ic_code-1.5.0 → ic_code-1.5.2}/MANIFEST.in +0 -0
  19. {ic_code-1.5.0 → ic_code-1.5.2}/SECURITY.md +0 -0
  20. {ic_code-1.5.0 → ic_code-1.5.2}/config/default.yaml +0 -0
  21. {ic_code-1.5.0 → ic_code-1.5.2}/docs/README.md +0 -0
  22. {ic_code-1.5.0 → ic_code-1.5.2}/docs/aws/README.md +0 -0
  23. {ic_code-1.5.0 → ic_code-1.5.2}/docs/cloudflare/README.md +0 -0
  24. {ic_code-1.5.0 → ic_code-1.5.2}/docs/installation.md +0 -0
  25. {ic_code-1.5.0 → ic_code-1.5.2}/docs/oci/README.md +0 -0
  26. {ic_code-1.5.0 → ic_code-1.5.2}/docs/release-guide.md +0 -0
  27. {ic_code-1.5.0 → ic_code-1.5.2}/docs/security.md +0 -0
  28. {ic_code-1.5.0 → ic_code-1.5.2}/docs/ssh/README.md +0 -0
  29. {ic_code-1.5.0 → ic_code-1.5.2}/docs/tencent/README.md +0 -0
  30. {ic_code-1.5.0 → ic_code-1.5.2}/docs/troubleshooting.md +0 -0
  31. {ic_code-1.5.0 → ic_code-1.5.2}/requirements.txt +0 -0
  32. {ic_code-1.5.0 → ic_code-1.5.2}/scripts/bump-version.sh +0 -0
  33. {ic_code-1.5.0 → ic_code-1.5.2}/scripts/cf_edge_nsg_make/cf_edge_nsg_make.py +0 -0
  34. {ic_code-1.5.0 → ic_code-1.5.2}/scripts/ci-detect-platforms.py +0 -0
  35. {ic_code-1.5.0 → ic_code-1.5.2}/scripts/ci-generate-matrix.py +0 -0
  36. {ic_code-1.5.0 → ic_code-1.5.2}/scripts/ci-smoke-test.sh +0 -0
  37. {ic_code-1.5.0 → ic_code-1.5.2}/scripts/deploy.sh +0 -0
  38. {ic_code-1.5.0 → ic_code-1.5.2}/scripts/oracle-policy/user_policy.py +0 -0
  39. {ic_code-1.5.0 → ic_code-1.5.2}/setup.cfg +0 -0
  40. {ic_code-1.5.0 → ic_code-1.5.2}/setup.py +0 -0
  41. {ic_code-1.5.0 → ic_code-1.5.2}/src/common/__init__.py +0 -0
  42. {ic_code-1.5.0 → ic_code-1.5.2}/src/common/gather_env.py +0 -0
  43. {ic_code-1.5.0 → ic_code-1.5.2}/src/common/gcp_config_validator.py +0 -0
  44. {ic_code-1.5.0 → ic_code-1.5.2}/src/common/gcp_monitoring.py +0 -0
  45. {ic_code-1.5.0 → ic_code-1.5.2}/src/common/progress_decorator.py +0 -0
  46. {ic_code-1.5.0 → ic_code-1.5.2}/src/common/slack.py +0 -0
  47. {ic_code-1.5.0 → ic_code-1.5.2}/src/common/utils.py +0 -0
  48. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/cli.py +0 -0
  49. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/commands/__init__.py +0 -0
  50. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/commands/config.py +0 -0
  51. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/commands/security.py +0 -0
  52. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/compat/__init__.py +0 -0
  53. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/compat/cli.py +0 -0
  54. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/config/__init__.py +0 -0
  55. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/config/cleanup.py +0 -0
  56. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/config/docs_organizer.py +0 -0
  57. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/config/external.py +0 -0
  58. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/config/installer.py +0 -0
  59. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/config/manager.py +0 -0
  60. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/config/migration.py +0 -0
  61. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/config/migration_utils.py +0 -0
  62. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/config/path_manager.py +0 -0
  63. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/config/schema.py +0 -0
  64. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/config/secrets.py +0 -0
  65. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/config/security.py +0 -0
  66. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/core/__init__.py +0 -0
  67. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/core/dependency_validator.py +0 -0
  68. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/core/desc_helper.py +0 -0
  69. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/core/interfaces/__init__.py +0 -0
  70. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/core/interfaces/command.py +0 -0
  71. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/core/interfaces/formatter.py +0 -0
  72. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/core/interfaces/result.py +0 -0
  73. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/core/platform_discovery.py +0 -0
  74. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/core/session.py +0 -0
  75. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/core/silence_logging.py +0 -0
  76. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/__init__.py +0 -0
  77. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/__init__.py +0 -0
  78. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/cloudfront/__init__.py +0 -0
  79. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/cloudfront/info.py +0 -0
  80. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/codepipeline/__init__.py +0 -0
  81. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/codepipeline/build.py +0 -0
  82. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/codepipeline/deploy.py +0 -0
  83. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/ec2/__init__.py +0 -0
  84. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/ec2/desc.py +0 -0
  85. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/ec2/info.py +0 -0
  86. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/ec2/list_tags.py +0 -0
  87. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/ec2/tag_check.py +0 -0
  88. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/ecs/__init__.py +0 -0
  89. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/ecs/info.py +0 -0
  90. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/ecs/service.py +0 -0
  91. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/ecs/task.py +0 -0
  92. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/eks/__init__.py +0 -0
  93. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/eks/addons.py +0 -0
  94. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/eks/fargate.py +0 -0
  95. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/eks/info.py +0 -0
  96. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/eks/nodes.py +0 -0
  97. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/eks/pods.py +0 -0
  98. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/eks/update_config.py +0 -0
  99. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/fargate/__init__.py +0 -0
  100. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/fargate/info.py +0 -0
  101. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/healthdashboard/__init__.py +0 -0
  102. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/healthdashboard/reboot.py +0 -0
  103. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/lb/__init__.py +0 -0
  104. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/lb/desc.py +0 -0
  105. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/lb/info.py +0 -0
  106. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/lb/list_tags.py +0 -0
  107. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/lb/tag_check.py +0 -0
  108. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/msk/__init__.py +0 -0
  109. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/msk/broker.py +0 -0
  110. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/msk/info.py +0 -0
  111. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/nat/__init__.py +0 -0
  112. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/nat/list_tags.py +0 -0
  113. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/nat/tag_check.py +0 -0
  114. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/profile/__init__.py +0 -0
  115. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/profile/info.py +0 -0
  116. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/rds/__init__.py +0 -0
  117. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/rds/info.py +0 -0
  118. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/rds/list_tags.py +0 -0
  119. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/rds/tag_check.py +0 -0
  120. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/s3/__init__.py +0 -0
  121. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/s3/info.py +0 -0
  122. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/s3/list_tags.py +0 -0
  123. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/s3/tag_check.py +0 -0
  124. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/sg/__init__.py +0 -0
  125. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/sg/info.py +0 -0
  126. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/vpc/__init__.py +0 -0
  127. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/vpc/info.py +0 -0
  128. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/vpc/list_tags.py +0 -0
  129. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/vpc/tag_check.py +0 -0
  130. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/vpn/__init__.py +0 -0
  131. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/aws/vpn/info.py +0 -0
  132. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/cloudflare/__init__.py +0 -0
  133. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/cloudflare/account/__init__.py +0 -0
  134. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/cloudflare/account/info.py +0 -0
  135. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/cloudflare/client.py +0 -0
  136. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/cloudflare/dns/__init__.py +0 -0
  137. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/cloudflare/dns/info.py +0 -0
  138. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/cloudflare/dns/list_info.py +0 -0
  139. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/cloudflare/rules/__init__.py +0 -0
  140. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/cloudflare/rules/info.py +0 -0
  141. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/cloudflare/traffic/__init__.py +0 -0
  142. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/cloudflare/traffic/info.py +0 -0
  143. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/cloudflare/waf/__init__.py +0 -0
  144. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/cloudflare/waf/info.py +0 -0
  145. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/cloudflare/zone/__init__.py +0 -0
  146. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/cloudflare/zone/info.py +0 -0
  147. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/__init__.py +0 -0
  148. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/billing/__init__.py +0 -0
  149. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/billing/info.py +0 -0
  150. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/billing/mock_data.json +0 -0
  151. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/compute/__init__.py +0 -0
  152. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/compute/desc.py +0 -0
  153. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/compute/info.py +0 -0
  154. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/compute/mock_data.json +0 -0
  155. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/dns/__init__.py +0 -0
  156. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/dns/info.py +0 -0
  157. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/dns/mock_data.json +0 -0
  158. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/firewall/__init__.py +0 -0
  159. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/functions/__init__.py +0 -0
  160. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/functions/info.py +0 -0
  161. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/functions/mock_data.json +0 -0
  162. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/gke/__init__.py +0 -0
  163. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/gke/info.py +0 -0
  164. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/gke/mock_data.json +0 -0
  165. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/lb/__init__.py +0 -0
  166. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/lb/desc.py +0 -0
  167. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/profile/__init__.py +0 -0
  168. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/profile/info.py +0 -0
  169. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/profile/mock_data.json +0 -0
  170. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/project/__init__.py +0 -0
  171. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/project/info.py +0 -0
  172. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/project/mock_data.json +0 -0
  173. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/run/__init__.py +0 -0
  174. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/run/info.py +0 -0
  175. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/run/mock_data.json +0 -0
  176. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/sql/__init__.py +0 -0
  177. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/sql/info.py +0 -0
  178. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/sql/mock_data.json +0 -0
  179. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/storage/__init__.py +0 -0
  180. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/storage/info.py +0 -0
  181. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/storage/mock_data.json +0 -0
  182. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/vpc/__init__.py +0 -0
  183. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/gcp/vpc/mock_data.json +0 -0
  184. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/oci/__init__.py +0 -0
  185. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/oci/common/__init__.py +0 -0
  186. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/oci/common/utils.py +0 -0
  187. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/oci/compartment/__init__.py +0 -0
  188. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/oci/compartment/info.py +0 -0
  189. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/oci/cost/__init__.py +0 -0
  190. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/oci/cost/credit.py +0 -0
  191. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/oci/cost/usage.py +0 -0
  192. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/oci/info/__init__.py +0 -0
  193. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/oci/info/oci_info.py +0 -0
  194. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/oci/lb/__init__.py +0 -0
  195. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/oci/lb/info.py +0 -0
  196. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/oci/nsg/__init__.py +0 -0
  197. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/oci/nsg/info.py +0 -0
  198. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/oci/obj/__init__.py +0 -0
  199. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/oci/obj/info.py +0 -0
  200. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/oci/policy/__init__.py +0 -0
  201. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/oci/policy/info.py +0 -0
  202. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/oci/policy/search.py +0 -0
  203. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/oci/vcn/__init__.py +0 -0
  204. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/oci/vcn/info.py +0 -0
  205. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/oci/vm/__init__.py +0 -0
  206. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/oci/vm/info.py +0 -0
  207. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/oci/volume/__init__.py +0 -0
  208. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/oci/volume/info.py +0 -0
  209. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/ssh/__init__.py +0 -0
  210. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/ssh/auto/__init__.py +0 -0
  211. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/ssh/auto/scan.py +0 -0
  212. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/ssh/auto_ssh.py +0 -0
  213. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/ssh/server/__init__.py +0 -0
  214. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/ssh/server/info.py +0 -0
  215. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/ssh/server_info.py +0 -0
  216. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/tencent/__init__.py +0 -0
  217. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/tencent/clb/__init__.py +0 -0
  218. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/tencent/clb/desc.py +0 -0
  219. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/tencent/clb/info.py +0 -0
  220. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/tencent/clb/traffic.py +0 -0
  221. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/tencent/client.py +0 -0
  222. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/tencent/cvm/__init__.py +0 -0
  223. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/tencent/cvm/desc.py +0 -0
  224. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/tencent/cvm/info.py +0 -0
  225. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/tencent/lighthouse/__init__.py +0 -0
  226. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/tencent/lighthouse/info.py +0 -0
  227. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/tencent/nat/__init__.py +0 -0
  228. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/tencent/nat/info.py +0 -0
  229. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/tencent/profile/__init__.py +0 -0
  230. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/tencent/profile/info.py +0 -0
  231. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/tencent/sg/__init__.py +0 -0
  232. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/tencent/sg/info.py +0 -0
  233. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/tencent/tke/__init__.py +0 -0
  234. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/tencent/tke/info.py +0 -0
  235. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/tencent/vpc/__init__.py +0 -0
  236. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/platforms/tencent/vpc/info.py +0 -0
  237. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/security/__init__.py +0 -0
  238. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/security/config.py +0 -0
  239. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/security/detector.py +0 -0
  240. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/security/guidance.py +0 -0
  241. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/security/hooks.py +0 -0
  242. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/security/patterns.py +0 -0
  243. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic/security/scanner.py +0 -0
  244. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic_code.egg-info/SOURCES.txt +0 -0
  245. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic_code.egg-info/dependency_links.txt +0 -0
  246. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic_code.egg-info/entry_points.txt +0 -0
  247. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic_code.egg-info/requires.txt +0 -0
  248. {ic_code-1.5.0 → ic_code-1.5.2}/src/ic_code.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ic-code
3
- Version: 1.5.0
3
+ Version: 1.5.2
4
4
  Summary: Infrastructure CLI tool for managing AWS, GCP, OCI, CloudFlare, SSH, and more
5
5
  Home-page: https://github.com/dgr009/ic
6
6
  Author: SangYun Kim
@@ -147,7 +147,7 @@ A comprehensive, production-grade Infrastructure Command Line Interface tool for
147
147
  - **Networking**: VPC, Subnets, NAT Gateways, CLB (Load Balancers - listener rules, health check, target health analysis & network traffic bandwidth statistics), Security Groups (with Ingress/Egress rules & tree view)
148
148
  - **Authentication**: Multi-account STS AssumeRole support, Profile management (`ic tencent profile info` via `~/.tencent/credentials`)
149
149
 
150
- ### 3. 🟩 GCP Services (Production Ready - v1.5.0)
150
+ ### 3. 🟩 GCP Services (Production Ready - v1.5.2)
151
151
  - **Compute Engine**: VM instances with status, zone, machine type (custom parsing), vCPU, memory, disks, IPs, tags, and verbose 15-column output (`ic gcp compute info -v`)
152
152
  - **Compute Detailed Inspection (`desc`)**: Full attribute discovery, dot-notation key filtering (`-k / --keys`), schema discovery (`-l / --list-keys`) for instances
153
153
  - **Load Balancing (LB)**: Forwarding rules, Target proxies, URL maps, Backend services, Health checks, and SSL certificates (`ic gcp lb info`)
@@ -336,7 +336,7 @@ ic tencent tke info
336
336
  ic tencent profile info
337
337
  ```
338
338
 
339
- ### GCP Commands (v1.5.0)
339
+ ### GCP Commands (v1.5.2)
340
340
 
341
341
  ```bash
342
342
  # Compute Engine VM instances (summary & verbose 15-column output)
@@ -41,7 +41,7 @@ A comprehensive, production-grade Infrastructure Command Line Interface tool for
41
41
  - **Networking**: VPC, Subnets, NAT Gateways, CLB (Load Balancers - listener rules, health check, target health analysis & network traffic bandwidth statistics), Security Groups (with Ingress/Egress rules & tree view)
42
42
  - **Authentication**: Multi-account STS AssumeRole support, Profile management (`ic tencent profile info` via `~/.tencent/credentials`)
43
43
 
44
- ### 3. 🟩 GCP Services (Production Ready - v1.5.0)
44
+ ### 3. 🟩 GCP Services (Production Ready - v1.5.2)
45
45
  - **Compute Engine**: VM instances with status, zone, machine type (custom parsing), vCPU, memory, disks, IPs, tags, and verbose 15-column output (`ic gcp compute info -v`)
46
46
  - **Compute Detailed Inspection (`desc`)**: Full attribute discovery, dot-notation key filtering (`-k / --keys`), schema discovery (`-l / --list-keys`) for instances
47
47
  - **Load Balancing (LB)**: Forwarding rules, Target proxies, URL maps, Backend services, Health checks, and SSL certificates (`ic gcp lb info`)
@@ -230,7 +230,7 @@ ic tencent tke info
230
230
  ic tencent profile info
231
231
  ```
232
232
 
233
- ### GCP Commands (v1.5.0)
233
+ ### GCP Commands (v1.5.2)
234
234
 
235
235
  ```bash
236
236
  # Compute Engine VM instances (summary & verbose 15-column output)
@@ -1,6 +1,6 @@
1
1
  # GCP Platform Documentation
2
2
 
3
- This directory contains documentation for the GCP (Google Cloud Platform) integration in IC CLI (v1.5.0).
3
+ This directory contains documentation for the GCP (Google Cloud Platform) integration in IC CLI (v1.5.2).
4
4
 
5
5
  ---
6
6
 
@@ -12,7 +12,7 @@ This directory contains documentation for the GCP (Google Cloud Platform) integr
12
12
 
13
13
  ---
14
14
 
15
- ## Services Supported (v1.5.0)
15
+ ## Services Supported (v1.5.2)
16
16
 
17
17
  | Service | Commands | Key Features |
18
18
  |---|---|---|
@@ -47,7 +47,7 @@ ic config show
47
47
  - **VPC / NAT / TKE**: `ic tencent vpc info` / `ic tencent nat info` / `ic tencent tke info`
48
48
  - **자격 증명 확인**: `ic tencent profile info`
49
49
 
50
- ### 3. 🟩 GCP Services (v1.5.0)
50
+ ### 3. 🟩 GCP Services (v1.5.2)
51
51
  - **Compute Engine (요약 & 15개 컬럼 상세 & desc)**:
52
52
  - `ic gcp compute info`: 기본 요약 목록
53
53
  - `ic gcp compute info -v`: 상세 15열 뷰 (vCPU, Mem, Disks, Net/Subnet, Tags 등)
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ic-code"
7
- version = "1.5.0"
7
+ version = "1.5.2"
8
8
  authors = [
9
9
  {name = "sykim", email = "cruiser594@gmail.com"},
10
10
  ]
@@ -13,8 +13,9 @@ from google.cloud.resourcemanager_v3.types import SearchProjectsRequest, GetProj
13
13
  from google.api_core import exceptions as gcp_exceptions
14
14
  from google.api_core import retry
15
15
  from ic.config.manager import ConfigManager
16
+ from common.progress_decorator import ManualProgress
16
17
 
17
- from .log import log_info, log_info_non_console, log_error, log_exception
18
+ from .log import log_info, log_info_non_console, log_error, log_error_file_only, log_exception
18
19
 
19
20
  # Import configuration validator
20
21
  try:
@@ -327,13 +328,13 @@ class GCPProjectManager:
327
328
  return project.state.name == "ACTIVE"
328
329
 
329
330
  except gcp_exceptions.NotFound:
330
- log_error(f"프로젝트를 찾을 수 없음: {project_id}")
331
+ log_info_non_console(f"프로젝트를 찾을 수 없음: {project_id}")
331
332
  return False
332
333
  except gcp_exceptions.PermissionDenied:
333
- log_error(f"프로젝트 접근 권한 없음: {project_id}")
334
+ log_info_non_console(f"프로젝트 접근 권한 없음: {project_id}")
334
335
  return False
335
336
  except Exception as e:
336
- log_error(f"프로젝트 접근 검증 실패: {project_id}, Error={e}")
337
+ log_info_non_console(f"프로젝트 접근 검증 실패: {project_id}, Error={e}")
337
338
  return False
338
339
 
339
340
  def get_project_info(self, project_id: str) -> Optional[Dict[str, Any]]:
@@ -360,7 +361,7 @@ class GCPProjectManager:
360
361
  }
361
362
 
362
363
  except Exception as e:
363
- log_error(f"프로젝트 정보 조회 실패: {project_id}, Error={e}")
364
+ log_info_non_console(f"프로젝트 정보 조회 실패: {project_id}, Error={e}")
364
365
  return None
365
366
 
366
367
 
@@ -377,27 +378,34 @@ class GCPResourceCollector:
377
378
  def parallel_collect(self, projects: List[str], collect_func: Callable, *args, **kwargs) -> List[Any]:
378
379
  """여러 프로젝트에서 병렬로 리소스를 수집합니다."""
379
380
  results = []
381
+ progress_desc = kwargs.pop('progress_desc', None) or f"Collecting GCP resources across {len(projects)} project(s)"
380
382
 
381
- with ThreadPoolExecutor(max_workers=_get_env_int('GCP_MAX_WORKERS', 10)) as executor:
382
- futures = []
383
-
384
- for project_id in projects:
385
- future = executor.submit(
386
- self._safe_collect, collect_func, project_id, *args, **kwargs
387
- )
388
- futures.append((future, project_id))
389
-
390
- for future, project_id in futures:
391
- try:
392
- result = future.result(timeout=_get_env_int('GCP_REQUEST_TIMEOUT', 30))
393
- if result:
394
- if isinstance(result, list):
395
- results.extend(result)
383
+ with ManualProgress(progress_desc, total=len(projects)) as progress:
384
+ with ThreadPoolExecutor(max_workers=_get_env_int('GCP_MAX_WORKERS', 10)) as executor:
385
+ futures = []
386
+
387
+ for project_id in projects:
388
+ future = executor.submit(
389
+ self._safe_collect, collect_func, project_id, *args, **kwargs
390
+ )
391
+ futures.append((future, project_id))
392
+
393
+ for future, project_id in futures:
394
+ try:
395
+ result = future.result(timeout=_get_env_int('GCP_REQUEST_TIMEOUT', 30))
396
+ if result:
397
+ if isinstance(result, list):
398
+ results.extend(result)
399
+ else:
400
+ results.append(result)
401
+ item_count = len(result) if isinstance(result, list) else 1
402
+ progress.update(f"Processed {project_id} ({item_count} items)", advance=1)
396
403
  else:
397
- results.append(result)
398
- except Exception as e:
399
- err_msg = str(e) or type(e).__name__
400
- log_error(f"프로젝트 {project_id}에서 리소스 수집 실패: {err_msg}")
404
+ progress.update(f"Processed {project_id} (0 items)", advance=1)
405
+ except Exception as e:
406
+ err_msg = str(e) or type(e).__name__
407
+ log_info_non_console(f"프로젝트 {project_id}에서 리소스 수집 실패: {err_msg}")
408
+ progress.update(f"Failed {project_id} - {err_msg[:40]}", advance=1)
401
409
 
402
410
  return results
403
411
 
@@ -406,7 +414,7 @@ class GCPResourceCollector:
406
414
  try:
407
415
  return self.handle_api_errors(lambda: collect_func(project_id, *args, **kwargs))
408
416
  except Exception as e:
409
- log_error(f"리소스 수집 중 오류 발생: Project={project_id}, Error={e}")
417
+ log_info_non_console(f"리소스 수집 중 오류 발생: Project={project_id}, Error={e}")
410
418
  return None
411
419
 
412
420
  def handle_api_errors(self, func: Callable) -> Any:
@@ -429,19 +437,19 @@ class GCPResourceCollector:
429
437
  try:
430
438
  return _retry_func()
431
439
  except gcp_exceptions.PermissionDenied as e:
432
- log_error(f"권한 거부: {e}")
440
+ log_info_non_console(f"권한 거부: {e}")
433
441
  raise
434
442
  except gcp_exceptions.NotFound as e:
435
- log_error(f"리소스를 찾을 수 없음: {e}")
443
+ log_info_non_console(f"리소스를 찾을 수 없음: {e}")
436
444
  return None
437
445
  except gcp_exceptions.Forbidden as e:
438
- log_error(f"API가 비활성화되었거나 접근 금지: {e}")
446
+ log_info_non_console(f"API가 비활성화되었거나 접근 금지: {e}")
439
447
  return None
440
448
  except gcp_exceptions.TooManyRequests as e:
441
- log_error(f"API 요청 한도 초과: {e}")
449
+ log_info_non_console(f"API 요청 한도 초과: {e}")
442
450
  raise
443
451
  except Exception as e:
444
- log_error(f"예상치 못한 API 오류: {e}")
452
+ log_info_non_console(f"예상치 못한 API 오류: {e}")
445
453
  raise
446
454
 
447
455
  def apply_filters(self, resources: List[Dict], filters: Dict[str, Any]) -> List[Dict]:
@@ -68,6 +68,13 @@ def log_info(message: str):
68
68
  if os.environ.get("IC_VERBOSE") == "true":
69
69
  console.print(f"[bold cyan]INFO:[/bold cyan] {message}")
70
70
 
71
+ def log_error_file_only(message: str):
72
+ """ERROR 레벨 로그 출력 + 콘솔 미표시 (파일 전용)"""
73
+ if NEW_LOGGING_AVAILABLE and ic_logger:
74
+ ic_logger.log_error_file_only(message)
75
+ else:
76
+ logger.error(message)
77
+
71
78
  def log_error(message: str):
72
79
  """ERROR 레벨 로그 출력 + 콘솔 표시"""
73
80
  if NEW_LOGGING_AVAILABLE and ic_logger:
@@ -4,7 +4,7 @@ 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.5.0"
7
+ __version__ = "1.5.2"
8
8
  __author__ = "SangYun"
9
9
  __email__ = "cruiser594@gmail.com"
10
10
 
@@ -36,6 +36,18 @@ def log_error(message: str, **kwargs) -> None:
36
36
  logger.log_error(message)
37
37
 
38
38
 
39
+ def log_error_file_only(message: str, **kwargs) -> None:
40
+ """
41
+ Backward compatibility function for log_error_file_only.
42
+
43
+ Args:
44
+ message: Error message to log to file
45
+ **kwargs: Additional keyword arguments (ignored for compatibility)
46
+ """
47
+ logger = get_logger()
48
+ logger.log_error_file_only(message)
49
+
50
+
39
51
  def log_env_short(env_dict=None, **kwargs) -> None:
40
52
  """
41
53
  Backward compatibility function for log_env_short.
@@ -72,7 +84,7 @@ def log_args_short(args: Any) -> None:
72
84
  logger.log_args(args)
73
85
 
74
86
 
75
- def gather_env_for_command(platform: str, service: str = None, command: str = None) -> Dict[str, Any]:
87
+ def gather_env_for_command(platform: str, service: Optional[str] = None, command: Optional[str] = None) -> Dict[str, Any]:
76
88
  """
77
89
  Backward compatibility function for gather_env_for_command.
78
90
 
@@ -124,7 +136,7 @@ class GatherEnvCompat:
124
136
  """Compatibility class for common.gather_env module."""
125
137
 
126
138
  @staticmethod
127
- def gather_env_for_command(platform: str, service: str = None, command: str = None) -> Dict[str, Any]:
139
+ def gather_env_for_command(platform: str, service: Optional[str] = None, command: Optional[str] = None) -> Dict[str, Any]:
128
140
  """Gather environment for command."""
129
141
  return gather_env_for_command(platform, service, command)
130
142
 
@@ -135,7 +147,7 @@ gather_env_compat = GatherEnvCompat()
135
147
 
136
148
 
137
149
  # Utility functions for AWS session compatibility
138
- def get_aws_session_compat(account_id: str, region: str = None):
150
+ def get_aws_session_compat(account_id: str, region: Optional[str] = None):
139
151
  """
140
152
  Backward compatibility function for AWS session creation.
141
153
 
@@ -199,8 +211,8 @@ def get_gcp_client_compat(service_type: str):
199
211
 
200
212
  # Import GCP utilities if available
201
213
  try:
202
- from common.gcp_utils import get_gcp_client
203
- return get_gcp_client(service_type)
214
+ from common.gcp_utils import create_gcp_client
215
+ return create_gcp_client(service_type)
204
216
  except ImportError:
205
217
  raise ImportError("GCP utilities not available. Please install google-cloud dependencies.")
206
218
 
@@ -208,6 +220,7 @@ def get_gcp_client_compat(service_type: str):
208
220
  # Export compatibility functions
209
221
  __all__ = [
210
222
  'log_error',
223
+ 'log_error_file_only',
211
224
  'log_env_short',
212
225
  'log_args_short',
213
226
  'gather_env_for_command',
@@ -123,8 +123,10 @@ class ICLogger:
123
123
  console_formatter = logging.Formatter('%(message)s')
124
124
  console_handler.setFormatter(console_formatter)
125
125
 
126
- # Add filter to suppress non-ERROR messages on console
126
+ # Add filter to suppress non-ERROR messages and file-only messages on console
127
127
  def error_only_filter(record):
128
+ if getattr(record, "file_only", False):
129
+ return False
128
130
  return record.levelno >= logging.ERROR
129
131
 
130
132
  console_handler.addFilter(error_only_filter)
@@ -138,7 +140,9 @@ class ICLogger:
138
140
  encoding='utf-8'
139
141
  )
140
142
  file_handler.setLevel(self.file_level)
141
- file_formatter = logging.Formatter(self.log_format)
143
+ file_formatter = logging.Formatter(
144
+ '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
145
+ )
142
146
  file_handler.setFormatter(file_formatter)
143
147
  logger.addHandler(file_handler)
144
148
 
@@ -152,31 +156,27 @@ class ICLogger:
152
156
  # Use security manager to mask sensitive data
153
157
  return self.security_manager.mask_sensitive_in_text(message)
154
158
 
155
- def log_args(self, args: Union[Dict[str, Any], object]) -> None:
159
+ def log_args(self, args: Any) -> None:
156
160
  """
157
- Display command arguments on console and log to file.
161
+ Log command arguments with sensitive data masking.
162
+ Only logs to file, never to console.
158
163
 
159
164
  Args:
160
- args: Arguments dictionary or argparse Namespace object
165
+ args: Command line arguments namespace or dict
161
166
  """
162
- # Convert args to dictionary if it's an object
167
+ if not args:
168
+ return
169
+
170
+ args_dict = {}
163
171
  if hasattr(args, '__dict__'):
164
- args_dict = {k: v for k, v in vars(args).items()
165
- if not k.startswith('_') and k != 'func'}
166
- else:
167
- args_dict = dict(args) if isinstance(args, dict) else {}
168
-
169
- # Format arguments for display
170
- pretty_args = {k: (v if v is not None else "default")
171
- for k, v in args_dict.items()}
172
+ args_dict = {k: v for k, v in vars(args).items() if not k.startswith('_') and k != 'func'}
173
+ elif isinstance(args, dict):
174
+ args_dict = {k: v for k, v in args.items() if not k.startswith('_')}
175
+
176
+ # Format arguments nicely
177
+ pretty_args = {k: (v if v is not None else "default") for k, v in args_dict.items()}
172
178
  args_str = ", ".join(f"{k}={v}" for k, v in pretty_args.items())
173
179
 
174
- # Console output for args (always shown regardless of log level)
175
- if self.console and RICH_AVAILABLE:
176
- self.console.print(f"[bold cyan]Args:[/bold cyan] {args_str}")
177
- else:
178
- print(f"Args: {args_str}")
179
-
180
180
  # File logging with masking
181
181
  masked_args_str = self._mask_message(f"Args: {args_str}")
182
182
  self.logger.info(masked_args_str)
@@ -191,6 +191,16 @@ class ICLogger:
191
191
  masked_message = self._mask_message(message)
192
192
  self.logger.info(masked_message)
193
193
 
194
+ def log_error_file_only(self, message: str) -> None:
195
+ """
196
+ Log ERROR message to file only (not console).
197
+
198
+ Args:
199
+ message: Error message to log to file
200
+ """
201
+ masked_message = self._mask_message(message)
202
+ self.logger.error(masked_message, extra={"file_only": True})
203
+
194
204
  def log_error(self, message: str) -> None:
195
205
  """
196
206
  Log ERROR message to both console and file.
@@ -200,12 +210,6 @@ class ICLogger:
200
210
  """
201
211
  masked_message = self._mask_message(message)
202
212
  self.logger.error(masked_message)
203
-
204
- # Also display on console with Rich formatting if available
205
- if self.console and RICH_AVAILABLE:
206
- self.console.print(f"[bold red]ERROR:[/bold red] {message}")
207
- else:
208
- print(f"ERROR: {message}")
209
213
 
210
214
  def log_critical(self, message: str) -> None:
211
215
  """
@@ -216,12 +220,6 @@ class ICLogger:
216
220
  """
217
221
  masked_message = self._mask_message(message)
218
222
  self.logger.critical(masked_message)
219
-
220
- # Also display on console with Rich formatting if available
221
- if self.console and RICH_AVAILABLE:
222
- self.console.print(f"[bold red]CRITICAL:[/bold red] {message}")
223
- else:
224
- print(f"CRITICAL: {message}")
225
223
 
226
224
  def log_warning(self, message: str) -> None:
227
225
  """