nuvu-scan 2.1.2__tar.gz → 2.1.6__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 (77) hide show
  1. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/.gitignore +3 -0
  2. nuvu_scan-2.1.6/DEVELOPMENT_STATUS.md +216 -0
  3. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/PKG-INFO +5 -1
  4. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/README.md +4 -0
  5. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/cli/commands/scan.py +2 -0
  6. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/core/base.py +10 -0
  7. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/core/providers/aws/aws_scanner.py +135 -6
  8. nuvu_scan-2.1.6/nuvu_scan/core/providers/aws/collectors/apigateway.py +197 -0
  9. nuvu_scan-2.1.6/nuvu_scan/core/providers/aws/collectors/backup.py +252 -0
  10. nuvu_scan-2.1.6/nuvu_scan/core/providers/aws/collectors/cloudfront.py +132 -0
  11. nuvu_scan-2.1.6/nuvu_scan/core/providers/aws/collectors/cloudtrail.py +189 -0
  12. nuvu_scan-2.1.6/nuvu_scan/core/providers/aws/collectors/cloudwatch.py +163 -0
  13. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/core/providers/aws/collectors/cost_explorer.py +90 -0
  14. nuvu_scan-2.1.6/nuvu_scan/core/providers/aws/collectors/dynamodb.py +236 -0
  15. nuvu_scan-2.1.6/nuvu_scan/core/providers/aws/collectors/ec2.py +572 -0
  16. nuvu_scan-2.1.6/nuvu_scan/core/providers/aws/collectors/ecs.py +243 -0
  17. nuvu_scan-2.1.6/nuvu_scan/core/providers/aws/collectors/eks.py +246 -0
  18. nuvu_scan-2.1.6/nuvu_scan/core/providers/aws/collectors/elasticache.py +325 -0
  19. nuvu_scan-2.1.6/nuvu_scan/core/providers/aws/collectors/elb.py +198 -0
  20. nuvu_scan-2.1.6/nuvu_scan/core/providers/aws/collectors/iam.py +593 -0
  21. nuvu_scan-2.1.6/nuvu_scan/core/providers/aws/collectors/kinesis.py +174 -0
  22. nuvu_scan-2.1.6/nuvu_scan/core/providers/aws/collectors/kms.py +186 -0
  23. nuvu_scan-2.1.6/nuvu_scan/core/providers/aws/collectors/lakeformation.py +303 -0
  24. nuvu_scan-2.1.6/nuvu_scan/core/providers/aws/collectors/lambda_collector.py +224 -0
  25. nuvu_scan-2.1.6/nuvu_scan/core/providers/aws/collectors/misc_services.py +320 -0
  26. nuvu_scan-2.1.6/nuvu_scan/core/providers/aws/collectors/rds.py +405 -0
  27. nuvu_scan-2.1.6/nuvu_scan/core/providers/aws/collectors/route53.py +183 -0
  28. nuvu_scan-2.1.6/nuvu_scan/core/providers/aws/collectors/secrets.py +178 -0
  29. nuvu_scan-2.1.6/nuvu_scan/core/providers/aws/collectors/security_services.py +329 -0
  30. nuvu_scan-2.1.6/nuvu_scan/core/providers/aws/collectors/sns_sqs.py +284 -0
  31. nuvu_scan-2.1.6/nuvu_scan/core/providers/aws/collectors/vpc_costs.py +296 -0
  32. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/pyproject.toml +1 -1
  33. nuvu_scan-2.1.2/DEVELOPMENT_STATUS.md +0 -377
  34. nuvu_scan-2.1.2/nuvu_scan/core/providers/aws/collectors/iam.py +0 -277
  35. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/.cursorrules +0 -0
  36. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  37. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/.github/workflows/ci.yml +0 -0
  38. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/.github/workflows/release.yml +0 -0
  39. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/.pre-commit-config.yaml +0 -0
  40. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/CONTRIBUTING.md +0 -0
  41. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/Makefile +0 -0
  42. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/RELEASE.md +0 -0
  43. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/__init__.py +0 -0
  44. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/cli/__init__.py +0 -0
  45. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/cli/commands/__init__.py +0 -0
  46. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/cli/formatters/__init__.py +0 -0
  47. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/cli/formatters/csv.py +0 -0
  48. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/cli/formatters/html.py +0 -0
  49. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/cli/formatters/json.py +0 -0
  50. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/cli/main.py +0 -0
  51. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/core/__init__.py +0 -0
  52. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/core/analyzers/__init__.py +0 -0
  53. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/core/models/__init__.py +0 -0
  54. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/core/providers/__init__.py +0 -0
  55. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/core/providers/aws/__init__.py +0 -0
  56. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/core/providers/aws/collectors/__init__.py +0 -0
  57. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/core/providers/aws/collectors/athena.py +0 -0
  58. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/core/providers/aws/collectors/glue.py +0 -0
  59. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/core/providers/aws/collectors/mwaa.py +0 -0
  60. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/core/providers/aws/collectors/redshift.py +0 -0
  61. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/core/providers/aws/collectors/s3.py +0 -0
  62. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/core/providers/gcp/__init__.py +0 -0
  63. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/core/providers/gcp/collectors/__init__.py +0 -0
  64. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/core/providers/gcp/collectors/bigquery.py +0 -0
  65. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/core/providers/gcp/collectors/billing.py +0 -0
  66. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/core/providers/gcp/collectors/dataproc.py +0 -0
  67. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/core/providers/gcp/collectors/gcs.py +0 -0
  68. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/core/providers/gcp/collectors/gemini.py +0 -0
  69. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/core/providers/gcp/collectors/iam.py +0 -0
  70. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/core/providers/gcp/collectors/pubsub.py +0 -0
  71. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/nuvu_scan/core/providers/gcp/gcp_scanner.py +0 -0
  72. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/tests/__init__.py +0 -0
  73. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/tests/test_base.py +0 -0
  74. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/tests/test_cli.py +0 -0
  75. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/tests/test_formatters.py +0 -0
  76. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/tests/test_push_payload.py +0 -0
  77. {nuvu_scan-2.1.2 → nuvu_scan-2.1.6}/tests/test_scanners.py +0 -0
@@ -61,6 +61,9 @@ test-scan*.html
61
61
  *.json
62
62
  !tests/**/*.json
63
63
 
64
+ # Raw scan data (contains sensitive AWS data)
65
+ raws/
66
+
64
67
  # Environment variables
65
68
  .env
66
69
  .env.local
@@ -0,0 +1,216 @@
1
+ # Nuvu Scan - Development Status
2
+
3
+ **Multi-Cloud Data Asset Scanner** - Open-source scanner designed to discover and inventory cloud data assets across AWS, GCP, Azure, and Databricks.
4
+
5
+ > **Note**: nuvu-scan is a read-only scanner that collects asset metadata. For governance, policy enforcement, and decision-making, see [nuvu-cloud](https://github.com/nuvudev/nuvu-cloud).
6
+
7
+ ## ✅ Available Collectors (v2.1.0)
8
+
9
+ ### AWS Collectors (18 collectors)
10
+
11
+ | Collector | Command Flag | What It Scans | Key Metrics |
12
+ |-----------|--------------|---------------|-------------|
13
+ | **S3** | `s3` | Buckets, policies, encryption | Size, public access, versioning |
14
+ | **Glue** | `glue` | Databases, tables, crawlers, jobs, connections | Table counts, crawl status, job runs |
15
+ | **Athena** | `athena` | Workgroups, query history | Query stats, failure rates |
16
+ | **Redshift** | `redshift` | Clusters, serverless, snapshots, datashares, reserved nodes | CPU, connections, WLM, costs |
17
+ | **IAM** | `iam` | Roles, users, groups, access keys | Permissions, MFA, key age, last used |
18
+ | **MWAA** | `mwaa` | Apache Airflow environments | Environment class, worker counts |
19
+ | **EC2/VPC** | `ec2` | Security groups, VPCs, instances, EBS volumes, Elastic IPs | Open ports, public IPs, volume encryption |
20
+ | **KMS** | `kms` | Customer-managed encryption keys | Rotation status, key state |
21
+ | **RDS** | `rds` | RDS instances, Aurora clusters, snapshots | Encryption, multi-AZ, backup retention |
22
+ | **DynamoDB** | `dynamodb` | DynamoDB tables | PITR, encryption, capacity mode |
23
+ | **Lambda** | `lambda` | Lambda functions | Runtime, code size, VPC config |
24
+ | **Secrets Manager** | `secrets` | Secrets | Rotation, last accessed, age |
25
+ | **AWS Backup** | `backup` | Backup vaults, backup plans | Recovery points, lifecycle |
26
+ | **EKS** | `eks` | EKS clusters, node groups | K8s version, endpoint access |
27
+ | **SNS/SQS** | `sns_sqs` | SNS topics, SQS queues | Encryption, DLQ, message counts |
28
+ | **Lake Formation** | `lakeformation` | Data lake settings, permissions, LF-Tags | Permission grants, admin count |
29
+ | **CloudTrail** | `cloudtrail` | CloudTrail trails | Multi-region, encryption, logging status |
30
+ | **CloudWatch** | `cloudwatch` | CloudWatch log groups | Retention, encryption, size |
31
+
32
+ ### GCP Collectors (6 collectors)
33
+
34
+ | Collector | Command Flag | What It Scans | Key Metrics |
35
+ |-----------|--------------|---------------|-------------|
36
+ | **GCS** | `gcs` | Cloud Storage buckets | Size, public access, lifecycle |
37
+ | **BigQuery** | `bigquery` | Datasets, tables, query history | Table sizes, query costs |
38
+ | **Dataproc** | `dataproc` | Dataproc clusters | Cluster config, job history |
39
+ | **Pub/Sub** | `pubsub` | Topics, subscriptions | Message counts |
40
+ | **IAM** | `iam` | Service accounts | Roles, permissions |
41
+ | **Gemini** | `gemini` | Gemini API usage | API costs |
42
+
43
+ ## 📋 Usage
44
+
45
+ ### Basic Scan
46
+ ```bash
47
+ # Scan all AWS collectors
48
+ nuvu-scan aws
49
+
50
+ # Scan all GCP collectors
51
+ nuvu-scan gcp --credentials /path/to/key.json
52
+ ```
53
+
54
+ ### Selective Scanning
55
+ ```bash
56
+ # Scan specific collectors
57
+ nuvu-scan aws --collectors s3,rds,iam,kms
58
+
59
+ # List available collectors
60
+ nuvu-scan aws --list-collectors
61
+ ```
62
+
63
+ ### Output Formats
64
+ ```bash
65
+ # HTML report (default)
66
+ nuvu-scan aws -o report.html
67
+
68
+ # JSON output
69
+ nuvu-scan aws -o assets.json
70
+
71
+ # CSV output
72
+ nuvu-scan aws -o assets.csv
73
+ ```
74
+
75
+ ### Push to Nuvu Cloud
76
+ ```bash
77
+ # Push results to nuvu-cloud for governance
78
+ nuvu-scan aws --push --api-key YOUR_API_KEY
79
+ ```
80
+
81
+ ## 🔒 IAM Permissions
82
+
83
+ The complete IAM policy is in `aws-iam-policy.json` (60+ permission statements).
84
+
85
+ ### Permission Categories
86
+
87
+ | Category | Services | Example Actions |
88
+ |----------|----------|-----------------|
89
+ | **Storage** | S3, EBS | `s3:GetBucket*`, `ec2:DescribeVolumes` |
90
+ | **Compute** | EC2, Lambda, EKS | `ec2:DescribeInstances`, `lambda:ListFunctions` |
91
+ | **Database** | RDS, DynamoDB, Redshift | `rds:DescribeDB*`, `dynamodb:DescribeTable` |
92
+ | **Data Analytics** | Glue, Athena, Lake Formation | `glue:GetTables`, `athena:ListWorkGroups` |
93
+ | **Security** | IAM, KMS, Secrets Manager | `iam:ListRoles`, `kms:DescribeKey` |
94
+ | **Networking** | VPC, Security Groups | `ec2:DescribeSecurityGroups`, `ec2:DescribeVpcs` |
95
+ | **Messaging** | SNS, SQS | `sns:GetTopicAttributes`, `sqs:GetQueueAttributes` |
96
+ | **Observability** | CloudWatch, CloudTrail | `logs:DescribeLogGroups`, `cloudtrail:DescribeTrails` |
97
+ | **Resilience** | AWS Backup | `backup:ListBackupVaults`, `backup:ListBackupPlans` |
98
+ | **Cost** | Cost Explorer | `ce:GetCostAndUsage` |
99
+
100
+ All permissions are **read-only** following the principle of least privilege.
101
+
102
+ ## 📊 Asset Types Collected
103
+
104
+ ### Compute
105
+ - EC2 instances, EBS volumes, Elastic IPs
106
+ - Lambda functions
107
+ - EKS clusters, node groups
108
+
109
+ ### Storage
110
+ - S3 buckets
111
+ - EBS volumes
112
+
113
+ ### Databases
114
+ - RDS instances, Aurora clusters
115
+ - DynamoDB tables
116
+ - Redshift clusters (provisioned & serverless)
117
+
118
+ ### Data Catalog
119
+ - Glue databases, tables, crawlers, jobs
120
+ - Lake Formation settings, permissions, LF-Tags
121
+
122
+ ### Security
123
+ - IAM roles, users, groups, access keys
124
+ - KMS keys
125
+ - Secrets Manager secrets
126
+ - Security groups, VPCs
127
+
128
+ ### Observability
129
+ - CloudWatch log groups
130
+ - CloudTrail trails
131
+
132
+ ### Messaging
133
+ - SNS topics
134
+ - SQS queues
135
+
136
+ ### Backup
137
+ - AWS Backup vaults and plans
138
+
139
+ ## 🏷️ Risk Flags
140
+
141
+ nuvu-scan identifies potential issues by flagging assets:
142
+
143
+ | Category | Example Flags |
144
+ |----------|---------------|
145
+ | **Security** | `unencrypted`, `publicly_accessible`, `mfa_disabled`, `open_to_internet` |
146
+ | **Access** | `unused_role`, `old_key`, `overly_permissive`, `public_access` |
147
+ | **Operations** | `no_backups`, `stale_crawler`, `deprecated_runtime`, `logging_disabled` |
148
+ | **Cost** | `unattached_volume`, `old_snapshot`, `unused_eip` |
149
+ | **Compliance** | `no_retention_policy`, `rotation_disabled`, `pitr_disabled` |
150
+
151
+ ## 🧪 Testing
152
+
153
+ ```bash
154
+ # Run tests
155
+ uv run pytest
156
+
157
+ # Run with coverage
158
+ uv run pytest --cov=nuvu_scan
159
+ ```
160
+
161
+ ## 📦 Installation
162
+
163
+ ```bash
164
+ # From PyPI
165
+ pip install nuvu-scan
166
+
167
+ # From source
168
+ git clone https://github.com/nuvudev/nuvu-scan
169
+ cd nuvu-scan
170
+ uv sync
171
+ ```
172
+
173
+ ## 📋 Roadmap
174
+
175
+ ### Additional AWS Collectors
176
+ - [ ] OpenSearch collector
177
+ - [ ] EMR collector
178
+ - [ ] SageMaker collector
179
+ - [ ] Bedrock collector
180
+ - [ ] MSK (Kafka) collector
181
+ - [ ] Kinesis collector
182
+ - [ ] Step Functions collector
183
+ - [ ] EventBridge collector
184
+
185
+ ### Additional GCP Collectors
186
+ - [ ] Cloud SQL collector
187
+ - [ ] Cloud Spanner collector
188
+ - [ ] Bigtable collector
189
+ - [ ] Firestore collector
190
+ - [ ] Vertex AI collector
191
+ - [ ] Dataflow collector
192
+ - [ ] Cloud Composer collector
193
+
194
+ ### Azure Provider
195
+ - [ ] Blob Storage collector
196
+ - [ ] Data Lake collector
197
+ - [ ] Synapse collector
198
+ - [ ] Azure Databricks collector
199
+
200
+ ### Databricks Provider
201
+ - [ ] Workspace discovery
202
+ - [ ] Unity Catalog
203
+
204
+ ### Enhancements
205
+ - [ ] Parallel collection for faster scans
206
+ - [ ] Progress bars with ETA
207
+ - [ ] Incremental scanning (delta detection)
208
+ - [ ] Schema-level inventory (Redshift Data API)
209
+
210
+ ## 🤝 Contributing
211
+
212
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
213
+
214
+ ## 📄 License
215
+
216
+ MIT License - see [LICENSE](LICENSE) for details.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nuvu-scan
3
- Version: 2.1.2
3
+ Version: 2.1.6
4
4
  Summary: Multi-Cloud Data Asset Control - Discover, govern, and optimize your cloud data assets across AWS and GCP
5
5
  Project-URL: Homepage, https://nuvu.dev
6
6
  Project-URL: Documentation, https://github.com/nuvudev/nuvu-scan#readme
@@ -48,6 +48,10 @@ Description-Content-Type: text/markdown
48
48
 
49
49
  # Nuvu Scan
50
50
 
51
+ [![PyPI Downloads](https://img.shields.io/pypi/dm/nuvu-scan?style=flat-square&label=downloads&color=667eea)](https://pypistats.org/packages/nuvu-scan)
52
+ [![GitHub Stars](https://img.shields.io/github/stars/nuvudev/nuvu-scan?style=flat-square&label=stars&color=667eea)](https://github.com/nuvudev/nuvu-scan)
53
+ [![PyPI Version](https://img.shields.io/pypi/v/nuvu-scan?style=flat-square&label=version&color=764ba2)](https://pypi.org/project/nuvu-scan/)
54
+
51
55
  **Take Control of Your Cloud Data Estate**
52
56
  Discover, govern, and optimize your cloud data assets across **AWS and GCP** — reduce wasted spend, enforce compliance, and gain full visibility into unused, idle, or risky resources.
53
57
 
@@ -1,5 +1,9 @@
1
1
  # Nuvu Scan
2
2
 
3
+ [![PyPI Downloads](https://img.shields.io/pypi/dm/nuvu-scan?style=flat-square&label=downloads&color=667eea)](https://pypistats.org/packages/nuvu-scan)
4
+ [![GitHub Stars](https://img.shields.io/github/stars/nuvudev/nuvu-scan?style=flat-square&label=stars&color=667eea)](https://github.com/nuvudev/nuvu-scan)
5
+ [![PyPI Version](https://img.shields.io/pypi/v/nuvu-scan?style=flat-square&label=version&color=764ba2)](https://pypi.org/project/nuvu-scan/)
6
+
3
7
  **Take Control of Your Cloud Data Estate**
4
8
  Discover, govern, and optimize your cloud data assets across **AWS and GCP** — reduce wasted spend, enforce compliance, and gain full visibility into unused, idle, or risky resources.
5
9
 
@@ -331,6 +331,7 @@ def scan_command(
331
331
  "total_cost_estimate_usd": result.total_cost_estimate_usd,
332
332
  "scan_regions": scan_regions if scan_regions else None,
333
333
  "scan_all_regions": not bool(region),
334
+ "summary": result.summary, # Include cost data from Cost Explorer
334
335
  "assets": [
335
336
  {
336
337
  "provider": asset.provider,
@@ -353,6 +354,7 @@ def scan_command(
353
354
  "risk_flags": asset.risk_flags,
354
355
  "ownership_confidence": asset.ownership_confidence or "unknown",
355
356
  "suggested_owner": asset.suggested_owner,
357
+ "underlying_cloud_account_id": asset.underlying_cloud_account_id,
356
358
  }
357
359
  for asset in result.assets
358
360
  ],
@@ -28,6 +28,16 @@ class NormalizedCategory(str, Enum):
28
28
  DATABASE = "database"
29
29
  SECURITY = "security"
30
30
  BILLING = "billing"
31
+ # Additional categories for comprehensive coverage
32
+ NETWORKING = "networking" # VPC, Load Balancers, Route 53, CloudFront
33
+ CACHING = "caching" # ElastiCache, DAX
34
+ CONTAINER = "container" # ECS, ECR, Fargate
35
+ SERVERLESS = "serverless" # Lambda, Step Functions, API Gateway
36
+ STORAGE = "storage" # EBS, EFS, FSx
37
+ MESSAGING = "messaging" # SNS, SQS, EventBridge
38
+ OBSERVABILITY = "observability" # CloudWatch, X-Ray
39
+ RESILIENCE = "resilience" # Backup, DR
40
+ GOVERNANCE = "governance" # Config, CloudTrail, Organizations
31
41
 
32
42
 
33
43
  @dataclass
@@ -15,15 +15,37 @@ from nuvu_scan.core.base import (
15
15
  ScanConfig,
16
16
  )
17
17
 
18
+ from .collectors.apigateway import APIGatewayCollector
18
19
  from .collectors.athena import AthenaCollector
20
+ from .collectors.backup import BackupCollector
21
+ from .collectors.cloudfront import CloudFrontCollector
22
+ from .collectors.cloudtrail import CloudTrailCollector
23
+ from .collectors.cloudwatch import CloudWatchLogsCollector
19
24
  from .collectors.cost_explorer import CostExplorerCollector
25
+ from .collectors.dynamodb import DynamoDBCollector
26
+ from .collectors.ec2 import EC2Collector
27
+ from .collectors.ecs import ECSCollector
28
+ from .collectors.eks import EKSCollector
29
+ from .collectors.elasticache import ElastiCacheCollector
30
+ from .collectors.elb import ELBCollector
20
31
  from .collectors.glue import GlueCollector
21
32
  from .collectors.iam import IAMCollector
33
+ from .collectors.kinesis import KinesisFirehoseCollector
34
+ from .collectors.kms import KMSCollector
35
+ from .collectors.lakeformation import LakeFormationCollector
36
+ from .collectors.lambda_collector import LambdaCollector
37
+ from .collectors.misc_services import EFSCollector, StepFunctionsCollector, SystemsManagerCollector
22
38
  from .collectors.mwaa import MWAACollector
39
+ from .collectors.rds import RDSCollector
23
40
  from .collectors.redshift import RedshiftCollector
24
-
25
- # Import collectors
41
+ from .collectors.route53 import Route53Collector
26
42
  from .collectors.s3 import S3Collector
43
+ from .collectors.secrets import SecretsManagerCollector
44
+ from .collectors.security_services import SecurityServicesCollector
45
+ from .collectors.sns_sqs import SNSSQSCollector
46
+
47
+ # New collectors for comprehensive coverage
48
+ from .collectors.vpc_costs import VPCCostsCollector
27
49
 
28
50
 
29
51
  class AWSScanner(CloudProviderScan):
@@ -166,12 +188,38 @@ class AWSScanner(CloudProviderScan):
166
188
 
167
189
  # Map of collector names to their classes for filtering
168
190
  COLLECTOR_MAP = {
191
+ # Original collectors
169
192
  "s3": S3Collector,
170
193
  "glue": GlueCollector,
171
194
  "athena": AthenaCollector,
172
195
  "redshift": RedshiftCollector,
173
196
  "iam": IAMCollector,
174
197
  "mwaa": MWAACollector,
198
+ "ec2": EC2Collector,
199
+ "kms": KMSCollector,
200
+ "rds": RDSCollector,
201
+ "dynamodb": DynamoDBCollector,
202
+ "lambda": LambdaCollector,
203
+ "secrets": SecretsManagerCollector,
204
+ "backup": BackupCollector,
205
+ "eks": EKSCollector,
206
+ "sns_sqs": SNSSQSCollector,
207
+ "lakeformation": LakeFormationCollector,
208
+ "cloudtrail": CloudTrailCollector,
209
+ "cloudwatch": CloudWatchLogsCollector,
210
+ # New collectors for comprehensive coverage
211
+ "vpc_costs": VPCCostsCollector,
212
+ "elb": ELBCollector,
213
+ "elasticache": ElastiCacheCollector,
214
+ "route53": Route53Collector,
215
+ "kinesis": KinesisFirehoseCollector,
216
+ "apigateway": APIGatewayCollector,
217
+ "cloudfront": CloudFrontCollector,
218
+ "ecs": ECSCollector,
219
+ "security": SecurityServicesCollector,
220
+ "ssm": SystemsManagerCollector,
221
+ "stepfunctions": StepFunctionsCollector,
222
+ "efs": EFSCollector,
175
223
  }
176
224
 
177
225
  @classmethod
@@ -179,6 +227,22 @@ class AWSScanner(CloudProviderScan):
179
227
  """Return list of available collector names."""
180
228
  return list(cls.COLLECTOR_MAP.keys())
181
229
 
230
+ # Collectors that require account_id as a parameter
231
+ COLLECTORS_NEEDING_ACCOUNT_ID = {
232
+ "vpc_costs",
233
+ "elb",
234
+ "elasticache",
235
+ "route53",
236
+ "kinesis",
237
+ "apigateway",
238
+ "cloudfront",
239
+ "ecs",
240
+ "security",
241
+ "ssm",
242
+ "stepfunctions",
243
+ "efs",
244
+ }
245
+
182
246
  def _initialize_collectors(self) -> list:
183
247
  """Initialize AWS service collectors based on config."""
184
248
  collectors = []
@@ -189,15 +253,22 @@ class AWSScanner(CloudProviderScan):
189
253
  # Normalize to lowercase
190
254
  requested_lower = [c.lower() for c in requested]
191
255
 
256
+ def create_collector(name, collector_cls):
257
+ """Create a collector with appropriate parameters."""
258
+ if name in self.COLLECTORS_NEEDING_ACCOUNT_ID:
259
+ return collector_cls(self.session, self.config.regions, self.config.account_id)
260
+ else:
261
+ return collector_cls(self.session, self.config.regions)
262
+
192
263
  # If no specific collectors requested, use all
193
264
  if not requested_lower:
194
- for collector_cls in self.COLLECTOR_MAP.values():
195
- collectors.append(collector_cls(self.session, self.config.regions))
265
+ for name, collector_cls in self.COLLECTOR_MAP.items():
266
+ collectors.append(create_collector(name, collector_cls))
196
267
  else:
197
268
  # Filter to only requested collectors
198
269
  for name, collector_cls in self.COLLECTOR_MAP.items():
199
270
  if name in requested_lower:
200
- collectors.append(collector_cls(self.session, self.config.regions))
271
+ collectors.append(create_collector(name, collector_cls))
201
272
 
202
273
  # Warn about unknown collectors
203
274
  known = set(self.COLLECTOR_MAP.keys())
@@ -243,18 +314,68 @@ class AWSScanner(CloudProviderScan):
243
314
 
244
315
  end_date = datetime.utcnow()
245
316
  start_date = end_date - timedelta(days=30)
246
- service_costs = self.cost_explorer.get_service_costs(start_date, end_date)
317
+
318
+ # Get comprehensive cost data including Savings Plans
319
+ cost_data = self.cost_explorer.get_all_costs_with_savings(start_date, end_date)
320
+ service_costs = cost_data["service_costs"]
321
+ savings_plans = cost_data["savings_plans"]
247
322
  print(" → Cost data retrieved", file=sys.stderr)
323
+ if savings_plans.get("total_savings", 0) > 0:
324
+ print(
325
+ f" → Savings Plans: ${savings_plans['total_savings']:.2f} saved ({savings_plans['utilization_percent']:.1f}% utilization)",
326
+ file=sys.stderr,
327
+ )
248
328
 
249
329
  if service_costs:
250
330
  # Map collectors to AWS service names in Cost Explorer
251
331
  collector_to_services = {
332
+ # Original collectors
252
333
  "s3": ["Amazon Simple Storage Service"],
253
334
  "glue": ["AWS Glue"],
254
335
  "athena": ["Amazon Athena"],
255
336
  "redshift": ["Amazon Redshift"],
256
337
  "iam": [], # IAM is free
257
338
  "mwaa": ["Amazon Managed Workflows for Apache Airflow"],
339
+ "ec2": [
340
+ "Amazon Elastic Compute Cloud - Compute",
341
+ "EC2 - Other",
342
+ "Amazon EC2 Container Registry (ECR)",
343
+ ],
344
+ "kms": ["AWS Key Management Service"],
345
+ "rds": ["Amazon Relational Database Service"],
346
+ "dynamodb": ["Amazon DynamoDB"],
347
+ "lambda": ["AWS Lambda"],
348
+ "secrets": ["AWS Secrets Manager"],
349
+ "backup": ["AWS Backup"],
350
+ "eks": [
351
+ "Amazon Elastic Kubernetes Service",
352
+ "Amazon Elastic Container Service for Kubernetes",
353
+ ],
354
+ "sns_sqs": [
355
+ "Amazon Simple Notification Service",
356
+ "Amazon Simple Queue Service",
357
+ ],
358
+ "lakeformation": ["AWS Lake Formation"],
359
+ "cloudtrail": ["AWS CloudTrail"],
360
+ "cloudwatch": ["AmazonCloudWatch", "CloudWatch Events"],
361
+ # New collectors
362
+ "vpc_costs": ["Amazon Virtual Private Cloud"],
363
+ "elb": ["Amazon Elastic Load Balancing"],
364
+ "elasticache": ["Amazon ElastiCache"],
365
+ "route53": ["Amazon Route 53"],
366
+ "kinesis": ["Amazon Kinesis Firehose", "Amazon Kinesis"],
367
+ "apigateway": ["Amazon API Gateway"],
368
+ "cloudfront": ["Amazon CloudFront"],
369
+ "ecs": ["Amazon Elastic Container Service"],
370
+ "security": [
371
+ "Amazon GuardDuty",
372
+ "Amazon Inspector",
373
+ "AWS Security Hub",
374
+ "AWS Config",
375
+ ],
376
+ "ssm": ["AWS Systems Manager"],
377
+ "stepfunctions": ["AWS Step Functions"],
378
+ "efs": ["Amazon Elastic File System"],
258
379
  }
259
380
 
260
381
  # Filter costs based on active collectors
@@ -309,6 +430,14 @@ class AWSScanner(CloudProviderScan):
309
430
  "estimated_monthly_cost": monthly_estimate,
310
431
  "scope": scope_note,
311
432
  "note": "Actual costs from AWS Cost Explorer API for the last 30 days.",
433
+ # Savings Plans data
434
+ "savings_plans": {
435
+ "total_savings": savings_plans.get("total_savings", 0),
436
+ "utilization_percent": savings_plans.get("utilization_percent", 0),
437
+ "coverage_percent": savings_plans.get("coverage_percent", 0),
438
+ "amortized_commitment": savings_plans.get("amortized_commitment", 0),
439
+ "on_demand_equivalent": savings_plans.get("on_demand_equivalent", 0),
440
+ },
312
441
  },
313
442
  )
314
443
  all_assets.append(cost_summary_asset)