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.
Files changed (53) hide show
  1. plexavo-0.2.6/PKG-INFO +180 -0
  2. plexavo-0.2.6/README.md +151 -0
  3. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/__init__.py +1 -1
  4. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/cli.py +1 -1
  5. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/report/ai_narration.py +29 -3
  6. plexavo-0.2.6/plexavo.egg-info/PKG-INFO +180 -0
  7. {plexavo-0.2.4 → plexavo-0.2.6}/pyproject.toml +1 -1
  8. {plexavo-0.2.4 → plexavo-0.2.6}/tests/test_ai_narration_offline.py +14 -2
  9. plexavo-0.2.4/PKG-INFO +0 -324
  10. plexavo-0.2.4/README.md +0 -295
  11. plexavo-0.2.4/plexavo.egg-info/PKG-INFO +0 -324
  12. {plexavo-0.2.4 → plexavo-0.2.6}/LICENSE +0 -0
  13. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/__main__.py +0 -0
  14. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/auth.py +0 -0
  15. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/aws_profile_setup.py +0 -0
  16. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/checks/__init__.py +0 -0
  17. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/checks/encryption.py +0 -0
  18. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/checks/iam.py +0 -0
  19. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/checks/iam_hygiene.py +0 -0
  20. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/checks/logging.py +0 -0
  21. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/checks/network.py +0 -0
  22. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/checks/storage.py +0 -0
  23. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/checks/usage.py +0 -0
  24. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/findings.py +0 -0
  25. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/interactive.py +0 -0
  26. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/principals.py +0 -0
  27. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/report/__init__.py +0 -0
  28. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/report/fonts/DejaVuSans-Bold.ttf +0 -0
  29. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/report/fonts/DejaVuSans-BoldOblique.ttf +0 -0
  30. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/report/fonts/DejaVuSans-Oblique.ttf +0 -0
  31. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/report/fonts/DejaVuSans.ttf +0 -0
  32. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/report/fonts/GEIST-FONT-LICENSE.txt +0 -0
  33. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/report/html_report.py +0 -0
  34. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/report/pdf.py +0 -0
  35. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/report/templates/report.html.j2 +0 -0
  36. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo/scoring.py +0 -0
  37. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo.egg-info/SOURCES.txt +0 -0
  38. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo.egg-info/dependency_links.txt +0 -0
  39. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo.egg-info/entry_points.txt +0 -0
  40. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo.egg-info/requires.txt +0 -0
  41. {plexavo-0.2.4 → plexavo-0.2.6}/plexavo.egg-info/top_level.txt +0 -0
  42. {plexavo-0.2.4 → plexavo-0.2.6}/setup.cfg +0 -0
  43. {plexavo-0.2.4 → plexavo-0.2.6}/tests/test_auth_offline.py +0 -0
  44. {plexavo-0.2.4 → plexavo-0.2.6}/tests/test_cli_entrypoint.py +0 -0
  45. {plexavo-0.2.4 → plexavo-0.2.6}/tests/test_encryption_offline.py +0 -0
  46. {plexavo-0.2.4 → plexavo-0.2.6}/tests/test_iam_hygiene_offline.py +0 -0
  47. {plexavo-0.2.4 → plexavo-0.2.6}/tests/test_iam_offline.py +0 -0
  48. {plexavo-0.2.4 → plexavo-0.2.6}/tests/test_logging_offline.py +0 -0
  49. {plexavo-0.2.4 → plexavo-0.2.6}/tests/test_network_offline.py +0 -0
  50. {plexavo-0.2.4 → plexavo-0.2.6}/tests/test_report_offline.py +0 -0
  51. {plexavo-0.2.4 → plexavo-0.2.6}/tests/test_scoring.py +0 -0
  52. {plexavo-0.2.4 → plexavo-0.2.6}/tests/test_storage_offline.py +0 -0
  53. {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.
@@ -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.
@@ -4,4 +4,4 @@ Runs entirely with your own local AWS credentials. Nothing is sent to
4
4
  anyone else. See README.md for usage, or `plexavo scan --help`.
5
5
  """
6
6
 
7
- __version__ = "0.2.4"
7
+ __version__ = "0.2.6"
@@ -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 (10 common check types); --explain always uses live AI instead, for every "
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 10 most common, narratively-generic check types.
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 10 most common, narratively-generic check
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 10 templated ones, is sent
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.4"
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 10 templates produce non-empty impact/next_step, with ZERO API contact ===")
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) == 10, f"Exactly 10 templated checks exist (got {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)")