cloudwire 0.1.0__py3-none-any.whl
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/__init__.py +3 -0
- cloudwire/app/__init__.py +1 -0
- cloudwire/app/graph_store.py +88 -0
- cloudwire/app/main.py +453 -0
- cloudwire/app/models.py +83 -0
- cloudwire/app/scan_jobs.py +368 -0
- cloudwire/app/scanner.py +1149 -0
- cloudwire/cli.py +86 -0
- cloudwire/static/assets/index-CByMF4j6.js +40 -0
- cloudwire/static/assets/index-lik1Sxh5.css +1 -0
- cloudwire/static/index.html +13 -0
- cloudwire-0.1.0.dist-info/METADATA +186 -0
- cloudwire-0.1.0.dist-info/RECORD +16 -0
- cloudwire-0.1.0.dist-info/WHEEL +5 -0
- cloudwire-0.1.0.dist-info/entry_points.txt +2 -0
- cloudwire-0.1.0.dist-info/top_level.txt +1 -0
cloudwire/cli.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""CLI entry point for CloudWire."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import socket
|
|
7
|
+
import threading
|
|
8
|
+
import webbrowser
|
|
9
|
+
|
|
10
|
+
import click
|
|
11
|
+
import uvicorn
|
|
12
|
+
|
|
13
|
+
from . import __version__
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _port_is_available(host: str, port: int) -> bool:
|
|
17
|
+
"""Return True if the port is free to bind on the given host."""
|
|
18
|
+
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock:
|
|
19
|
+
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
20
|
+
try:
|
|
21
|
+
sock.bind((host, port))
|
|
22
|
+
return True
|
|
23
|
+
except OSError:
|
|
24
|
+
return False
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@click.command()
|
|
28
|
+
@click.option("--port", default=8080, show_default=True, help="Local port to listen on.")
|
|
29
|
+
@click.option("--host", default="127.0.0.1", show_default=True, help="Bind address. Never expose 0.0.0.0 on untrusted networks.")
|
|
30
|
+
@click.option("--profile", default=None, envvar="AWS_PROFILE", help="AWS credentials profile from ~/.aws/credentials.")
|
|
31
|
+
@click.option("--region", default="us-east-1", show_default=True, envvar="AWS_DEFAULT_REGION", help="Default AWS region.")
|
|
32
|
+
@click.option("--no-browser", is_flag=True, default=False, help="Do not open the browser automatically.")
|
|
33
|
+
@click.option("--print-url", is_flag=True, default=False, help="Print the URL to stdout and exit (useful for SSH tunnels).")
|
|
34
|
+
@click.version_option(version=__version__, prog_name="cloudwire")
|
|
35
|
+
def main(port: int, host: str, profile: str | None, region: str, no_browser: bool, print_url: bool) -> None:
|
|
36
|
+
"""Scan and visualize your AWS infrastructure as an interactive graph.
|
|
37
|
+
|
|
38
|
+
AWS credentials are read from the standard credential chain:
|
|
39
|
+
environment variables, ~/.aws/credentials profiles, and instance metadata.
|
|
40
|
+
Tools like saml2aws, aws-vault, and aws sso login all write to ~/.aws/credentials
|
|
41
|
+
and work automatically.
|
|
42
|
+
|
|
43
|
+
\b
|
|
44
|
+
Examples:
|
|
45
|
+
cloudwire # use default AWS profile
|
|
46
|
+
cloudwire --profile staging # use a named profile
|
|
47
|
+
cloudwire --region eu-west-1 # override region
|
|
48
|
+
cloudwire --port 9000 --no-browser # custom port, skip auto-open
|
|
49
|
+
cloudwire --print-url # print URL only (SSH tunnel use case)
|
|
50
|
+
"""
|
|
51
|
+
url = f"http://localhost:{port}"
|
|
52
|
+
|
|
53
|
+
# --print-url: just output the URL and exit (for scripting / SSH tunnels)
|
|
54
|
+
if print_url:
|
|
55
|
+
click.echo(url)
|
|
56
|
+
return
|
|
57
|
+
|
|
58
|
+
if profile:
|
|
59
|
+
os.environ["AWS_PROFILE"] = profile
|
|
60
|
+
|
|
61
|
+
# Only set region if not already in environment
|
|
62
|
+
os.environ.setdefault("AWS_DEFAULT_REGION", region)
|
|
63
|
+
|
|
64
|
+
# Port conflict check — fail fast with a clear message
|
|
65
|
+
if not _port_is_available(host, port):
|
|
66
|
+
raise click.ClickException(
|
|
67
|
+
f"Port {port} is already in use. Try a different port with --port <number>."
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
click.echo("")
|
|
71
|
+
click.echo(f" cloudwire {__version__}")
|
|
72
|
+
click.echo(f" Running at → {url}")
|
|
73
|
+
click.echo(" Press Ctrl+C to stop.\n")
|
|
74
|
+
|
|
75
|
+
if not no_browser:
|
|
76
|
+
threading.Timer(1.5, lambda: webbrowser.open(url)).start()
|
|
77
|
+
|
|
78
|
+
try:
|
|
79
|
+
uvicorn.run(
|
|
80
|
+
"cloudwire.app.main:app",
|
|
81
|
+
host=host,
|
|
82
|
+
port=port,
|
|
83
|
+
log_level="warning",
|
|
84
|
+
)
|
|
85
|
+
except KeyboardInterrupt:
|
|
86
|
+
click.echo("\n Stopped.")
|