{"id":47630021,"url":"https://github.com/cleancloud-io/scan-action","last_synced_at":"2026-04-07T22:01:19.926Z","repository":{"id":346027167,"uuid":"1176102245","full_name":"cleancloud-io/scan-action","owner":"cleancloud-io","description":"GitHub Action for CleanCloud — read-only cloud hygiene scanner for AWS, Azure and GCP","archived":false,"fork":false,"pushed_at":"2026-03-30T20:05:30.000Z","size":16,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-02T07:29:46.900Z","etag":null,"topics":["aws","azure","cloud","cloud-computing","cost-optimization","devops","finops","hygiene","sre"],"latest_commit_sha":null,"homepage":"https://www.getcleancloud.com","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/cleancloud-io.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-08T16:11:47.000Z","updated_at":"2026-03-30T20:05:47.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/cleancloud-io/scan-action","commit_stats":null,"previous_names":["cleancloud-io/scan-action"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/cleancloud-io/scan-action","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cleancloud-io%2Fscan-action","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cleancloud-io%2Fscan-action/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cleancloud-io%2Fscan-action/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cleancloud-io%2Fscan-action/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cleancloud-io","download_url":"https://codeload.github.com/cleancloud-io/scan-action/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cleancloud-io%2Fscan-action/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31530647,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-07T16:28:08.000Z","status":"ssl_error","status_checked_at":"2026-04-07T16:28:06.951Z","response_time":105,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aws","azure","cloud","cloud-computing","cost-optimization","devops","finops","hygiene","sre"],"created_at":"2026-04-01T23:17:08.772Z","updated_at":"2026-04-07T22:01:19.916Z","avatar_url":"https://github.com/cleancloud-io.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# CleanCloud Scan Action\n\nGitHub Action for [CleanCloud](https://github.com/cleancloud-io/cleancloud) — a read-only cloud hygiene scanner for AWS, Azure, and GCP that finds orphaned resources, detects idle AI/ML waste ($500–$23K/month per endpoint), and enforces policy-as-code in CI.\n\n## Usage\n\n### AWS — single account (OIDC)\n\n```yaml\n- uses: aws-actions/configure-aws-credentials@v4\n  with:\n    role-to-assume: arn:aws:iam::${{ vars.AWS_ACCOUNT_ID }}:role/CleanCloudCIReadOnly\n    aws-region: us-east-1\n\n- uses: cleancloud-io/scan-action@v1\n  with:\n    provider: aws\n    all-regions: 'true'\n    fail-on-confidence: HIGH\n    fail-on-cost: '100'\n    output: json\n    output-file: scan-results.json\n```\n\n### AWS — all accounts in an Organization\n\n```yaml\n- uses: aws-actions/configure-aws-credentials@v4\n  with:\n    role-to-assume: arn:aws:iam::${{ vars.AWS_ACCOUNT_ID }}:role/CleanCloudCIReadOnly\n    aws-region: us-east-1\n\n- uses: cleancloud-io/scan-action@v1\n  with:\n    provider: aws\n    org: 'true'\n    all-regions: 'true'\n    fail-on-confidence: HIGH\n    output: json\n    output-file: scan-results.json\n```\n\n### AWS — specific accounts (inline)\n\n```yaml\n- uses: cleancloud-io/scan-action@v1\n  with:\n    provider: aws\n    accounts: '111111111111,222222222222,333333333333'\n    all-regions: 'true'\n    output: json\n    output-file: scan-results.json\n```\n\n### AWS — specific accounts (config file)\n\n```yaml\n- uses: cleancloud-io/scan-action@v1\n  with:\n    provider: aws\n    multi-account: .cleancloud/accounts.yaml\n    all-regions: 'true'\n    output: json\n    output-file: scan-results.json\n```\n\n### Azure — single subscription (Workload Identity)\n\n```yaml\n- uses: azure/login@v2\n  with:\n    client-id: ${{ secrets.AZURE_CLIENT_ID }}\n    tenant-id: ${{ secrets.AZURE_TENANT_ID }}\n    subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}\n\n- uses: cleancloud-io/scan-action@v1\n  with:\n    provider: azure\n    fail-on-confidence: HIGH\n    fail-on-cost: '100'\n    output: json\n    output-file: scan-results.json\n```\n\n### Azure — all subscriptions under a Management Group\n\n```yaml\n- uses: azure/login@v2\n  with:\n    client-id: ${{ secrets.AZURE_CLIENT_ID }}\n    tenant-id: ${{ secrets.AZURE_TENANT_ID }}\n    subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}\n\n- uses: cleancloud-io/scan-action@v1\n  with:\n    provider: azure\n    management-group: my-management-group-id\n    fail-on-confidence: HIGH\n    output: json\n    output-file: scan-results.json\n```\n\n### Azure — specific subscriptions\n\n```yaml\n- uses: cleancloud-io/scan-action@v1\n  with:\n    provider: azure\n    subscription: 'xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx, yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy'\n    fail-on-confidence: HIGH\n    output: json\n    output-file: scan-results.json\n```\n\n### GCP — all projects (Workload Identity Federation)\n\n```yaml\n- uses: google-github-actions/auth@v2\n  with:\n    workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}\n    service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }}\n\n- uses: cleancloud-io/scan-action@v1\n  with:\n    provider: gcp\n    all-projects: 'true'\n    fail-on-confidence: HIGH\n    fail-on-cost: '100'\n    output: json\n    output-file: scan-results.json\n```\n\n### GCP — single project\n\n```yaml\n- uses: google-github-actions/auth@v2\n  with:\n    workload_identity_provider: ${{ secrets.GCP_WORKLOAD_IDENTITY_PROVIDER }}\n    service_account: ${{ secrets.GCP_SERVICE_ACCOUNT }}\n\n- uses: cleancloud-io/scan-action@v1\n  with:\n    provider: gcp\n    project: my-gcp-project-id\n    fail-on-confidence: HIGH\n    output: json\n    output-file: scan-results.json\n```\n\n### GCP — specific projects (comma-separated)\n\n```yaml\n- uses: cleancloud-io/scan-action@v1\n  with:\n    provider: gcp\n    project: 'project-id-1, project-id-2, project-id-3'\n    fail-on-confidence: HIGH\n    output: json\n    output-file: scan-results.json\n```\n\n### AI/ML waste detection — AWS (SageMaker)\n\nDetect idle SageMaker endpoints with zero invocations. GPU-backed endpoints flagged HIGH risk ($500–$23K/month).\n\n```yaml\n- uses: cleancloud-io/scan-action@v1\n  with:\n    provider: aws\n    all-regions: 'true'\n    category: ai\n    fail-on-confidence: HIGH\n    output: json\n    output-file: scan-results.json\n```\n\n### AI/ML waste detection — Azure (AML compute clusters)\n\n```yaml\n- uses: cleancloud-io/scan-action@v1\n  with:\n    provider: azure\n    category: ai\n    fail-on-confidence: HIGH\n    output: json\n    output-file: scan-results.json\n```\n\n### AI/ML waste detection — GCP (Vertex AI endpoints)\n\n```yaml\n- uses: cleancloud-io/scan-action@v1\n  with:\n    provider: gcp\n    all-projects: 'true'\n    category: ai\n    fail-on-confidence: HIGH\n    output: json\n    output-file: scan-results.json\n```\n\n### Hygiene + AI/ML together\n\n```yaml\n- uses: cleancloud-io/scan-action@v1\n  with:\n    provider: aws\n    org: 'true'\n    all-regions: 'true'\n    category: all\n    fail-on-confidence: HIGH\n    fail-on-cost: '500'\n    output: json\n    output-file: scan-results.json\n```\n\n### With policy-as-code config\n\nCommit a `cleancloud.yaml` to your repo — exceptions, thresholds, and tag filtering are picked up automatically:\n\n```yaml\n- uses: actions/checkout@v4   # required so cleancloud.yaml is available\n\n- uses: cleancloud-io/scan-action@v1\n  with:\n    provider: aws\n    all-regions: 'true'\n    # config auto-detected from cleancloud.yaml in repo root\n    # or pass explicitly:\n    # config: configs/prod.yaml\n    output: json\n    output-file: scan-results.json\n```\n\n`cleancloud.yaml` (committed to repo root):\n```yaml\ndefaults:\n  confidence: MEDIUM\n  min_cost: 10\nexceptions:\n  - rule_id: aws.ec2.instance.stopped\n    resource_id: i-0abc1234567890def\n    reason: \"Bastion host — started on demand\"\n    expires_at: \"2026-12-31\"\nthresholds:\n  fail_on_confidence: HIGH\n  fail_on_cost: 500\n```\n\nSee [policy config reference](https://github.com/cleancloud-io/cleancloud/blob/main/docs/configuration.md) for full options.\n\n### Scan a specific region\n\n**AWS:**\n```yaml\n- uses: cleancloud-io/scan-action@v1\n  with:\n    provider: aws\n    region: us-east-1\n    fail-on-confidence: HIGH\n    output: json\n    output-file: scan-results.json\n```\n\n**Azure** (`region` is optional — omit to scan all locations):\n```yaml\n- uses: cleancloud-io/scan-action@v1\n  with:\n    provider: azure\n    region: westeurope\n    fail-on-confidence: HIGH\n    output: json\n    output-file: scan-results.json\n```\n\n## Inputs\n\n### General\n\n| Input | Required | Default | Description |\n|-------|----------|---------|-------------|\n| `provider` | Yes | — | `aws`, `azure`, or `gcp` |\n| `category` | No | `hygiene` | `hygiene` (default), `ai` (SageMaker / AML / Vertex AI — all clouds), or `all` |\n| `region` | No | — | Specific region (AWS) or location filter (Azure, optional) |\n| `fail-on-confidence` | No | — | Fail if findings at or above this level: `LOW`, `MEDIUM`, or `HIGH` |\n| `fail-on-cost` | No | — | Fail if estimated monthly waste exceeds this USD amount |\n| `fail-on-findings` | No | `false` | Fail on any finding |\n| `output` | No | `human` | Output format: `human`, `json`, `csv`, or `markdown` |\n| `output-file` | No | — | Path to write output file (required for `json`/`csv`, optional for `markdown`) |\n| `artifact-name` | No | — | Upload the output file as a GitHub Actions artifact with this name. Leave empty to skip upload. |\n| `config` | No | — | Path to `cleancloud.yaml` config file. Auto-detected from repo root if omitted (requires `actions/checkout` first). |\n| `explain` | No | `false` | Print suppression reason for each filtered finding. Useful for debugging policy config. |\n| `skip` | No | — | Comma-separated rule IDs to skip. Example: `aws.ec2.ami.old,aws.resource.untagged` |\n| `ignore-tag` | No | — | Ignore findings by tag. Comma-separated `key` or `key:value` pairs. Example: `env:dev,temporary` |\n| `version` | No | latest | CleanCloud version to install (e.g. `1.7.2`) |\n\n### AWS\n\n| Input | Required | Default | Description |\n|-------|----------|---------|-------------|\n| `all-regions` | One of `all-regions` or `region` required | `false` | Scan all active regions |\n| `org` | No | `false` | Auto-discover and scan all accounts in your AWS Organization. Requires `organizations:ListAccounts` on the hub role. |\n| `accounts` | No | — | Comma-separated AWS account IDs to scan. Example: `111111111111,222222222222` |\n| `multi-account` | No | — | Path to accounts config file. Example: `.cleancloud/accounts.yaml` |\n| `role-name` | No | `CleanCloudReadOnlyRole` | IAM role name to assume in each spoke account |\n| `external-id` | No | — | External ID for cross-account role assumption, if required by the spoke trust policy |\n| `concurrency` | No | `3` | Number of accounts to scan in parallel. Keep low to avoid API throttling. |\n| `timeout` | No | `3600` | Total scan timeout in seconds across all accounts |\n| `per-account-regions` | No | `false` | Detect active regions per account instead of once on the hub. Slower but accurate if accounts use different regions. |\n\n\u003e `org`, `accounts`, and `multi-account` are mutually exclusive — use only one.\n\n### Azure\n\n| Input | Required | Default | Description |\n|-------|----------|---------|-------------|\n| `subscription` | No | — | Comma-separated subscription IDs to scan. Omit to scan all accessible subscriptions. |\n| `management-group` | No | — | Management Group ID — auto-discovers all subscriptions underneath. |\n\n\u003e `subscription` and `management-group` are mutually exclusive — use only one.\n\n### GCP\n\n| Input | Required | Default | Description |\n|-------|----------|---------|-------------|\n| `project` | No | — | Comma-separated GCP project IDs to scan. Omit to use the default project from credentials. |\n| `all-projects` | No | `false` | Scan all accessible GCP projects. Requires `roles/browser` on the service account. |\n\n\u003e `project` and `all-projects` are mutually exclusive — use only one.\n\n## Exit Codes\n\n| Code | Meaning |\n|------|---------|\n| `0` | No policy violations |\n| `1` | Configuration error or unexpected failure |\n| `2` | Policy violation — findings detected (when enforcement enabled) |\n| `3` | Missing credentials or insufficient permissions |\n\n## How it works\n\nThis action installs CleanCloud from PyPI and runs it directly on the runner. For Docker-based CI, use the [Docker image](https://hub.docker.com/r/getcleancloud/cleancloud) directly instead of this action.\n\n## Authentication\n\nCleanCloud is read-only — it never creates, modifies, or deletes resources. Set up authentication before calling this action:\n\n- **AWS:** Use [`aws-actions/configure-aws-credentials`](https://github.com/aws-actions/configure-aws-credentials) with OIDC. See [AWS setup guide](https://github.com/cleancloud-io/cleancloud/blob/main/docs/aws.md).\n- **Azure:** Use [`azure/login`](https://github.com/Azure/login) with Workload Identity Federation. See [Azure setup guide](https://github.com/cleancloud-io/cleancloud/blob/main/docs/azure.md).\n- **GCP:** Use [`google-github-actions/auth`](https://github.com/google-github-actions/auth) with Workload Identity Federation. See [GCP setup guide](https://github.com/cleancloud-io/cleancloud/blob/main/docs/gcp.md).\n\n## Versioning\n\nThis action installs the latest CleanCloud from PyPI by default. To pin a specific version:\n\n```yaml\n- uses: cleancloud-io/scan-action@v1\n  with:\n    provider: aws\n    version: '1.9.0'\n```\n\n## As featured in\n\n- [Korben](https://korben.info/cleancloud-nettoyeur-cloud-aws-azure.html) 🇫🇷 — Major French tech publication\n- [Last Week in AWS #457](https://www.lastweekinaws.com/newsletter/15259/) — Corey Quinn's weekly AWS newsletter\n\n## Links\n\n- [CleanCloud CLI](https://github.com/cleancloud-io/cleancloud)\n- [CI/CD guide](https://github.com/cleancloud-io/cleancloud/blob/main/docs/ci.md)\n- [Detection rules](https://github.com/cleancloud-io/cleancloud/blob/main/docs/rules.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcleancloud-io%2Fscan-action","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcleancloud-io%2Fscan-action","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcleancloud-io%2Fscan-action/lists"}