sudiviz 0.3.0__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 (36) hide show
  1. sudiviz-0.3.0/LICENSE +21 -0
  2. sudiviz-0.3.0/MANIFEST.in +10 -0
  3. sudiviz-0.3.0/PKG-INFO +543 -0
  4. sudiviz-0.3.0/README.md +489 -0
  5. sudiviz-0.3.0/pyproject.toml +96 -0
  6. sudiviz-0.3.0/setup.cfg +4 -0
  7. sudiviz-0.3.0/sudiviz/__init__.py +9 -0
  8. sudiviz-0.3.0/sudiviz/__main__.py +5 -0
  9. sudiviz-0.3.0/sudiviz/cli.py +598 -0
  10. sudiviz-0.3.0/sudiviz/discovery/__init__.py +26 -0
  11. sudiviz-0.3.0/sudiviz/discovery/aws.py +873 -0
  12. sudiviz-0.3.0/sudiviz/discovery/models.py +337 -0
  13. sudiviz-0.3.0/sudiviz/discovery/terraform.py +257 -0
  14. sudiviz-0.3.0/sudiviz/graph/__init__.py +24 -0
  15. sudiviz-0.3.0/sudiviz/graph/analyzer.py +512 -0
  16. sudiviz-0.3.0/sudiviz/graph/builder.py +315 -0
  17. sudiviz-0.3.0/sudiviz/graph/visualizer.py +356 -0
  18. sudiviz-0.3.0/sudiviz/remediation/__init__.py +4 -0
  19. sudiviz-0.3.0/sudiviz/remediation/engine.py +385 -0
  20. sudiviz-0.3.0/sudiviz/tui.py +289 -0
  21. sudiviz-0.3.0/sudiviz/utils/__init__.py +1 -0
  22. sudiviz-0.3.0/sudiviz/utils/auth.py +146 -0
  23. sudiviz-0.3.0/sudiviz/utils/branding.py +49 -0
  24. sudiviz-0.3.0/sudiviz/utils/reachability.py +77 -0
  25. sudiviz-0.3.0/sudiviz/web.py +205 -0
  26. sudiviz-0.3.0/sudiviz/web_templates/cytoscape.js +106 -0
  27. sudiviz-0.3.0/sudiviz/web_templates/index.html +390 -0
  28. sudiviz-0.3.0/sudiviz/web_templates/style.css +90 -0
  29. sudiviz-0.3.0/sudiviz.egg-info/PKG-INFO +543 -0
  30. sudiviz-0.3.0/sudiviz.egg-info/SOURCES.txt +34 -0
  31. sudiviz-0.3.0/sudiviz.egg-info/dependency_links.txt +1 -0
  32. sudiviz-0.3.0/sudiviz.egg-info/entry_points.txt +2 -0
  33. sudiviz-0.3.0/sudiviz.egg-info/requires.txt +37 -0
  34. sudiviz-0.3.0/sudiviz.egg-info/top_level.txt +1 -0
  35. sudiviz-0.3.0/tests/test_analyzer.py +234 -0
  36. sudiviz-0.3.0/tests/test_discovery.py +215 -0
sudiviz-0.3.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Sudipto Ghosh
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,10 @@
1
+ # Include
2
+ include LICENSE
3
+ include README.md
4
+ include pyproject.toml
5
+ recursive-include sudiviz *.py *.html *.css *.js
6
+
7
+ # Exclude sensitive/personal files
8
+ exclude LINKEDIN_POST.md
9
+ prune .claude
10
+ prune docs/demo-broken-alb.md
sudiviz-0.3.0/PKG-INFO ADDED
@@ -0,0 +1,543 @@
1
+ Metadata-Version: 2.4
2
+ Name: sudiviz
3
+ Version: 0.3.0
4
+ Summary: Sufficient visibility into cloud infrastructure failures — live AWS topology + Terraform drift in one CLI.
5
+ Author: Sudipto Ghosh
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/sudiptoghosh/sudiviz
8
+ Project-URL: Issues, https://github.com/sudiptoghosh/sudiviz/issues
9
+ Keywords: aws,terraform,observability,networking,diagnose,alb,vpc
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: System Administrators
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: System :: Networking :: Monitoring
19
+ Requires-Python: >=3.10
20
+ Description-Content-Type: text/markdown
21
+ License-File: LICENSE
22
+ Requires-Dist: typer>=0.15.0
23
+ Requires-Dist: boto3>=1.35.0
24
+ Requires-Dist: botocore>=1.35.0
25
+ Requires-Dist: networkx>=3.0
26
+ Requires-Dist: pydantic>=2.0
27
+ Requires-Dist: rich>=13.0
28
+ Requires-Dist: aiohttp>=3.9
29
+ Requires-Dist: graphviz>=0.20
30
+ Requires-Dist: jinja2>=3.1
31
+ Provides-Extra: tui
32
+ Requires-Dist: textual>=0.50.0; extra == "tui"
33
+ Provides-Extra: web
34
+ Requires-Dist: fastapi>=0.115.0; extra == "web"
35
+ Requires-Dist: uvicorn>=0.30.0; extra == "web"
36
+ Requires-Dist: websockets>=13.0; extra == "web"
37
+ Provides-Extra: diagrams
38
+ Requires-Dist: diagrams>=0.23; extra == "diagrams"
39
+ Provides-Extra: terraform
40
+ Requires-Dist: python-terraform>=0.10; extra == "terraform"
41
+ Provides-Extra: all
42
+ Requires-Dist: textual>=0.50.0; extra == "all"
43
+ Requires-Dist: fastapi>=0.115.0; extra == "all"
44
+ Requires-Dist: uvicorn>=0.30.0; extra == "all"
45
+ Requires-Dist: websockets>=13.0; extra == "all"
46
+ Requires-Dist: diagrams>=0.23; extra == "all"
47
+ Requires-Dist: python-terraform>=0.10; extra == "all"
48
+ Provides-Extra: dev
49
+ Requires-Dist: pytest>=8.0; extra == "dev"
50
+ Requires-Dist: pytest-asyncio>=0.23; extra == "dev"
51
+ Requires-Dist: ruff>=0.5; extra == "dev"
52
+ Requires-Dist: mypy>=1.8; extra == "dev"
53
+ Dynamic: license-file
54
+
55
+ # sudiviz
56
+
57
+ > **sudiviz** = **sudipto's** + **viz** → *X-ray vision for your cloud infrastructure.*
58
+
59
+ Live, interactive topology + diagnosis for AWS (Azure/GCP next). When a
60
+ deployment 503s, sudiviz tells you **why** — in plain English — and **draws
61
+ you a picture**. Every render is a fresh API call. Every orphan pulses red.
62
+
63
+ ```
64
+ _ _ _
65
+ ___ _ _ __| (_)_ _(_)____
66
+ / __| | | |/ _` | \ \ / / |_ /
67
+ \__ \ |_| | (_| | |\ V /| |/ /
68
+ |___/\__,_|\__,_|_| \_/ |_/___|
69
+
70
+ X-ray vision for your cloud infrastructure
71
+ ```
72
+
73
+ ---
74
+
75
+ ## Why sudiviz?
76
+
77
+ Hava.io and Cloudcraft.co generate gorgeous diagrams — **but they're snapshots**.
78
+ By the time you reload, your problem has moved. sudiviz is built around live
79
+ data: every render is a fresh API call, every node is clickable, every orphan
80
+ is highlighted in red dashed lines.
81
+
82
+ | Feature | sudiviz | Hava.io | Cloudcraft |
83
+ |--------------------------------------|:--------:|:--------------:|:------------:|
84
+ | Live data (no manual refresh) | ✅ | ❌ (static) | ❌ (static) |
85
+ | Terminal UI (Textual) | ✅ | ❌ | ❌ |
86
+ | Interactive web (Cytoscape.js) | ✅ | ✅ | ✅ |
87
+ | WebSocket real-time updates | ✅ | ❌ | ❌ |
88
+ | PNG export | ✅ | ✅ | ✅ |
89
+ | Plain-English fix suggestions | ✅ | ❌ | ❌ |
90
+ | Terraform drift detection | ✅ | ❌ | ❌ |
91
+ | **Orphan detection** (red dashed) | ✅ | ❌ | ❌ |
92
+ | ECS / EKS / RDS / Lambda / S3 | ✅ | ✅ | ✅ |
93
+ | Security & encryption checks | ✅ | ❌ | ❌ |
94
+ | Free / open source | ✅ MIT | ❌ ($29/mo) | ❌ ($49/mo) |
95
+ | CI-friendly `--json` flag | ✅ | ❌ | ❌ |
96
+
97
+ ---
98
+
99
+ ## Install
100
+
101
+ ```bash
102
+ pip install sudiviz # core CLI (EC2, ALB, SGs, basic discovery)
103
+ pip install 'sudiviz[all]' # + TUI, web server, PNG diagrams
104
+ ```
105
+
106
+ > **Auth:** sudiviz uses the standard boto3 credential chain — env vars,
107
+ > `~/.aws/credentials`, SSO, instance profile. Credentials are **never**
108
+ > accepted as CLI flags. Run `aws configure` or set `AWS_ACCESS_KEY_ID` /
109
+ > `AWS_SECRET_ACCESS_KEY` / `AWS_DEFAULT_REGION` before running.
110
+
111
+ ---
112
+
113
+ ## AWS services discovered
114
+
115
+ sudiviz discovers these services in parallel from your live AWS account:
116
+
117
+ | Service | What's collected |
118
+ |---------|-----------------|
119
+ | **ALB / NLB** | Load balancers, listeners, listener rules, scheme, state |
120
+ | **Target Groups** | Protocol, port, per-target health (healthy / unhealthy / draining) |
121
+ | **EC2 Instances** | State, IPs, subnet, security group memberships |
122
+ | **Security Groups** | Ingress/egress rules, ENI attachments |
123
+ | **ECS** | Clusters → Services (desired vs running tasks, launch type, TG links) |
124
+ | **EKS** | Clusters → Node Groups (status, capacity type, scaling config) |
125
+ | **RDS** | DB instances (engine, status, endpoint, encryption, public access) |
126
+ | **Lambda** | Functions (runtime, state, VPC config, event source mappings) |
127
+ | **S3** | Buckets (versioning, public access block, server-side encryption) |
128
+ | **VPC** | Used as the graph root when `--vpc-id` is supplied |
129
+
130
+ All discovery calls run via `asyncio.to_thread` — a typical account with
131
+ ~50 resources finishes in under 5 seconds.
132
+
133
+ ---
134
+
135
+ ## Three visualization modes
136
+
137
+ ### 1. Terminal (default)
138
+
139
+ ```bash
140
+ sudiviz diagnose --region us-east-1
141
+ sudiviz diagnose --vpc-id vpc-abc --service-tag Service=checkout
142
+ ```
143
+
144
+ ```
145
+ ╭─ sudiviz topology ──────────────────────────────────────╮
146
+ │ Topology │
147
+ │ ├── alb: web-prod │
148
+ │ │ └── ──▶ target_group: web-prod-tg [2/3] │
149
+ │ │ ├── ──▶ instance: i-0a1b2c (healthy) │
150
+ │ │ └── ──▶ instance: i-0a1b2d (unhealthy) │
151
+ │ ├── ECS │
152
+ │ │ └── ecs_cluster: prod-cluster │
153
+ │ │ └── ──▶ ecs_service: api [3/3 running] │
154
+ │ ├── EKS │
155
+ │ │ └── eks_cluster: prod ──▶ eks_nodegroup: workers │
156
+ │ ├── RDS │
157
+ │ │ └── rds: mydb (postgres / available) │
158
+ │ ├── Lambda │
159
+ │ │ └── lambda: worker (python3.12 / Active) │
160
+ │ ├── S3 │
161
+ │ │ └── s3: my-bucket │
162
+ │ └── ORPHANS │
163
+ │ ╌╌ target_group: legacy-tg │
164
+ │ ╌╌ security_group: unused-sg │
165
+ ╰─────────────────────────────────────────────────────────╯
166
+
167
+ ┌──────────┬─────────────────────────────────────┬──────────────────────────────────────┐
168
+ │ Severity │ Title │ Detail │
169
+ ├──────────┼─────────────────────────────────────┼──────────────────────────────────────┤
170
+ │ critical │ S3 'my-bucket': public access open │ Enable S3 Block Public Access… │
171
+ │ critical │ TG 'web-prod-tg': 2/3 healthy │ 1 target failing health checks… │
172
+ │ warning │ RDS 'mydb': storage not encrypted │ Enable SSE-S3 or SSE-KMS… │
173
+ │ warning │ Orphan target group: legacy-tg │ No listener forwards here… │
174
+ │ info │ Unused security group: unused-sg │ Safe to delete. │
175
+ └──────────┴─────────────────────────────────────┴──────────────────────────────────────┘
176
+ ```
177
+
178
+ ### 2. Textual TUI (mouse + keyboard)
179
+
180
+ ```bash
181
+ sudiviz tui --vpc-id vpc-abc
182
+ pip install 'sudiviz[tui]' # if not already installed
183
+ ```
184
+
185
+ | Key | Action |
186
+ |-----|---------------------------------|
187
+ | `r` | Refresh discovery |
188
+ | `o` | Toggle orphan-only filter |
189
+ | `d` | Drift overlay hint |
190
+ | `q` | Quit |
191
+
192
+ Click any row to populate the details pane — shows ARN, health, engine,
193
+ task counts, encryption status, and more depending on node type.
194
+
195
+ Status bar shows live counts for all services:
196
+ ```
197
+ ● 123456789 us-east-1 vpc=all · 3 ALBs · 5 TGs · 8 EC2 · 2 ECS clusters (6 svcs) · 1 EKS clusters · 3 RDS · 4 Lambda · 12 S3 · refreshed 14:23:01
198
+ ```
199
+
200
+ ### 3. Interactive web (Cytoscape.js)
201
+
202
+ ```bash
203
+ pip install 'sudiviz[web]' # if not already installed
204
+ sudiviz graph --output web --port 8000 --open
205
+ ```
206
+
207
+ Opens a browser with a live topology graph that:
208
+
209
+ - Pans, zooms, and drags nodes freely
210
+ - Click any node → sidebar shows full metadata (ARN, health, engine, task counts, encryption)
211
+ - **Cmd/Ctrl-click** opens the AWS Console directly for that resource
212
+ - Auto-refreshes every 30 s via WebSocket (toggleable)
213
+ - **Orphan edges pulse red dashed** — impossible to miss
214
+ - **⚠ Orphans button** filters the graph to only show problem nodes
215
+ - **⤓ PNG button** exports the current view as a PNG
216
+
217
+ **Node colours by kind:**
218
+
219
+ | Node type | Shape | Colour |
220
+ |-----------|-------|--------|
221
+ | ALB / NLB | Cut rectangle | Blue |
222
+ | Target Group | Rounded rect | Cyan |
223
+ | EC2 Instance | Rounded rect | Purple |
224
+ | Security Group | Diamond | Amber |
225
+ | ECS Cluster | Barrel | Pink |
226
+ | ECS Service | Rounded rect | Fuchsia |
227
+ | EKS Cluster | Hexagon | Blue |
228
+ | EKS Node Group | Rounded rect | Sky |
229
+ | RDS | Barrel | Yellow |
230
+ | Lambda | Triangle | Green |
231
+ | S3 | Rounded rect | Orange |
232
+ | VPC | Rectangle | Gray |
233
+
234
+ Or export a static PNG:
235
+
236
+ ```bash
237
+ sudiviz graph --output png --file topology.png --open
238
+ ```
239
+
240
+ ---
241
+
242
+ ## Connectivity indicators — green / red / dashed
243
+
244
+ sudiviz uses a consistent visual language across **all three output modes**:
245
+
246
+ | State | Terminal | Web (Cytoscape) | PNG (Graphviz) |
247
+ |-------|----------|-----------------|----------------|
248
+ | Healthy edge | `──▶` (dim) | Solid green line (`#22c55e`) | `style=solid color=#374151` |
249
+ | Orphan edge | `╌╌▶` (bold red) | Dashed red line (`#dc2626`) + pulse | `style=dashed color=#dc2626 penwidth=2` |
250
+ | Healthy node border | — | Green border | Green fill `#dcfce7` |
251
+ | Unhealthy node border | — | Red border | Red fill `#fecaca` |
252
+ | Orphan node | Red dashed section | Red dashed border + red fill `#fee2e2` | Red fill `#fee2e2` |
253
+
254
+ ### What triggers a red dashed line?
255
+
256
+ An edge turns red and dashed whenever **either endpoint** is an orphan:
257
+
258
+ 1. **Orphan target group** — no ALB listener has a `forwards_to` edge pointing at it.
259
+ 2. **Orphan instance** — not registered in any target group.
260
+ 3. **Orphan security group** — no ENI or resource has a `guarded_by` edge to it.
261
+
262
+ ```bash
263
+ sudiviz diagnose --show-unattached --highlight-orphans
264
+ ```
265
+
266
+ Algorithm lives in [sudiviz/graph/analyzer.py](sudiviz/graph/analyzer.py) →
267
+ `mark_orphaned_edges()`. It annotates `node['orphan']=True` and
268
+ `edge['style']='dashed'` so all visualizers stay output-agnostic.
269
+
270
+ ---
271
+
272
+ ## Diagnostic rules — what sudiviz checks
273
+
274
+ ### Load balancer + networking
275
+ | Check | Severity |
276
+ |-------|----------|
277
+ | Target group has unhealthy targets | critical / warning |
278
+ | Instance SG missing required port from ALB SG | critical |
279
+ | Orphan target group (no listener routes to it) | warning |
280
+ | Instance not in any target group | info |
281
+ | Security group attached to nothing | info |
282
+
283
+ ### ECS
284
+ | Check | Severity |
285
+ |-------|----------|
286
+ | Service `running < desired` tasks | critical (0 running) / warning |
287
+ | Service has 0 desired tasks | — (skipped, intentional scale-down) |
288
+
289
+ ### EKS
290
+ | Check | Severity |
291
+ |-------|----------|
292
+ | Cluster not in ACTIVE state | critical |
293
+ | Node group not in ACTIVE state | warning |
294
+
295
+ ### RDS
296
+ | Check | Severity |
297
+ |-------|----------|
298
+ | Instance not `available` | critical (failed) / warning |
299
+ | Storage encryption disabled | warning |
300
+ | Publicly accessible | warning |
301
+
302
+ ### Lambda
303
+ | Check | Severity |
304
+ |-------|----------|
305
+ | Function state not `Active` | warning |
306
+
307
+ ### S3
308
+ | Check | Severity |
309
+ |-------|----------|
310
+ | Public access not fully blocked | **critical** |
311
+ | Server-side encryption not enabled | warning |
312
+
313
+ ---
314
+
315
+ ## Terraform drift detection
316
+
317
+ ```bash
318
+ terraform show -json > tfstate.json
319
+ sudiviz drift --tfstate tfstate.json --region us-east-1
320
+ ```
321
+
322
+ Compares your Terraform state against live AWS. Covers:
323
+
324
+ | Terraform resource type | Live check |
325
+ |------------------------|------------|
326
+ | `aws_lb` / `aws_alb` | Load balancers |
327
+ | `aws_lb_target_group` | Target groups |
328
+ | `aws_security_group` | Security groups |
329
+ | `aws_instance` | EC2 instances |
330
+ | `aws_ecs_cluster` | ECS clusters |
331
+ | `aws_ecs_service` | ECS services |
332
+ | `aws_eks_cluster` | EKS clusters |
333
+ | `aws_db_instance` | RDS instances |
334
+ | `aws_lambda_function` | Lambda functions |
335
+
336
+ Drift kinds reported:
337
+
338
+ | Kind | Meaning |
339
+ |------|---------|
340
+ | `missing` | Terraform expects this, AWS doesn't have it |
341
+ | `orphan_in_aws` | AWS has it, Terraform doesn't (manual change) |
342
+ | `orphan_listener` | TF expected a listener TG, but no live listener routes there |
343
+
344
+ Exits non-zero on drift — use as a CI gate:
345
+
346
+ ```yaml
347
+ - run: sudiviz drift --tfstate plan.json --json > drift.json
348
+ ```
349
+
350
+ ---
351
+
352
+ ## CI / scripting (`--json`)
353
+
354
+ Every command emits machine-readable JSON with `--json`:
355
+
356
+ ```bash
357
+ # Fail CI if any critical issue exists
358
+ sudiviz diagnose --region us-east-1 --json | jq '.diagnosis.fixes[] | select(.severity=="critical")'
359
+
360
+ # Drift as a CI gate
361
+ sudiviz drift --tfstate tfstate.json --json
362
+ ```
363
+
364
+ Exit codes:
365
+
366
+ | Code | Meaning |
367
+ |------|---------|
368
+ | `0` | No critical findings / no drift |
369
+ | `1` | Drift detected (`drift` command) |
370
+ | `2` | At least one critical fix (`diagnose` command) |
371
+
372
+ ---
373
+
374
+ ## Automated remediation (`sudiviz fix`)
375
+
376
+ sudiviz can **automatically fix** diagnosed issues — not just report them.
377
+
378
+ ### Usage
379
+
380
+ ```bash
381
+ sudiviz fix # List all fixes (dry-run)
382
+ sudiviz fix 1 # Show fix #1 only
383
+ sudiviz fix 1 --apply # Apply fix #1
384
+ sudiviz fix 1,3 --apply # Apply fixes #1 and #3
385
+ sudiviz fix 1-3 --apply # Apply fixes #1, #2, and #3
386
+ sudiviz fix --apply # Apply all fixes
387
+ sudiviz fix --apply --force # Apply all fixes including destructive ones
388
+ ```
389
+
390
+ ### Example output
391
+
392
+ ```bash
393
+ $ sudiviz fix
394
+
395
+ Proposed fixes (dry-run):
396
+
397
+ 1. CRITICAL Security group missing port 80 from ALB SG
398
+ Add inbound rule to sg-instance: allow TCP/80 from sg-alb
399
+
400
+ aws ec2 authorize-security-group-ingress \
401
+ --region us-east-1 \
402
+ --group-id sg-instance \
403
+ --protocol tcp \
404
+ --port 80 \
405
+ --source-group sg-alb
406
+
407
+ 2. WARNING S3 bucket 'my-bucket': server-side encryption not enabled
408
+ Enable SSE-S3 encryption on bucket: my-bucket
409
+
410
+ aws s3api put-bucket-encryption \
411
+ --bucket my-bucket \
412
+ --server-side-encryption-configuration ...
413
+
414
+ Run with --apply to execute these fixes.
415
+ ```
416
+
417
+ ### Supported auto-fixes
418
+
419
+ | Issue | Fix applied |
420
+ |-------|-------------|
421
+ | Security group missing port from ALB SG | `ec2:AuthorizeSecurityGroupIngress` |
422
+ | S3 public access not blocked | `s3:PutPublicAccessBlock` |
423
+ | S3 encryption not enabled | `s3:PutBucketEncryption` |
424
+ | RDS publicly accessible | `rds:ModifyDBInstance` |
425
+ | Orphan target group | `elbv2:DeleteTargetGroup` (requires `--force`) |
426
+ | Unused security group | `ec2:DeleteSecurityGroup` (requires `--force`) |
427
+
428
+ ### IAM permissions required
429
+
430
+ For `sudiviz diagnose` (read-only):
431
+ - `ReadOnlyAccess` (AWS managed policy)
432
+
433
+ For `sudiviz fix --apply` (write operations):
434
+ - `AmazonEC2FullAccess` — security group fixes
435
+ - `ElasticLoadBalancingFullAccess` — delete orphan target groups
436
+ - `AmazonS3FullAccess` — S3 encryption and public access fixes
437
+ - `AmazonRDSFullAccess` — RDS public accessibility fixes
438
+
439
+ ### Safety
440
+
441
+ - **Dry-run by default** — always shows what would change before applying
442
+ - **Destructive operations require `--force`** — delete operations won't run without explicit flag
443
+ - **Selective application** — apply specific fixes by number instead of all at once
444
+
445
+ ---
446
+
447
+ ## Continuous monitoring
448
+
449
+ ```bash
450
+ sudiviz watch --interval 30 --region us-east-1
451
+ ```
452
+
453
+ Re-runs full discovery + analysis every `--interval` seconds. Pair with
454
+ `tmux` for an always-on dashboard. The web mode (`sudiviz graph --output web`)
455
+ is more ergonomic for long-running monitoring — it auto-refreshes via
456
+ WebSocket and lets you inspect nodes interactively.
457
+
458
+ ---
459
+
460
+ ## Bonus features
461
+
462
+ - **`sudiviz compare --baseline graph.json`** — diff a saved snapshot vs live topology (shows added/removed nodes).
463
+ - **`sudiviz share --upload`** — push graph JSON to transfer.sh for an ephemeral public link.
464
+ - **`sudiviz diagnose --speak`** — macOS `say` reads the top fixes aloud.
465
+
466
+ ---
467
+
468
+ ## Architecture
469
+
470
+ ```
471
+ sudiviz/
472
+ ├── cli.py # Typer commands: diagnose, drift, graph, tui, watch, compare, share
473
+ ├── tui.py # Textual TUI — live table + details pane
474
+ ├── web.py # FastAPI + WebSocket broadcast loop
475
+ ├── discovery/
476
+ │ ├── aws.py # boto3 + asyncio.to_thread — ECS/EKS/RDS/Lambda/S3/ALB/EC2/SG
477
+ │ ├── terraform.py # `terraform show -json` parser + drift detection
478
+ │ └── models.py # Pydantic v2 — provider-agnostic data models
479
+ ├── graph/
480
+ │ ├── builder.py # NetworkX DiGraph construction
481
+ │ ├── analyzer.py # Orphan detection + diagnostic rules + fix suggestions
482
+ │ └── visualizer.py # Terminal (Rich) / Cytoscape JSON / PNG (Graphviz)
483
+ ├── web_templates/
484
+ │ ├── index.html # Cytoscape.js app + WebSocket client
485
+ │ ├── style.css # Dark topbar, health-state colours, orphan pulse animation
486
+ │ └── cytoscape.js # Bundled Cytoscape (offline fallback)
487
+ └── utils/
488
+ ├── auth.py # boto3 session + STS identity + AWS Console URL builder
489
+ ├── reachability.py # VPC Reachability Analyzer integration (opt-in, paid)
490
+ └── branding.py # Logo, version, shared colour palette
491
+ ```
492
+
493
+ **Multi-cloud ready.** All discovery returns Pydantic types defined in
494
+ `discovery/models.py`. AWS-specific code is isolated to `discovery/aws.py`.
495
+ Add `discovery/azure.py` or `discovery/gcp.py` to extend without touching
496
+ the graph or visualization layer.
497
+
498
+ ---
499
+
500
+ ## Performance
501
+
502
+ - All boto3 calls run via `asyncio.to_thread` — parallel discovery with no extra dependencies.
503
+ - New service discovery (ECS, EKS, RDS, Lambda, S3) runs in the **same parallel gather** as ALB/EC2 — no extra latency.
504
+ - If any individual service fails (e.g. no EKS in the account), it logs a warning and returns an empty list — the rest of discovery continues.
505
+ - botocore retries are configured `mode="adaptive"` (exponential backoff + jitter).
506
+ - Pagination is fully drained for every API.
507
+ - The web server caches the latest discovery — multiple browser tabs don't trigger multiple sweeps.
508
+
509
+ ---
510
+
511
+ ## Development
512
+
513
+ ```bash
514
+ git clone https://github.com/sudiptoghosh/sudiviz
515
+ cd sudiviz
516
+ pip install -e '.[dev,all]'
517
+ pytest
518
+ ruff check .
519
+ mypy sudiviz
520
+ ```
521
+
522
+ ---
523
+
524
+ ## Publishing to PyPI
525
+
526
+ ```bash
527
+ pip install build twine
528
+ python -m build
529
+ python -m twine upload dist/*
530
+ ```
531
+
532
+ After upload, anyone can install with:
533
+
534
+ ```bash
535
+ pip install sudiviz
536
+ pip install 'sudiviz[all]'
537
+ ```
538
+
539
+ ---
540
+
541
+ ## License
542
+
543
+ MIT — see [LICENSE](LICENSE).