cloudwire 0.2.5__tar.gz → 0.2.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.
- {cloudwire-0.2.5 → cloudwire-0.2.6}/PKG-INFO +6 -17
- {cloudwire-0.2.5 → cloudwire-0.2.6}/README.md +1 -16
- cloudwire-0.2.6/cloudwire/__init__.py +8 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/main.py +42 -1
- cloudwire-0.2.6/cloudwire/static/assets/index-CJlbfCBD.js +40 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/static/index.html +1 -1
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire.egg-info/PKG-INFO +6 -17
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire.egg-info/SOURCES.txt +2 -2
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire.egg-info/requires.txt +2 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/pyproject.toml +15 -2
- cloudwire-0.2.5/cloudwire/__init__.py +0 -3
- cloudwire-0.2.5/cloudwire/static/assets/index-B17mpnyB.js +0 -40
- {cloudwire-0.2.5 → cloudwire-0.2.6}/LICENSE +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/__init__.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/aws_clients.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/errors.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/graph_store.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/hcl_parser.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/models.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/routes/__init__.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/routes/scan.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/routes/tags.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/routes/terraform.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/scan_jobs.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/scanner.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/scanners/__init__.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/scanners/_utils.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/scanners/apigateway.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/scanners/appsync.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/scanners/cloudfront.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/scanners/cognito.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/scanners/dynamodb.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/scanners/ec2.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/scanners/ecs.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/scanners/elasticache.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/scanners/eventbridge.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/scanners/glue.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/scanners/iam.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/scanners/kinesis.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/scanners/lambda_.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/scanners/rds.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/scanners/redshift.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/scanners/route53.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/scanners/s3.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/scanners/sns.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/scanners/sqs.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/scanners/stepfunctions.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/scanners/vpc.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/services.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/app/terraform_parser.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/cli.py +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/static/assets/index-BlarXbuP.css +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire/static/favicon.svg +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire.egg-info/dependency_links.txt +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire.egg-info/entry_points.txt +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/cloudwire.egg-info/top_level.txt +0 -0
- {cloudwire-0.2.5 → cloudwire-0.2.6}/setup.cfg +0 -0
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cloudwire
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.6
|
|
4
4
|
Summary: Scan and visualize your AWS infrastructure as an interactive graph
|
|
5
5
|
License-Expression: MIT
|
|
6
6
|
Project-URL: Homepage, https://github.com/Himanshu-370/cloudwire
|
|
7
7
|
Project-URL: Issues, https://github.com/Himanshu-370/cloudwire/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/Himanshu-370/cloudwire/blob/main/CHANGELOG.md
|
|
9
|
+
Project-URL: Documentation, https://github.com/Himanshu-370/cloudwire/blob/main/docs/USAGE.md
|
|
8
10
|
Keywords: aws,cloud,visualization,graph,infrastructure
|
|
9
11
|
Classifier: Development Status :: 4 - Beta
|
|
10
12
|
Classifier: Environment :: Console
|
|
@@ -25,6 +27,8 @@ License-File: LICENSE
|
|
|
25
27
|
Provides-Extra: dev
|
|
26
28
|
Requires-Dist: twine; extra == "dev"
|
|
27
29
|
Requires-Dist: build; extra == "dev"
|
|
30
|
+
Requires-Dist: ruff>=0.4; extra == "dev"
|
|
31
|
+
Requires-Dist: mypy>=1.0; extra == "dev"
|
|
28
32
|
Provides-Extra: dependencies
|
|
29
33
|
Requires-Dist: fastapi>=0.100; extra == "dependencies"
|
|
30
34
|
Requires-Dist: uvicorn>=0.20; extra == "dependencies"
|
|
@@ -54,16 +58,6 @@ No data leaves your system. AWS credentials never leave your terminal. The graph
|
|
|
54
58
|
<img src="docs/cloudgraph.svg" alt="CloudWire — AWS infrastructure graph visualization" width="100%">
|
|
55
59
|
</p>
|
|
56
60
|
|
|
57
|
-
> **Note:** The screenshot above contains placeholder resource IDs. Replace `docs/cloudgraph.svg` with a sanitized screenshot from your own environment.
|
|
58
|
-
|
|
59
|
-
<!-- TODO: Once a demo video is recorded, replace the static image above with:
|
|
60
|
-
<p align="center">
|
|
61
|
-
<a href="https://www.youtube.com/watch?v=YOUR_VIDEO_ID">
|
|
62
|
-
<img src="docs/demo-thumbnail.png" alt="CloudWire demo — click to watch" width="100%">
|
|
63
|
-
</a>
|
|
64
|
-
</p>
|
|
65
|
-
-->
|
|
66
|
-
|
|
67
61
|
---
|
|
68
62
|
|
|
69
63
|
## Quick start
|
|
@@ -96,14 +90,9 @@ On first load, select the services you want to scan from the top bar and click *
|
|
|
96
90
|
- **Tag-based scanning** — discover and scan resources by AWS tags
|
|
97
91
|
- **Terraform import** — upload `.tfstate` or `.tf` files to visualize without AWS credentials
|
|
98
92
|
- **Analysis tools** — blast radius, shortest path, architecture summary, pattern detection
|
|
99
|
-
- **
|
|
93
|
+
- **Three layout modes** — Circular, Flow, Swimlane — switchable from the toolbar
|
|
100
94
|
- **Permission-aware** — missing IAM policies surfaced clearly, never blocks the scan
|
|
101
95
|
|
|
102
|
-
<!-- TODO: Add 2-3 annotated screenshots here showing:
|
|
103
|
-
1. Full UI with sidebar + multi-service graph (Lambda → SQS → DynamoDB)
|
|
104
|
-
2. Inspector panel open on a node showing attributes and edges
|
|
105
|
-
3. VPC topology view with AZ grouping
|
|
106
|
-
-->
|
|
107
96
|
|
|
108
97
|
---
|
|
109
98
|
|
|
@@ -15,16 +15,6 @@ No data leaves your system. AWS credentials never leave your terminal. The graph
|
|
|
15
15
|
<img src="docs/cloudgraph.svg" alt="CloudWire — AWS infrastructure graph visualization" width="100%">
|
|
16
16
|
</p>
|
|
17
17
|
|
|
18
|
-
> **Note:** The screenshot above contains placeholder resource IDs. Replace `docs/cloudgraph.svg` with a sanitized screenshot from your own environment.
|
|
19
|
-
|
|
20
|
-
<!-- TODO: Once a demo video is recorded, replace the static image above with:
|
|
21
|
-
<p align="center">
|
|
22
|
-
<a href="https://www.youtube.com/watch?v=YOUR_VIDEO_ID">
|
|
23
|
-
<img src="docs/demo-thumbnail.png" alt="CloudWire demo — click to watch" width="100%">
|
|
24
|
-
</a>
|
|
25
|
-
</p>
|
|
26
|
-
-->
|
|
27
|
-
|
|
28
18
|
---
|
|
29
19
|
|
|
30
20
|
## Quick start
|
|
@@ -57,14 +47,9 @@ On first load, select the services you want to scan from the top bar and click *
|
|
|
57
47
|
- **Tag-based scanning** — discover and scan resources by AWS tags
|
|
58
48
|
- **Terraform import** — upload `.tfstate` or `.tf` files to visualize without AWS credentials
|
|
59
49
|
- **Analysis tools** — blast radius, shortest path, architecture summary, pattern detection
|
|
60
|
-
- **
|
|
50
|
+
- **Three layout modes** — Circular, Flow, Swimlane — switchable from the toolbar
|
|
61
51
|
- **Permission-aware** — missing IAM policies surfaced clearly, never blocks the scan
|
|
62
52
|
|
|
63
|
-
<!-- TODO: Add 2-3 annotated screenshots here showing:
|
|
64
|
-
1. Full UI with sidebar + multi-service graph (Lambda → SQS → DynamoDB)
|
|
65
|
-
2. Inspector panel open on a node showing attributes and edges
|
|
66
|
-
3. VPC topology view with AZ grouping
|
|
67
|
-
-->
|
|
68
53
|
|
|
69
54
|
---
|
|
70
55
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""CloudWire — scan and visualize your AWS infrastructure."""
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
4
|
+
|
|
5
|
+
try:
|
|
6
|
+
__version__ = version("cloudwire")
|
|
7
|
+
except PackageNotFoundError:
|
|
8
|
+
__version__ = "0.2.6" # fallback when running from source without pip install
|
|
@@ -43,9 +43,41 @@ app = FastAPI(title="CloudWire API", version=_app_version, lifespan=lifespan)
|
|
|
43
43
|
|
|
44
44
|
|
|
45
45
|
# ---------------------------------------------------------------------------
|
|
46
|
-
#
|
|
46
|
+
# Middleware — registered last-in first-out (outermost executes first)
|
|
47
47
|
# ---------------------------------------------------------------------------
|
|
48
48
|
|
|
49
|
+
_MAX_JSON_BODY_BYTES = 2 * 1024 * 1024 # 2 MB
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class RequestBodyLimitMiddleware(BaseHTTPMiddleware):
|
|
53
|
+
"""Reject oversized JSON request bodies before Pydantic validation."""
|
|
54
|
+
|
|
55
|
+
async def dispatch(self, request: Request, call_next):
|
|
56
|
+
content_type = request.headers.get("content-type", "")
|
|
57
|
+
if "application/json" in content_type:
|
|
58
|
+
# Fast path: reject immediately if Content-Length header exceeds limit
|
|
59
|
+
content_length = request.headers.get("content-length")
|
|
60
|
+
if content_length and int(content_length) > _MAX_JSON_BODY_BYTES:
|
|
61
|
+
return JSONResponse(
|
|
62
|
+
status_code=413,
|
|
63
|
+
content=error_payload(
|
|
64
|
+
"payload_too_large",
|
|
65
|
+
f"Request body exceeds the {_MAX_JSON_BODY_BYTES // (1024 * 1024)} MB limit.",
|
|
66
|
+
),
|
|
67
|
+
)
|
|
68
|
+
# Also check actual body size (handles chunked transfers / missing header)
|
|
69
|
+
body = await request.body()
|
|
70
|
+
if len(body) > _MAX_JSON_BODY_BYTES:
|
|
71
|
+
return JSONResponse(
|
|
72
|
+
status_code=413,
|
|
73
|
+
content=error_payload(
|
|
74
|
+
"payload_too_large",
|
|
75
|
+
f"Request body exceeds the {_MAX_JSON_BODY_BYTES // (1024 * 1024)} MB limit.",
|
|
76
|
+
),
|
|
77
|
+
)
|
|
78
|
+
return await call_next(request)
|
|
79
|
+
|
|
80
|
+
|
|
49
81
|
class SecurityHeadersMiddleware(BaseHTTPMiddleware):
|
|
50
82
|
async def dispatch(self, request: Request, call_next):
|
|
51
83
|
response = await call_next(request)
|
|
@@ -56,6 +88,7 @@ class SecurityHeadersMiddleware(BaseHTTPMiddleware):
|
|
|
56
88
|
return response
|
|
57
89
|
|
|
58
90
|
|
|
91
|
+
app.add_middleware(RequestBodyLimitMiddleware)
|
|
59
92
|
app.add_middleware(SecurityHeadersMiddleware)
|
|
60
93
|
|
|
61
94
|
|
|
@@ -123,6 +156,14 @@ if _STATIC_DIR.is_dir() and ((_STATIC_DIR / "assets").is_dir()):
|
|
|
123
156
|
app.mount("/assets", StaticFiles(directory=str(_STATIC_DIR / "assets")), name="assets")
|
|
124
157
|
|
|
125
158
|
|
|
159
|
+
@app.api_route("/api/{api_path:path}", methods=["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"], include_in_schema=False)
|
|
160
|
+
def api_not_found(api_path: str) -> JSONResponse:
|
|
161
|
+
return JSONResponse(
|
|
162
|
+
status_code=404,
|
|
163
|
+
content=error_payload("not_found", f"API endpoint '/api/{api_path}' not found."),
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
|
|
126
167
|
@app.get("/{full_path:path}", include_in_schema=False)
|
|
127
168
|
def spa_fallback(full_path: str) -> FileResponse:
|
|
128
169
|
index = _STATIC_DIR / "index.html"
|