plexavo 0.2.4__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.
- plexavo-0.2.6/PKG-INFO +180 -0
- plexavo-0.2.6/README.md +151 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/__init__.py +1 -1
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/cli.py +1 -1
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/report/ai_narration.py +29 -3
- plexavo-0.2.6/plexavo.egg-info/PKG-INFO +180 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/pyproject.toml +1 -1
- {plexavo-0.2.4 → plexavo-0.2.6}/tests/test_ai_narration_offline.py +14 -2
- plexavo-0.2.4/PKG-INFO +0 -324
- plexavo-0.2.4/README.md +0 -295
- plexavo-0.2.4/plexavo.egg-info/PKG-INFO +0 -324
- {plexavo-0.2.4 → plexavo-0.2.6}/LICENSE +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/__main__.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/auth.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/aws_profile_setup.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/checks/__init__.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/checks/encryption.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/checks/iam.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/checks/iam_hygiene.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/checks/logging.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/checks/network.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/checks/storage.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/checks/usage.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/findings.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/interactive.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/principals.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/report/__init__.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/report/fonts/DejaVuSans-Bold.ttf +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/report/fonts/DejaVuSans-BoldOblique.ttf +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/report/fonts/DejaVuSans-Oblique.ttf +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/report/fonts/DejaVuSans.ttf +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/report/fonts/GEIST-FONT-LICENSE.txt +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/report/html_report.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/report/pdf.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/report/templates/report.html.j2 +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/scoring.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo.egg-info/SOURCES.txt +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo.egg-info/dependency_links.txt +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo.egg-info/entry_points.txt +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo.egg-info/requires.txt +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/plexavo.egg-info/top_level.txt +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/setup.cfg +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/tests/test_auth_offline.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/tests/test_cli_entrypoint.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/tests/test_encryption_offline.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/tests/test_iam_hygiene_offline.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/tests/test_iam_offline.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/tests/test_logging_offline.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/tests/test_network_offline.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/tests/test_report_offline.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/tests/test_scoring.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/tests/test_storage_offline.py +0 -0
- {plexavo-0.2.4 → plexavo-0.2.6}/tests/test_usage_offline.py +0 -0
plexavo-0.2.6/PKG-INFO
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: plexavo
|
|
3
|
+
Version: 0.2.6
|
|
4
|
+
Summary: Open-source AWS misconfiguration scanner — runs with your own local AWS credentials, nothing sent to anyone else.
|
|
5
|
+
Author: Kavee
|
|
6
|
+
License: AGPL-3.0-or-later
|
|
7
|
+
Project-URL: Homepage, https://github.com/plexavo/Plexavo
|
|
8
|
+
Project-URL: Issues, https://github.com/plexavo/Plexavo/issues
|
|
9
|
+
Project-URL: Security, https://github.com/plexavo/Plexavo/blob/main/SECURITY.md
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
|
|
12
|
+
Classifier: Topic :: Security
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Requires-Python: >=3.9
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: boto3>=1.34
|
|
18
|
+
Requires-Dist: python-dateutil>=2.9
|
|
19
|
+
Requires-Dist: rich>=13.7
|
|
20
|
+
Requires-Dist: jinja2>=3.1
|
|
21
|
+
Requires-Dist: markupsafe>=2.1
|
|
22
|
+
Requires-Dist: fpdf2>=2.8
|
|
23
|
+
Provides-Extra: ai
|
|
24
|
+
Requires-Dist: anthropic>=0.116; extra == "ai"
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
27
|
+
Requires-Dist: pypdf>=4.0; extra == "dev"
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
<div align="center">
|
|
31
|
+
<picture>
|
|
32
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/plexavo-logo-dark.png">
|
|
33
|
+
<img src="assets/plexavo-logo-light.png" alt="Plexavo" height="115">
|
|
34
|
+
</picture>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
# Plexavo
|
|
38
|
+
|
|
39
|
+
<div align="center">
|
|
40
|
+
<img src="assets/demo.gif" alt="Plexavo interactive scan demo" width="800">
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
Plexavo is an open-source cloud security tool that audits AWS accounts
|
|
44
|
+
for real-world misconfigurations. It runs entirely with your own local
|
|
45
|
+
AWS credentials, the same way you'd run `aws s3 ls`, so nothing about
|
|
46
|
+
your account is ever handed to anyone else. Each scan produces a 0-100
|
|
47
|
+
security score and a plain-English report: what's wrong, what an
|
|
48
|
+
attacker would actually do with it, and the exact command to fix it.
|
|
49
|
+
|
|
50
|
+
Detection is pure Python/boto3, never AI. Claude only rewrites
|
|
51
|
+
already-found technical findings into something a non-security founder
|
|
52
|
+
can read, and it's entirely optional. See [Cost](#cost).
|
|
53
|
+
|
|
54
|
+
## What it checks
|
|
55
|
+
|
|
56
|
+
31 checks across 6 categories, run against real AWS accounts:
|
|
57
|
+
|
|
58
|
+
- **IAM**: privilege escalation paths, wildcard admin, cross-account
|
|
59
|
+
trust, root usage, dormant credentials
|
|
60
|
+
- **Network**: security groups and RDS instances exposed to the
|
|
61
|
+
internet
|
|
62
|
+
- **Storage**: public S3 buckets, via ACLs, bucket policies, or missing
|
|
63
|
+
Block Public Access
|
|
64
|
+
- **Encryption**: unencrypted EBS volumes, RDS instances, S3 buckets
|
|
65
|
+
- **Logging**: CloudTrail coverage and encryption, GuardDuty status
|
|
66
|
+
- **Usage**: permissions granted but never used, roles nobody has
|
|
67
|
+
assumed in 90+ days
|
|
68
|
+
|
|
69
|
+
See the `docs/*-TEST-MATRIX.md` files for exactly how each check was
|
|
70
|
+
verified.
|
|
71
|
+
|
|
72
|
+
## Installation
|
|
73
|
+
|
|
74
|
+
Every path below installs Plexavo into its own isolated environment.
|
|
75
|
+
|
|
76
|
+
### macOS & Linux
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh # skip if you have uv
|
|
80
|
+
uv tool install plexavo
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Prefer [pipx](https://pipx.pypa.io/)? `pipx install plexavo` works the
|
|
84
|
+
same way.
|
|
85
|
+
|
|
86
|
+
### Windows
|
|
87
|
+
|
|
88
|
+
`uv`/`pipx` still work, but the launcher they put on your PATH is
|
|
89
|
+
unsigned, and Windows Smart App Control blocks it. Run Plexavo through
|
|
90
|
+
Python instead, two options:
|
|
91
|
+
|
|
92
|
+
**Option 1, uv (recommended)**
|
|
93
|
+
|
|
94
|
+
```powershell
|
|
95
|
+
uv tool install plexavo
|
|
96
|
+
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
|
|
97
|
+
if (!(Test-Path $PROFILE)) { New-Item -ItemType File -Path $PROFILE -Force }
|
|
98
|
+
Add-Content $PROFILE 'function plexavo { & "$env:APPDATA\uv\tools\plexavo\Scripts\python.exe" -m plexavo @args }'
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Open a new terminal. `plexavo` now works exactly like it does on
|
|
102
|
+
macOS/Linux, routed through uv's signed Python instead of the blocked
|
|
103
|
+
launcher.
|
|
104
|
+
|
|
105
|
+
**Option 2, plain venv**
|
|
106
|
+
|
|
107
|
+
```powershell
|
|
108
|
+
py -m venv plexavo-venv
|
|
109
|
+
.\plexavo-venv\Scripts\Activate.ps1
|
|
110
|
+
python -m pip install plexavo
|
|
111
|
+
python -m plexavo
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Use `python -m` for everything here too. The venv's own `pip.exe` and
|
|
115
|
+
`plexavo.exe` are unsigned as well, only `python.exe` is signed.
|
|
116
|
+
|
|
117
|
+
### AI narration (optional)
|
|
118
|
+
|
|
119
|
+
Want each finding rewritten as a full narrative? Install `"plexavo[ai]"`
|
|
120
|
+
instead of `plexavo`, and set `ANTHROPIC_API_KEY`. See [Cost](#cost).
|
|
121
|
+
|
|
122
|
+
## Using Plexavo
|
|
123
|
+
|
|
124
|
+
Run it with no arguments and it walks you through everything: picking an
|
|
125
|
+
AWS profile, choosing HTML or PDF, then scanning and showing your score
|
|
126
|
+
with every finding.
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
plexavo # macOS/Linux, and Windows Option 1
|
|
130
|
+
python -m plexavo # Windows Option 2
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
<div align="center">
|
|
134
|
+
<img src="assets/screenshot-cli.png" alt="Plexavo interactive CLI" width="700">
|
|
135
|
+
</div>
|
|
136
|
+
|
|
137
|
+
## The report
|
|
138
|
+
|
|
139
|
+
Reports are generated as HTML, PDF, or both. Every finding gets a free,
|
|
140
|
+
template-based fix by default, no key, no cost. Full AI-written
|
|
141
|
+
narration is offered automatically only when an `ANTHROPIC_API_KEY` is
|
|
142
|
+
detected, see [Cost](#cost).
|
|
143
|
+
|
|
144
|
+
<div align="center">
|
|
145
|
+
<img src="assets/screenshot-report.png" alt="Plexavo HTML report" width="700">
|
|
146
|
+
</div>
|
|
147
|
+
|
|
148
|
+
Severity, confidence, and evidence are always shown as separate signals.
|
|
149
|
+
A low-confidence Critical never reads the same as a high-confidence
|
|
150
|
+
Medium.
|
|
151
|
+
|
|
152
|
+
## Cost
|
|
153
|
+
|
|
154
|
+
Detection and the free templates always cost nothing. Live AI only runs
|
|
155
|
+
with `--explain`, using **your own** `ANTHROPIC_API_KEY` in **your own**
|
|
156
|
+
Anthropic account. Plexavo never sees your key and never calls the API
|
|
157
|
+
without it. A full scan with `--explain` typically costs a few cents.
|
|
158
|
+
|
|
159
|
+
## Contributing
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
git clone https://github.com/plexavo/plexavo.git
|
|
163
|
+
cd plexavo
|
|
164
|
+
uv pip install -e .
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
See [`CONTRIBUTING.md`](CONTRIBUTING.md) for the pattern used to add a
|
|
168
|
+
new check.
|
|
169
|
+
|
|
170
|
+
## Security
|
|
171
|
+
|
|
172
|
+
Found a vulnerability in the tool itself, not a misconfiguration in your
|
|
173
|
+
own AWS account (that's the tool working correctly)? See
|
|
174
|
+
[`SECURITY.md`](SECURITY.md) for a private reporting path.
|
|
175
|
+
|
|
176
|
+
## License
|
|
177
|
+
|
|
178
|
+
AGPL-3.0, see [`LICENSE`](LICENSE). Use, run, and modify it freely. If
|
|
179
|
+
you run a modified version as a hosted service, you're required to
|
|
180
|
+
publish those modifications too.
|
plexavo-0.2.6/README.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/plexavo-logo-dark.png">
|
|
4
|
+
<img src="assets/plexavo-logo-light.png" alt="Plexavo" height="115">
|
|
5
|
+
</picture>
|
|
6
|
+
</div>
|
|
7
|
+
|
|
8
|
+
# Plexavo
|
|
9
|
+
|
|
10
|
+
<div align="center">
|
|
11
|
+
<img src="assets/demo.gif" alt="Plexavo interactive scan demo" width="800">
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
Plexavo is an open-source cloud security tool that audits AWS accounts
|
|
15
|
+
for real-world misconfigurations. It runs entirely with your own local
|
|
16
|
+
AWS credentials, the same way you'd run `aws s3 ls`, so nothing about
|
|
17
|
+
your account is ever handed to anyone else. Each scan produces a 0-100
|
|
18
|
+
security score and a plain-English report: what's wrong, what an
|
|
19
|
+
attacker would actually do with it, and the exact command to fix it.
|
|
20
|
+
|
|
21
|
+
Detection is pure Python/boto3, never AI. Claude only rewrites
|
|
22
|
+
already-found technical findings into something a non-security founder
|
|
23
|
+
can read, and it's entirely optional. See [Cost](#cost).
|
|
24
|
+
|
|
25
|
+
## What it checks
|
|
26
|
+
|
|
27
|
+
31 checks across 6 categories, run against real AWS accounts:
|
|
28
|
+
|
|
29
|
+
- **IAM**: privilege escalation paths, wildcard admin, cross-account
|
|
30
|
+
trust, root usage, dormant credentials
|
|
31
|
+
- **Network**: security groups and RDS instances exposed to the
|
|
32
|
+
internet
|
|
33
|
+
- **Storage**: public S3 buckets, via ACLs, bucket policies, or missing
|
|
34
|
+
Block Public Access
|
|
35
|
+
- **Encryption**: unencrypted EBS volumes, RDS instances, S3 buckets
|
|
36
|
+
- **Logging**: CloudTrail coverage and encryption, GuardDuty status
|
|
37
|
+
- **Usage**: permissions granted but never used, roles nobody has
|
|
38
|
+
assumed in 90+ days
|
|
39
|
+
|
|
40
|
+
See the `docs/*-TEST-MATRIX.md` files for exactly how each check was
|
|
41
|
+
verified.
|
|
42
|
+
|
|
43
|
+
## Installation
|
|
44
|
+
|
|
45
|
+
Every path below installs Plexavo into its own isolated environment.
|
|
46
|
+
|
|
47
|
+
### macOS & Linux
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh # skip if you have uv
|
|
51
|
+
uv tool install plexavo
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Prefer [pipx](https://pipx.pypa.io/)? `pipx install plexavo` works the
|
|
55
|
+
same way.
|
|
56
|
+
|
|
57
|
+
### Windows
|
|
58
|
+
|
|
59
|
+
`uv`/`pipx` still work, but the launcher they put on your PATH is
|
|
60
|
+
unsigned, and Windows Smart App Control blocks it. Run Plexavo through
|
|
61
|
+
Python instead, two options:
|
|
62
|
+
|
|
63
|
+
**Option 1, uv (recommended)**
|
|
64
|
+
|
|
65
|
+
```powershell
|
|
66
|
+
uv tool install plexavo
|
|
67
|
+
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
|
|
68
|
+
if (!(Test-Path $PROFILE)) { New-Item -ItemType File -Path $PROFILE -Force }
|
|
69
|
+
Add-Content $PROFILE 'function plexavo { & "$env:APPDATA\uv\tools\plexavo\Scripts\python.exe" -m plexavo @args }'
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Open a new terminal. `plexavo` now works exactly like it does on
|
|
73
|
+
macOS/Linux, routed through uv's signed Python instead of the blocked
|
|
74
|
+
launcher.
|
|
75
|
+
|
|
76
|
+
**Option 2, plain venv**
|
|
77
|
+
|
|
78
|
+
```powershell
|
|
79
|
+
py -m venv plexavo-venv
|
|
80
|
+
.\plexavo-venv\Scripts\Activate.ps1
|
|
81
|
+
python -m pip install plexavo
|
|
82
|
+
python -m plexavo
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
Use `python -m` for everything here too. The venv's own `pip.exe` and
|
|
86
|
+
`plexavo.exe` are unsigned as well, only `python.exe` is signed.
|
|
87
|
+
|
|
88
|
+
### AI narration (optional)
|
|
89
|
+
|
|
90
|
+
Want each finding rewritten as a full narrative? Install `"plexavo[ai]"`
|
|
91
|
+
instead of `plexavo`, and set `ANTHROPIC_API_KEY`. See [Cost](#cost).
|
|
92
|
+
|
|
93
|
+
## Using Plexavo
|
|
94
|
+
|
|
95
|
+
Run it with no arguments and it walks you through everything: picking an
|
|
96
|
+
AWS profile, choosing HTML or PDF, then scanning and showing your score
|
|
97
|
+
with every finding.
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
plexavo # macOS/Linux, and Windows Option 1
|
|
101
|
+
python -m plexavo # Windows Option 2
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
<div align="center">
|
|
105
|
+
<img src="assets/screenshot-cli.png" alt="Plexavo interactive CLI" width="700">
|
|
106
|
+
</div>
|
|
107
|
+
|
|
108
|
+
## The report
|
|
109
|
+
|
|
110
|
+
Reports are generated as HTML, PDF, or both. Every finding gets a free,
|
|
111
|
+
template-based fix by default, no key, no cost. Full AI-written
|
|
112
|
+
narration is offered automatically only when an `ANTHROPIC_API_KEY` is
|
|
113
|
+
detected, see [Cost](#cost).
|
|
114
|
+
|
|
115
|
+
<div align="center">
|
|
116
|
+
<img src="assets/screenshot-report.png" alt="Plexavo HTML report" width="700">
|
|
117
|
+
</div>
|
|
118
|
+
|
|
119
|
+
Severity, confidence, and evidence are always shown as separate signals.
|
|
120
|
+
A low-confidence Critical never reads the same as a high-confidence
|
|
121
|
+
Medium.
|
|
122
|
+
|
|
123
|
+
## Cost
|
|
124
|
+
|
|
125
|
+
Detection and the free templates always cost nothing. Live AI only runs
|
|
126
|
+
with `--explain`, using **your own** `ANTHROPIC_API_KEY` in **your own**
|
|
127
|
+
Anthropic account. Plexavo never sees your key and never calls the API
|
|
128
|
+
without it. A full scan with `--explain` typically costs a few cents.
|
|
129
|
+
|
|
130
|
+
## Contributing
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
git clone https://github.com/plexavo/plexavo.git
|
|
134
|
+
cd plexavo
|
|
135
|
+
uv pip install -e .
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
See [`CONTRIBUTING.md`](CONTRIBUTING.md) for the pattern used to add a
|
|
139
|
+
new check.
|
|
140
|
+
|
|
141
|
+
## Security
|
|
142
|
+
|
|
143
|
+
Found a vulnerability in the tool itself, not a misconfiguration in your
|
|
144
|
+
own AWS account (that's the tool working correctly)? See
|
|
145
|
+
[`SECURITY.md`](SECURITY.md) for a private reporting path.
|
|
146
|
+
|
|
147
|
+
## License
|
|
148
|
+
|
|
149
|
+
AGPL-3.0, see [`LICENSE`](LICENSE). Use, run, and modify it freely. If
|
|
150
|
+
you run a modified version as a hosted service, you're required to
|
|
151
|
+
publish those modifications too.
|
|
@@ -83,7 +83,7 @@ def _build_parser() -> argparse.ArgumentParser:
|
|
|
83
83
|
"key. No key set, or a call fails for any reason? That finding falls back to raw "
|
|
84
84
|
"detail automatically, the scan never stops because of it. Off by default — without "
|
|
85
85
|
"it, findings still get free, no-API-key-needed remediation text wherever a template "
|
|
86
|
-
"exists (
|
|
86
|
+
"exists (11 common check types); --explain always uses live AI instead, for every "
|
|
87
87
|
"finding, not just the non-templated ones.")
|
|
88
88
|
scan.add_argument("--explain-limit", type=int, default=25,
|
|
89
89
|
help="Safety cap on how many findings get a live AI call when --explain is passed, in "
|
|
@@ -172,7 +172,7 @@ def _parse_sections(raw_text: str) -> tuple[str, str, str]:
|
|
|
172
172
|
|
|
173
173
|
|
|
174
174
|
# ---------------------------------------------------------------------------
|
|
175
|
-
# Templates for the
|
|
175
|
+
# Templates for the 11 most common, narratively-generic check types.
|
|
176
176
|
# Every specific fact (resource names, chain targets) already lives in
|
|
177
177
|
# the Finding's own fields, computed deterministically in Python — the
|
|
178
178
|
# template just substitutes them into fixed prose matching the same
|
|
@@ -373,6 +373,31 @@ def _template_enc29(f: Finding) -> Explanation:
|
|
|
373
373
|
)
|
|
374
374
|
|
|
375
375
|
|
|
376
|
+
def _template_log25(f: Finding) -> Explanation:
|
|
377
|
+
return Explanation(
|
|
378
|
+
impact=(
|
|
379
|
+
"GuardDuty is not enabled in this region, so there is no automated threat detection watching the "
|
|
380
|
+
"account. GuardDuty continuously analyzes CloudTrail, VPC flow logs, and DNS logs for known-bad "
|
|
381
|
+
"signals — an access key suddenly used from a new country or a Tor exit node, an EC2 instance "
|
|
382
|
+
"calling a known crypto-mining or malware domain, someone running account-wide recon with calls "
|
|
383
|
+
"like iam:ListUsers, ec2:DescribeInstances, and s3:ListAllMyBuckets in quick succession. With it "
|
|
384
|
+
"off, all of that happens with nothing raising an alert, so a compromise is usually only noticed "
|
|
385
|
+
"once it causes visible damage or a surprise bill."
|
|
386
|
+
),
|
|
387
|
+
how_to_fix=(
|
|
388
|
+
"Enable GuardDuty in this region, then confirm the detector is active:\n"
|
|
389
|
+
"aws guardduty create-detector --enable\n"
|
|
390
|
+
"aws guardduty list-detectors\n"
|
|
391
|
+
"GuardDuty is per-region, so repeat this in every region you run workloads in, or enable it for "
|
|
392
|
+
"the whole organization from your AWS Organizations management account. It is free for the first "
|
|
393
|
+
"30 days, then billed on the volume of logs analyzed (typically a few dollars a month for a small "
|
|
394
|
+
"account)."
|
|
395
|
+
),
|
|
396
|
+
next_step="Turn GuardDuty on in this region now: aws guardduty create-detector --enable",
|
|
397
|
+
source="template",
|
|
398
|
+
)
|
|
399
|
+
|
|
400
|
+
|
|
376
401
|
COMMON_CHECK_TEMPLATES = {
|
|
377
402
|
"IAM-01": _template_iam01,
|
|
378
403
|
"IAM-06": _template_iam06,
|
|
@@ -384,18 +409,19 @@ COMMON_CHECK_TEMPLATES = {
|
|
|
384
409
|
"NET-02": _template_net02,
|
|
385
410
|
"STOR-19": _template_stor19,
|
|
386
411
|
"ENC-29": _template_enc29,
|
|
412
|
+
"LOG-25": _template_log25,
|
|
387
413
|
}
|
|
388
414
|
|
|
389
415
|
|
|
390
416
|
def explain_finding(finding: Finding, client=None, use_ai: bool = False) -> Explanation | None:
|
|
391
417
|
"""use_ai=False (default): route to the free template (zero API cost,
|
|
392
|
-
zero network) for the
|
|
418
|
+
zero network) for the 11 most common, narratively-generic check
|
|
393
419
|
types; every other check returns None (raw finding detail only — no
|
|
394
420
|
API call is ever attempted in this mode, regardless of whether a key
|
|
395
421
|
is configured). This is the always-on baseline — no flag needed to
|
|
396
422
|
get free remediation guidance where a template exists.
|
|
397
423
|
|
|
398
|
-
use_ai=True: every finding, including the
|
|
424
|
+
use_ai=True: every finding, including the 11 templated ones, is sent
|
|
399
425
|
to Claude instead — deliberately bypasses the template shortcut so
|
|
400
426
|
"AI narration on" always means fully AI-written content, never a mix
|
|
401
427
|
of template and AI.
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: plexavo
|
|
3
|
+
Version: 0.2.6
|
|
4
|
+
Summary: Open-source AWS misconfiguration scanner — runs with your own local AWS credentials, nothing sent to anyone else.
|
|
5
|
+
Author: Kavee
|
|
6
|
+
License: AGPL-3.0-or-later
|
|
7
|
+
Project-URL: Homepage, https://github.com/plexavo/Plexavo
|
|
8
|
+
Project-URL: Issues, https://github.com/plexavo/Plexavo/issues
|
|
9
|
+
Project-URL: Security, https://github.com/plexavo/Plexavo/blob/main/SECURITY.md
|
|
10
|
+
Classifier: Programming Language :: Python :: 3
|
|
11
|
+
Classifier: License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)
|
|
12
|
+
Classifier: Topic :: Security
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Requires-Python: >=3.9
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
License-File: LICENSE
|
|
17
|
+
Requires-Dist: boto3>=1.34
|
|
18
|
+
Requires-Dist: python-dateutil>=2.9
|
|
19
|
+
Requires-Dist: rich>=13.7
|
|
20
|
+
Requires-Dist: jinja2>=3.1
|
|
21
|
+
Requires-Dist: markupsafe>=2.1
|
|
22
|
+
Requires-Dist: fpdf2>=2.8
|
|
23
|
+
Provides-Extra: ai
|
|
24
|
+
Requires-Dist: anthropic>=0.116; extra == "ai"
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest>=8.0; extra == "dev"
|
|
27
|
+
Requires-Dist: pypdf>=4.0; extra == "dev"
|
|
28
|
+
Dynamic: license-file
|
|
29
|
+
|
|
30
|
+
<div align="center">
|
|
31
|
+
<picture>
|
|
32
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/plexavo-logo-dark.png">
|
|
33
|
+
<img src="assets/plexavo-logo-light.png" alt="Plexavo" height="115">
|
|
34
|
+
</picture>
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
# Plexavo
|
|
38
|
+
|
|
39
|
+
<div align="center">
|
|
40
|
+
<img src="assets/demo.gif" alt="Plexavo interactive scan demo" width="800">
|
|
41
|
+
</div>
|
|
42
|
+
|
|
43
|
+
Plexavo is an open-source cloud security tool that audits AWS accounts
|
|
44
|
+
for real-world misconfigurations. It runs entirely with your own local
|
|
45
|
+
AWS credentials, the same way you'd run `aws s3 ls`, so nothing about
|
|
46
|
+
your account is ever handed to anyone else. Each scan produces a 0-100
|
|
47
|
+
security score and a plain-English report: what's wrong, what an
|
|
48
|
+
attacker would actually do with it, and the exact command to fix it.
|
|
49
|
+
|
|
50
|
+
Detection is pure Python/boto3, never AI. Claude only rewrites
|
|
51
|
+
already-found technical findings into something a non-security founder
|
|
52
|
+
can read, and it's entirely optional. See [Cost](#cost).
|
|
53
|
+
|
|
54
|
+
## What it checks
|
|
55
|
+
|
|
56
|
+
31 checks across 6 categories, run against real AWS accounts:
|
|
57
|
+
|
|
58
|
+
- **IAM**: privilege escalation paths, wildcard admin, cross-account
|
|
59
|
+
trust, root usage, dormant credentials
|
|
60
|
+
- **Network**: security groups and RDS instances exposed to the
|
|
61
|
+
internet
|
|
62
|
+
- **Storage**: public S3 buckets, via ACLs, bucket policies, or missing
|
|
63
|
+
Block Public Access
|
|
64
|
+
- **Encryption**: unencrypted EBS volumes, RDS instances, S3 buckets
|
|
65
|
+
- **Logging**: CloudTrail coverage and encryption, GuardDuty status
|
|
66
|
+
- **Usage**: permissions granted but never used, roles nobody has
|
|
67
|
+
assumed in 90+ days
|
|
68
|
+
|
|
69
|
+
See the `docs/*-TEST-MATRIX.md` files for exactly how each check was
|
|
70
|
+
verified.
|
|
71
|
+
|
|
72
|
+
## Installation
|
|
73
|
+
|
|
74
|
+
Every path below installs Plexavo into its own isolated environment.
|
|
75
|
+
|
|
76
|
+
### macOS & Linux
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
curl -LsSf https://astral.sh/uv/install.sh | sh # skip if you have uv
|
|
80
|
+
uv tool install plexavo
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Prefer [pipx](https://pipx.pypa.io/)? `pipx install plexavo` works the
|
|
84
|
+
same way.
|
|
85
|
+
|
|
86
|
+
### Windows
|
|
87
|
+
|
|
88
|
+
`uv`/`pipx` still work, but the launcher they put on your PATH is
|
|
89
|
+
unsigned, and Windows Smart App Control blocks it. Run Plexavo through
|
|
90
|
+
Python instead, two options:
|
|
91
|
+
|
|
92
|
+
**Option 1, uv (recommended)**
|
|
93
|
+
|
|
94
|
+
```powershell
|
|
95
|
+
uv tool install plexavo
|
|
96
|
+
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
|
|
97
|
+
if (!(Test-Path $PROFILE)) { New-Item -ItemType File -Path $PROFILE -Force }
|
|
98
|
+
Add-Content $PROFILE 'function plexavo { & "$env:APPDATA\uv\tools\plexavo\Scripts\python.exe" -m plexavo @args }'
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Open a new terminal. `plexavo` now works exactly like it does on
|
|
102
|
+
macOS/Linux, routed through uv's signed Python instead of the blocked
|
|
103
|
+
launcher.
|
|
104
|
+
|
|
105
|
+
**Option 2, plain venv**
|
|
106
|
+
|
|
107
|
+
```powershell
|
|
108
|
+
py -m venv plexavo-venv
|
|
109
|
+
.\plexavo-venv\Scripts\Activate.ps1
|
|
110
|
+
python -m pip install plexavo
|
|
111
|
+
python -m plexavo
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Use `python -m` for everything here too. The venv's own `pip.exe` and
|
|
115
|
+
`plexavo.exe` are unsigned as well, only `python.exe` is signed.
|
|
116
|
+
|
|
117
|
+
### AI narration (optional)
|
|
118
|
+
|
|
119
|
+
Want each finding rewritten as a full narrative? Install `"plexavo[ai]"`
|
|
120
|
+
instead of `plexavo`, and set `ANTHROPIC_API_KEY`. See [Cost](#cost).
|
|
121
|
+
|
|
122
|
+
## Using Plexavo
|
|
123
|
+
|
|
124
|
+
Run it with no arguments and it walks you through everything: picking an
|
|
125
|
+
AWS profile, choosing HTML or PDF, then scanning and showing your score
|
|
126
|
+
with every finding.
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
plexavo # macOS/Linux, and Windows Option 1
|
|
130
|
+
python -m plexavo # Windows Option 2
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
<div align="center">
|
|
134
|
+
<img src="assets/screenshot-cli.png" alt="Plexavo interactive CLI" width="700">
|
|
135
|
+
</div>
|
|
136
|
+
|
|
137
|
+
## The report
|
|
138
|
+
|
|
139
|
+
Reports are generated as HTML, PDF, or both. Every finding gets a free,
|
|
140
|
+
template-based fix by default, no key, no cost. Full AI-written
|
|
141
|
+
narration is offered automatically only when an `ANTHROPIC_API_KEY` is
|
|
142
|
+
detected, see [Cost](#cost).
|
|
143
|
+
|
|
144
|
+
<div align="center">
|
|
145
|
+
<img src="assets/screenshot-report.png" alt="Plexavo HTML report" width="700">
|
|
146
|
+
</div>
|
|
147
|
+
|
|
148
|
+
Severity, confidence, and evidence are always shown as separate signals.
|
|
149
|
+
A low-confidence Critical never reads the same as a high-confidence
|
|
150
|
+
Medium.
|
|
151
|
+
|
|
152
|
+
## Cost
|
|
153
|
+
|
|
154
|
+
Detection and the free templates always cost nothing. Live AI only runs
|
|
155
|
+
with `--explain`, using **your own** `ANTHROPIC_API_KEY` in **your own**
|
|
156
|
+
Anthropic account. Plexavo never sees your key and never calls the API
|
|
157
|
+
without it. A full scan with `--explain` typically costs a few cents.
|
|
158
|
+
|
|
159
|
+
## Contributing
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
git clone https://github.com/plexavo/plexavo.git
|
|
163
|
+
cd plexavo
|
|
164
|
+
uv pip install -e .
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
See [`CONTRIBUTING.md`](CONTRIBUTING.md) for the pattern used to add a
|
|
168
|
+
new check.
|
|
169
|
+
|
|
170
|
+
## Security
|
|
171
|
+
|
|
172
|
+
Found a vulnerability in the tool itself, not a misconfiguration in your
|
|
173
|
+
own AWS account (that's the tool working correctly)? See
|
|
174
|
+
[`SECURITY.md`](SECURITY.md) for a private reporting path.
|
|
175
|
+
|
|
176
|
+
## License
|
|
177
|
+
|
|
178
|
+
AGPL-3.0, see [`LICENSE`](LICENSE). Use, run, and modify it freely. If
|
|
179
|
+
you run a modified version as a hosted service, you're required to
|
|
180
|
+
publish those modifications too.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "plexavo"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.6"
|
|
8
8
|
description = "Open-source AWS misconfiguration scanner — runs with your own local AWS credentials, nothing sent to anyone else."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { text = "AGPL-3.0-or-later" }
|
|
@@ -73,7 +73,7 @@ assert_true(_short_name("arn:aws:iam::111111111111:role/my-role") == "my-role",
|
|
|
73
73
|
assert_true(_short_name("arn:aws:s3:::my-bucket") == "my-bucket", "Extracts name after last : when no /")
|
|
74
74
|
assert_true(_short_name("i-0abc123") == "i-0abc123", "Bare ID with no separators returned as-is")
|
|
75
75
|
|
|
76
|
-
print("\n=== All
|
|
76
|
+
print("\n=== All 11 templates produce non-empty impact/next_step, with ZERO API contact ===")
|
|
77
77
|
for check_id in COMMON_CHECK_TEMPLATES:
|
|
78
78
|
finding = f(check_id)
|
|
79
79
|
result = explain_finding(finding, client=ExplodingClient())
|
|
@@ -81,7 +81,19 @@ for check_id in COMMON_CHECK_TEMPLATES:
|
|
|
81
81
|
assert_true(bool(result.impact.strip()), f"{check_id} impact is non-empty")
|
|
82
82
|
assert_true(bool(result.how_to_fix.strip()), f"{check_id} how_to_fix is non-empty")
|
|
83
83
|
assert_true(bool(result.next_step.strip()), f"{check_id} next_step is non-empty — this is new, every template must set it")
|
|
84
|
-
assert_true(len(COMMON_CHECK_TEMPLATES) ==
|
|
84
|
+
assert_true(len(COMMON_CHECK_TEMPLATES) == 11, f"Exactly 11 templated checks exist (got {len(COMMON_CHECK_TEMPLATES)})")
|
|
85
|
+
|
|
86
|
+
print("\n=== LOG-25 (GuardDuty): account-level finding, template does not depend on a resource name ===")
|
|
87
|
+
# LOG-25's real finding has resource_arn="account" — no per-resource
|
|
88
|
+
# identifier to substitute, unlike bucket/volume/user templates. The
|
|
89
|
+
# template must still produce complete, correct guidance.
|
|
90
|
+
finding = f("LOG-25", resource_arn="account", raw_detail="GuardDuty is not enabled in this region.")
|
|
91
|
+
result = explain_finding(finding, client=ExplodingClient())
|
|
92
|
+
assert_true(result.source == "template", f"LOG-25 routes to template (got source={result.source})")
|
|
93
|
+
assert_true("guardduty create-detector" in result.how_to_fix, "LOG-25 fix names the actual enable command")
|
|
94
|
+
assert_true("guardduty create-detector" in result.next_step, "LOG-25 next_step names the actual enable command")
|
|
95
|
+
assert_true("<PLACEHOLDER" not in result.how_to_fix and "<PLACEHOLDER" not in result.next_step,
|
|
96
|
+
"LOG-25 has no per-resource value to fill, so no placeholder should appear")
|
|
85
97
|
|
|
86
98
|
print("\n=== Confidence/evidence are copied from the Finding, not decided by the template ===")
|
|
87
99
|
finding = f("IAM-01", confidence="Likely — see note", evidence="Grant is scoped by a Condition block (aws:SourceIp)")
|