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.
- {ic_code-1.6.1/src/ic_code.egg-info → ic_code-1.7.1}/PKG-INFO +5 -10
- {ic_code-1.6.1 → ic_code-1.7.1}/docs/aws/README.md +28 -27
- {ic_code-1.6.1 → ic_code-1.7.1}/docs/tencent/README.md +5 -2
- {ic_code-1.6.1 → ic_code-1.7.1}/pyproject.toml +4 -4
- {ic_code-1.6.1 → ic_code-1.7.1}/requirements.txt +3 -1
- {ic_code-1.6.1 → ic_code-1.7.1}/scripts/ci-detect-platforms.py +103 -49
- {ic_code-1.6.1 → ic_code-1.7.1}/scripts/ci-generate-matrix.py +30 -11
- ic_code-1.7.1/scripts/ci-smoke-test.sh +111 -0
- ic_code-1.7.1/setup.py +9 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/__init__.py +2 -2
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/cli.py +5 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/core/dependency_validator.py +7 -6
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/core/platform_discovery.py +11 -2
- ic_code-1.7.1/src/ic/platforms/aws/iam/_helpers.py +531 -0
- ic_code-1.7.1/src/ic/platforms/aws/iam/check.py +556 -0
- ic_code-1.7.1/src/ic/platforms/aws/iam/policy.py +828 -0
- ic_code-1.7.1/src/ic/platforms/aws/iam/role.py +643 -0
- ic_code-1.7.1/src/ic/platforms/aws/iam/user.py +836 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/compute/mock_data.json +6 -6
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/dns/mock_data.json +2 -2
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/gke/mock_data.json +3 -3
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/lb/mock_data.json +2 -2
- ic_code-1.7.1/src/ic/platforms/tencent/cam/_helpers.py +454 -0
- 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
- ic_code-1.7.1/src/ic/platforms/tencent/cam/policy.py +683 -0
- ic_code-1.7.1/src/ic/platforms/tencent/cam/role.py +639 -0
- ic_code-1.7.1/src/ic/platforms/tencent/cam/user.py +872 -0
- {ic_code-1.6.1 → ic_code-1.7.1/src/ic_code.egg-info}/PKG-INFO +5 -10
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic_code.egg-info/SOURCES.txt +8 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic_code.egg-info/requires.txt +1 -1
- ic_code-1.6.1/scripts/ci-smoke-test.sh +0 -83
- ic_code-1.6.1/setup.py +0 -237
- ic_code-1.6.1/src/ic/platforms/aws/iam/user.py +0 -559
- {ic_code-1.6.1 → ic_code-1.7.1}/LICENSE +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/MANIFEST.in +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/README.md +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/SECURITY.md +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/config/default.yaml +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/docs/README.md +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/docs/cloudflare/README.md +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/docs/gcp/README.md +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/docs/installation.md +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/docs/oci/README.md +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/docs/release-guide.md +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/docs/security.md +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/docs/ssh/README.md +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/docs/troubleshooting.md +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/docs/user_guide.md +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/scripts/bump-version.sh +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/scripts/cf_edge_nsg_make/cf_edge_nsg_make.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/scripts/deploy.sh +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/scripts/oracle-policy/user_policy.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/setup.cfg +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/common/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/common/gather_env.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/common/gcp_config_validator.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/common/gcp_monitoring.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/common/gcp_utils.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/common/log.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/common/progress_decorator.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/common/slack.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/common/utils.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/commands/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/commands/config.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/commands/security.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/compat/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/compat/cli.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/compat/common.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/config/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/config/cleanup.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/config/docs_organizer.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/config/external.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/config/installer.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/config/manager.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/config/migration.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/config/migration_utils.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/config/path_manager.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/config/schema.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/config/secrets.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/config/security.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/core/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/core/desc_helper.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/core/interfaces/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/core/interfaces/command.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/core/interfaces/formatter.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/core/interfaces/result.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/core/logging.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/core/session.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/core/silence_logging.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/cloudfront/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/cloudfront/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/codepipeline/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/codepipeline/build.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/codepipeline/deploy.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/disk/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/disk/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/ebs/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/ebs/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/ebs/mock_data.json +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/ec2/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/ec2/desc.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/ec2/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/ec2/list_tags.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/ec2/tag_check.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/ecs/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/ecs/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/ecs/service.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/ecs/task.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/eks/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/eks/addons.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/eks/fargate.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/eks/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/eks/nodes.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/eks/pods.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/eks/update_config.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/fargate/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/fargate/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/healthdashboard/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/healthdashboard/reboot.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/iam/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/lb/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/lb/desc.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/lb/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/lb/list_tags.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/lb/tag_check.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/msk/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/msk/broker.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/msk/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/nat/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/nat/list_tags.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/nat/tag_check.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/profile/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/profile/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/profile/switch.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/rds/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/rds/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/rds/list_tags.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/rds/tag_check.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/s3/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/s3/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/s3/list_tags.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/s3/tag_check.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/sg/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/sg/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/vpc/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/vpc/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/vpc/list_tags.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/vpc/tag_check.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/vpn/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/aws/vpn/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/account/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/account/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/client.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/dns/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/dns/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/dns/list_info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/rules/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/rules/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/traffic/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/traffic/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/waf/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/waf/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/zone/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/cloudflare/zone/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/billing/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/billing/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/billing/mock_data.json +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/compute/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/compute/desc.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/compute/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/disk/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/disk/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/disk/mock_data.json +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/dns/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/dns/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/firewall/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/firewall/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/firewall/mock_data.json +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/functions/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/functions/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/functions/mock_data.json +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/gke/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/gke/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/lb/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/lb/desc.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/lb/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/profile/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/profile/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/profile/mock_data.json +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/project/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/project/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/project/mock_data.json +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/run/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/run/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/run/mock_data.json +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/sql/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/sql/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/sql/mock_data.json +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/storage/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/storage/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/storage/mock_data.json +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/vpc/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/vpc/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/gcp/vpc/mock_data.json +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/common/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/common/utils.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/compartment/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/compartment/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/cost/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/cost/credit.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/cost/usage.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/info/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/info/oci_info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/lb/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/lb/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/nsg/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/nsg/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/obj/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/obj/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/policy/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/policy/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/policy/search.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/vcn/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/vcn/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/vm/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/vm/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/volume/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/oci/volume/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/ssh/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/ssh/auto/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/ssh/auto/scan.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/ssh/auto_ssh.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/ssh/policy.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/ssh/server/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/ssh/server/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/ssh/server_info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/cam/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/cbs/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/cbs/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/cbs/mock_data.json +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/clb/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/clb/desc.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/clb/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/clb/traffic.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/client.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/cvm/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/cvm/desc.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/cvm/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/disk/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/disk/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/lighthouse/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/lighthouse/firewall.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/lighthouse/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/nat/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/nat/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/profile/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/profile/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/profile/switch.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/sg/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/sg/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/tke/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/tke/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/vpc/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/platforms/tencent/vpc/info.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/security/__init__.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/security/config.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/security/detector.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/security/guidance.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/security/hooks.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/security/patterns.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic/security/scanner.py +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic_code.egg-info/dependency_links.txt +0 -0
- {ic_code-1.6.1 → ic_code-1.7.1}/src/ic_code.egg-info/entry_points.txt +0 -0
- {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.
|
|
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:
|
|
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<
|
|
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 -
|
|
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
|
|
63
|
+
### 4. IAM 자격증명 수명 점검 및 권한/정책/역할 관리 (`ic aws iam check|user|policy|role`)
|
|
64
64
|
|
|
65
|
-
AWS 계정 내 IAM
|
|
66
|
-
|
|
67
|
-
- **색상 규칙**: 90일 이상(빨강), 60~89일(노랑), 60일 이하(초록)
|
|
68
|
-
- **테이블 스타일**: 동일 계정 내 중복 셀 줄 삭제 및 프로필 명칭 그룹화 (`box.HORIZONTALS`)
|
|
65
|
+
AWS 계정 내 IAM 자격증명 수명 검사(`check`), 사용자별 적용된 그룹/정책/역할 매핑(`user`), 정책 및 연결 엔티티 조회(`policy`), 역할 및 신뢰 주체 조회(`role`) 기능을 제공합니다.
|
|
69
66
|
|
|
70
67
|
```bash
|
|
71
|
-
#
|
|
72
|
-
ic aws iam
|
|
73
|
-
|
|
74
|
-
#
|
|
75
|
-
ic aws iam
|
|
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
|
-
#
|
|
82
|
-
ic aws iam user
|
|
83
|
-
ic aws iam user -
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
ic aws iam user -
|
|
87
|
-
|
|
88
|
-
#
|
|
89
|
-
ic aws iam
|
|
90
|
-
|
|
91
|
-
#
|
|
92
|
-
ic aws iam
|
|
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
|
-
- **
|
|
50
|
-
-
|
|
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.
|
|
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,<
|
|
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,<
|
|
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
|
|
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
|
|
74
|
+
if re.search(r"\[(all|test-all)\]", commit_msg, re.IGNORECASE):
|
|
49
75
|
return list(all_platforms)
|
|
50
|
-
|
|
51
|
-
#
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
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
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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
|
-
|
|
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_*{
|
|
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(
|
|
87
|
-
print(f"
|
|
125
|
+
platforms_with_tests.append(norm)
|
|
126
|
+
print(f"Platform {norm} has {len(all_tests)} test files")
|
|
88
127
|
else:
|
|
89
|
-
print(f"
|
|
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
|
-
#
|
|
96
|
-
ALL_PLATFORMS =
|
|
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"
|
|
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"
|
|
121
|
-
|
|
122
|
-
#
|
|
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
|
|
125
|
-
detected_platforms =
|
|
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
|
|
131
|
-
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
|
-
|
|
136
|
-
|
|
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"
|
|
15
|
-
platforms_str = os.environ.get(
|
|
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
|
-
|
|
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
|
-
|
|
25
|
-
|
|
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
|
@@ -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.
|
|
8
|
-
__author__ = "
|
|
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
|
|