plexavo 0.3.0__tar.gz → 0.4.1__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 (58) hide show
  1. plexavo-0.4.1/PKG-INFO +264 -0
  2. plexavo-0.4.1/README.md +235 -0
  3. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/__init__.py +1 -1
  4. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/cli.py +37 -1
  5. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/interactive.py +1 -0
  6. plexavo-0.4.1/plexavo/report/json_report.py +104 -0
  7. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/report/templates/report.html.j2 +6 -3
  8. plexavo-0.4.1/plexavo.egg-info/PKG-INFO +264 -0
  9. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo.egg-info/SOURCES.txt +2 -0
  10. {plexavo-0.3.0 → plexavo-0.4.1}/pyproject.toml +1 -1
  11. plexavo-0.4.1/tests/test_json_report_offline.py +152 -0
  12. plexavo-0.3.0/PKG-INFO +0 -194
  13. plexavo-0.3.0/README.md +0 -165
  14. plexavo-0.3.0/plexavo.egg-info/PKG-INFO +0 -194
  15. {plexavo-0.3.0 → plexavo-0.4.1}/LICENSE +0 -0
  16. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/__main__.py +0 -0
  17. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/attack_paths.py +0 -0
  18. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/auth.py +0 -0
  19. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/aws_profile_setup.py +0 -0
  20. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/checks/__init__.py +0 -0
  21. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/checks/encryption.py +0 -0
  22. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/checks/iam.py +0 -0
  23. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/checks/iam_hygiene.py +0 -0
  24. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/checks/logging.py +0 -0
  25. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/checks/network.py +0 -0
  26. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/checks/storage.py +0 -0
  27. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/checks/usage.py +0 -0
  28. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/findings.py +0 -0
  29. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/principals.py +0 -0
  30. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/report/__init__.py +0 -0
  31. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/report/ai_narration.py +0 -0
  32. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/report/fonts/DejaVuSans-Bold.ttf +0 -0
  33. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/report/fonts/DejaVuSans-BoldOblique.ttf +0 -0
  34. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/report/fonts/DejaVuSans-Oblique.ttf +0 -0
  35. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/report/fonts/DejaVuSans.ttf +0 -0
  36. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/report/fonts/GEIST-FONT-LICENSE.txt +0 -0
  37. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/report/html_report.py +0 -0
  38. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/report/pdf.py +0 -0
  39. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo/scoring.py +0 -0
  40. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo.egg-info/dependency_links.txt +0 -0
  41. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo.egg-info/entry_points.txt +0 -0
  42. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo.egg-info/requires.txt +0 -0
  43. {plexavo-0.3.0 → plexavo-0.4.1}/plexavo.egg-info/top_level.txt +0 -0
  44. {plexavo-0.3.0 → plexavo-0.4.1}/setup.cfg +0 -0
  45. {plexavo-0.3.0 → plexavo-0.4.1}/tests/test_ai_narration_offline.py +0 -0
  46. {plexavo-0.3.0 → plexavo-0.4.1}/tests/test_attack_paths_offline.py +0 -0
  47. {plexavo-0.3.0 → plexavo-0.4.1}/tests/test_auth_offline.py +0 -0
  48. {plexavo-0.3.0 → plexavo-0.4.1}/tests/test_cli_entrypoint.py +0 -0
  49. {plexavo-0.3.0 → plexavo-0.4.1}/tests/test_encryption_offline.py +0 -0
  50. {plexavo-0.3.0 → plexavo-0.4.1}/tests/test_fail_on_offline.py +0 -0
  51. {plexavo-0.3.0 → plexavo-0.4.1}/tests/test_iam_hygiene_offline.py +0 -0
  52. {plexavo-0.3.0 → plexavo-0.4.1}/tests/test_iam_offline.py +0 -0
  53. {plexavo-0.3.0 → plexavo-0.4.1}/tests/test_logging_offline.py +0 -0
  54. {plexavo-0.3.0 → plexavo-0.4.1}/tests/test_network_offline.py +0 -0
  55. {plexavo-0.3.0 → plexavo-0.4.1}/tests/test_report_offline.py +0 -0
  56. {plexavo-0.3.0 → plexavo-0.4.1}/tests/test_scoring.py +0 -0
  57. {plexavo-0.3.0 → plexavo-0.4.1}/tests/test_storage_offline.py +0 -0
  58. {plexavo-0.3.0 → plexavo-0.4.1}/tests/test_usage_offline.py +0 -0
plexavo-0.4.1/PKG-INFO ADDED
@@ -0,0 +1,264 @@
1
+ Metadata-Version: 2.4
2
+ Name: plexavo
3
+ Version: 0.4.1
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
+
32
+ <picture>
33
+ <source media="(prefers-color-scheme: dark)" srcset="assets/plexavo-logo-dark.png">
34
+ <img src="assets/plexavo-logo-light.png" alt="Plexavo" height="105">
35
+ </picture>
36
+
37
+ <p>
38
+ <a href="https://github.com/plexavo/plexavo">
39
+ <img src="https://img.shields.io/github/stars/plexavo/plexavo?style=for-the-badge&logo=github&label=STARS" alt="GitHub stars">
40
+ </a>
41
+ <a href="https://github.com/plexavo/plexavo/blob/main/LICENSE">
42
+ <img src="https://img.shields.io/github/license/plexavo/plexavo?style=for-the-badge&label=LICENSE" alt="License">
43
+ </a>
44
+ <a href="https://pypi.org/project/plexavo/">
45
+ <img src="https://img.shields.io/pypi/v/plexavo?style=for-the-badge&logo=pypi&logoColor=white&label=PYPI" alt="PyPI version">
46
+ </a>
47
+ <a href="https://github.com/plexavo/plexavo/actions">
48
+ <img src="https://img.shields.io/github/actions/workflow/status/plexavo/plexavo/ci.yml?style=for-the-badge&label=BUILD" alt="Build status">
49
+ </a>
50
+ </p>
51
+
52
+ <p><strong>See your cloud. Secure what matters.</strong></p>
53
+ <p>Turn AWS configuration data into clear, actionable security intelligence.</p>
54
+
55
+ </div>
56
+
57
+ ---
58
+
59
+ <div align="center">
60
+ <img src="assets/demo.gif" alt="Plexavo interactive scan demo" width="800">
61
+ </div>
62
+
63
+ > [!NOTE]
64
+ > **Plexavo is built around a simple idea:** security tooling should tell you what is wrong, why it matters, and what to do next, without requiring a dedicated security team.
65
+
66
+ Plexavo is an open-source cloud security tool that audits AWS accounts
67
+ for real-world misconfigurations, using your own local AWS credentials
68
+ the same way `aws s3 ls` does, so nothing about your account ever
69
+ leaves your machine.
70
+
71
+ Each scan produces a **0–100 security score** and a plain-English report:
72
+ what's wrong, what an attacker would actually do with it, and the exact
73
+ command to fix it.
74
+
75
+ > [!IMPORTANT]
76
+ > **Detection is not AI.** Plexavo's detections are pure Python/boto3;
77
+ > Claude only rewrites already-found findings for readability, and
78
+ > narration is fully optional. See [Cost](#cost).
79
+
80
+ > [!TIP]
81
+ > 🤖 **New: talk to Plexavo through Claude Code.** No CLI flags, just ask
82
+ > "scan my AWS account with Plexavo" in a Claude Code session and get a
83
+ > conversational security briefing. See
84
+ > [Using it from Claude Code](#using-it-from-claude-code).
85
+
86
+ ## ✦ What it checks
87
+
88
+ **32 checks across 6 categories**, run against real AWS accounts:
89
+
90
+ | Category | What Plexavo looks for |
91
+ |---|---|
92
+ | **IAM** | Privilege escalation paths, wildcard admin, cross-account trust, root usage, dormant credentials |
93
+ | **Network** | Security groups and RDS instances exposed to the internet |
94
+ | **Storage** | Public S3 buckets via ACLs, bucket policies, or missing Block Public Access; buckets with no access logging |
95
+ | **Encryption** | Unencrypted EBS volumes, RDS instances, S3 buckets |
96
+ | **Logging** | CloudTrail coverage and encryption, GuardDuty status |
97
+ | **Usage** | Permissions granted but never used, roles nobody has assumed in 90+ days |
98
+
99
+ See `docs/*-TEST-MATRIX.md` for how each check was verified.
100
+
101
+ > [!TIP]
102
+ > **Don't just trust the number.** Plexavo keeps severity, confidence, and evidence as separate signals, so a low-confidence Critical does not read the same as a high-confidence Medium.
103
+
104
+ ## ⚡ Installation
105
+
106
+ Every path below installs Plexavo into its own isolated environment.
107
+
108
+ ### macOS & Linux
109
+
110
+ ```bash
111
+ curl -LsSf https://astral.sh/uv/install.sh | sh # skip if you have uv
112
+ uv tool install plexavo
113
+ ```
114
+
115
+ Prefer [pipx](https://pipx.pypa.io/)? `pipx install plexavo` works the
116
+ same way.
117
+
118
+ ### Windows
119
+
120
+ `uv`/`pipx` still work, but the PATH launcher is unsigned and Windows
121
+ Smart App Control blocks it. Run Plexavo through Python instead:
122
+
123
+ **Option 1, uv (recommended)**
124
+
125
+ ```powershell
126
+ uv tool install plexavo
127
+ Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
128
+ if (!(Test-Path $PROFILE)) { New-Item -ItemType File -Path $PROFILE -Force }
129
+ Add-Content $PROFILE 'function plexavo { & "$env:APPDATA\uv\tools\plexavo\Scripts\python.exe" -m plexavo @args }'
130
+ ```
131
+
132
+ Open a new terminal. `plexavo` now works like it does on macOS/Linux,
133
+ routed through uv's signed Python instead of the blocked launcher.
134
+
135
+ **Option 2, plain venv**
136
+
137
+ ```powershell
138
+ py -m venv plexavo-venv
139
+ .\plexavo-venv\Scripts\Activate.ps1
140
+ python -m pip install plexavo
141
+ python -m plexavo
142
+ ```
143
+
144
+ Use `python -m` for everything here too. The venv's own `pip.exe` and
145
+ `plexavo.exe` are unsigned as well, only `python.exe` is signed.
146
+
147
+ ### AI narration (optional)
148
+
149
+ Want each finding rewritten as a full narrative? Install `"plexavo[ai]"`
150
+ instead of `plexavo`, and set `ANTHROPIC_API_KEY`. See [Cost](#cost).
151
+
152
+ ## 🚀 Using Plexavo
153
+
154
+ Run it with no arguments and it walks you through everything: picking an
155
+ AWS profile, choosing HTML or PDF, then scanning and showing your score
156
+ with every finding.
157
+
158
+ ```bash
159
+ plexavo # macOS/Linux, and Windows Option 1
160
+ python -m plexavo # Windows Option 2
161
+ ```
162
+
163
+ <div align="center">
164
+ <img src="assets/screenshot-cli.png" alt="Plexavo interactive CLI" width="700">
165
+ </div>
166
+
167
+ ### Running it on a schedule
168
+
169
+ Plexavo can also run unattended from cron or a GitHub Actions workflow,
170
+ and flag a run when something regresses so you get notified without
171
+ opening a report. See [`docs/automation.md`](docs/automation.md).
172
+
173
+ > [!NOTE]
174
+ > **Think of a scan as a snapshot, not a finish line.** Run it repeatedly to catch regressions as your infrastructure changes.
175
+
176
+ ### 🤖 Using it from Claude Code
177
+
178
+ Using [Claude Code](https://claude.com/claude-code)? Install the
179
+ `plexavo-scan` plugin, then just ask: "scan my AWS account for security
180
+ issues using Plexavo." It relays exactly what Plexavo found, and never
181
+ runs a state-changing AWS command without asking first.
182
+
183
+ ```
184
+ /plugin marketplace add plexavo/Plexavo
185
+ /plugin install plexavo-scan@plexavo
186
+ ```
187
+
188
+ Prefer not to add a marketplace? Save
189
+ [`plexavo-scan/SKILL.md`](https://raw.githubusercontent.com/plexavo/Plexavo/main/.claude/skills/plexavo-scan/SKILL.md)
190
+ to `~/.claude/skills/plexavo-scan/SKILL.md`
191
+ (`%USERPROFILE%\.claude\skills\plexavo-scan\SKILL.md` on Windows) instead,
192
+ same skill, just without automatic updates.
193
+
194
+ ## 📊 The report
195
+
196
+ Reports are generated as HTML, PDF, or both. Every finding gets a free,
197
+ template-based fix by default, no key, no cost. Full AI-written
198
+ narration kicks in automatically once an `ANTHROPIC_API_KEY` is
199
+ detected, see [Cost](#cost).
200
+
201
+ <div align="center">
202
+ <img src="assets/screenshot-report.png" alt="Plexavo HTML report" width="700">
203
+ </div>
204
+
205
+ ## 💰 Cost
206
+
207
+ Detection and the free templates always cost nothing. Live AI only runs
208
+ with `--explain`, using **your own** `ANTHROPIC_API_KEY` in **your own**
209
+ Anthropic account.
210
+
211
+ Plexavo never sees your key and never calls the API without it. A full
212
+ scan with `--explain` typically costs a few cents.
213
+
214
+ > [!IMPORTANT]
215
+ > **No hidden AI bill.** If you don't provide an Anthropic API key, Plexavo does not make an AI API call.
216
+
217
+ ## 🤝 Contributing
218
+
219
+ ```bash
220
+ git clone https://github.com/plexavo/plexavo.git
221
+ cd plexavo
222
+ uv pip install -e .
223
+ ```
224
+
225
+ See [`CONTRIBUTING.md`](CONTRIBUTING.md) for the pattern used to add a
226
+ new check.
227
+
228
+ ### 🧨 Break Plexavo
229
+
230
+ Think you can make Plexavo miss something, or give confusing guidance?
231
+
232
+ [**Report it →**](../../issues/new?template=break-plexavo.yml)
233
+
234
+ Every confirmed, genuinely new finding gets fixed and shipped, and you
235
+ get a permanent credit in the [Hall of Bugs](HALL_OF_BUGS.md).
236
+
237
+ **No bounty. Public credit only.**
238
+
239
+ > [!TIP]
240
+ > **The best security tool is one that gets challenged.** If you find a blind spot, break it, report it, and help make the next scan better.
241
+
242
+ ## 🔐 Security
243
+
244
+ Found a vulnerability in the tool itself, not a misconfiguration in your
245
+ own AWS account (that's the tool working correctly)?
246
+
247
+ See [`SECURITY.md`](SECURITY.md) for a private reporting path.
248
+
249
+ ## 📄 License
250
+
251
+ AGPL-3.0, see [`LICENSE`](LICENSE).
252
+
253
+ Use, run, and modify it freely. If you run a modified version as a hosted
254
+ service, you're required to publish those modifications too.
255
+
256
+ ---
257
+
258
+ <div align="center">
259
+
260
+ **Plexavo · Open-source cloud security, built to be understood.**
261
+
262
+ <sub>Scan. Understand. Fix. Repeat.</sub>
263
+
264
+ </div>
@@ -0,0 +1,235 @@
1
+ <div align="center">
2
+
3
+ <picture>
4
+ <source media="(prefers-color-scheme: dark)" srcset="assets/plexavo-logo-dark.png">
5
+ <img src="assets/plexavo-logo-light.png" alt="Plexavo" height="105">
6
+ </picture>
7
+
8
+ <p>
9
+ <a href="https://github.com/plexavo/plexavo">
10
+ <img src="https://img.shields.io/github/stars/plexavo/plexavo?style=for-the-badge&logo=github&label=STARS" alt="GitHub stars">
11
+ </a>
12
+ <a href="https://github.com/plexavo/plexavo/blob/main/LICENSE">
13
+ <img src="https://img.shields.io/github/license/plexavo/plexavo?style=for-the-badge&label=LICENSE" alt="License">
14
+ </a>
15
+ <a href="https://pypi.org/project/plexavo/">
16
+ <img src="https://img.shields.io/pypi/v/plexavo?style=for-the-badge&logo=pypi&logoColor=white&label=PYPI" alt="PyPI version">
17
+ </a>
18
+ <a href="https://github.com/plexavo/plexavo/actions">
19
+ <img src="https://img.shields.io/github/actions/workflow/status/plexavo/plexavo/ci.yml?style=for-the-badge&label=BUILD" alt="Build status">
20
+ </a>
21
+ </p>
22
+
23
+ <p><strong>See your cloud. Secure what matters.</strong></p>
24
+ <p>Turn AWS configuration data into clear, actionable security intelligence.</p>
25
+
26
+ </div>
27
+
28
+ ---
29
+
30
+ <div align="center">
31
+ <img src="assets/demo.gif" alt="Plexavo interactive scan demo" width="800">
32
+ </div>
33
+
34
+ > [!NOTE]
35
+ > **Plexavo is built around a simple idea:** security tooling should tell you what is wrong, why it matters, and what to do next, without requiring a dedicated security team.
36
+
37
+ Plexavo is an open-source cloud security tool that audits AWS accounts
38
+ for real-world misconfigurations, using your own local AWS credentials
39
+ the same way `aws s3 ls` does, so nothing about your account ever
40
+ leaves your machine.
41
+
42
+ Each scan produces a **0–100 security score** and a plain-English report:
43
+ what's wrong, what an attacker would actually do with it, and the exact
44
+ command to fix it.
45
+
46
+ > [!IMPORTANT]
47
+ > **Detection is not AI.** Plexavo's detections are pure Python/boto3;
48
+ > Claude only rewrites already-found findings for readability, and
49
+ > narration is fully optional. See [Cost](#cost).
50
+
51
+ > [!TIP]
52
+ > 🤖 **New: talk to Plexavo through Claude Code.** No CLI flags, just ask
53
+ > "scan my AWS account with Plexavo" in a Claude Code session and get a
54
+ > conversational security briefing. See
55
+ > [Using it from Claude Code](#using-it-from-claude-code).
56
+
57
+ ## ✦ What it checks
58
+
59
+ **32 checks across 6 categories**, run against real AWS accounts:
60
+
61
+ | Category | What Plexavo looks for |
62
+ |---|---|
63
+ | **IAM** | Privilege escalation paths, wildcard admin, cross-account trust, root usage, dormant credentials |
64
+ | **Network** | Security groups and RDS instances exposed to the internet |
65
+ | **Storage** | Public S3 buckets via ACLs, bucket policies, or missing Block Public Access; buckets with no access logging |
66
+ | **Encryption** | Unencrypted EBS volumes, RDS instances, S3 buckets |
67
+ | **Logging** | CloudTrail coverage and encryption, GuardDuty status |
68
+ | **Usage** | Permissions granted but never used, roles nobody has assumed in 90+ days |
69
+
70
+ See `docs/*-TEST-MATRIX.md` for how each check was verified.
71
+
72
+ > [!TIP]
73
+ > **Don't just trust the number.** Plexavo keeps severity, confidence, and evidence as separate signals, so a low-confidence Critical does not read the same as a high-confidence Medium.
74
+
75
+ ## ⚡ Installation
76
+
77
+ Every path below installs Plexavo into its own isolated environment.
78
+
79
+ ### macOS & Linux
80
+
81
+ ```bash
82
+ curl -LsSf https://astral.sh/uv/install.sh | sh # skip if you have uv
83
+ uv tool install plexavo
84
+ ```
85
+
86
+ Prefer [pipx](https://pipx.pypa.io/)? `pipx install plexavo` works the
87
+ same way.
88
+
89
+ ### Windows
90
+
91
+ `uv`/`pipx` still work, but the PATH launcher is unsigned and Windows
92
+ Smart App Control blocks it. Run Plexavo through Python instead:
93
+
94
+ **Option 1, uv (recommended)**
95
+
96
+ ```powershell
97
+ uv tool install plexavo
98
+ Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
99
+ if (!(Test-Path $PROFILE)) { New-Item -ItemType File -Path $PROFILE -Force }
100
+ Add-Content $PROFILE 'function plexavo { & "$env:APPDATA\uv\tools\plexavo\Scripts\python.exe" -m plexavo @args }'
101
+ ```
102
+
103
+ Open a new terminal. `plexavo` now works like it does on macOS/Linux,
104
+ routed through uv's signed Python instead of the blocked launcher.
105
+
106
+ **Option 2, plain venv**
107
+
108
+ ```powershell
109
+ py -m venv plexavo-venv
110
+ .\plexavo-venv\Scripts\Activate.ps1
111
+ python -m pip install plexavo
112
+ python -m plexavo
113
+ ```
114
+
115
+ Use `python -m` for everything here too. The venv's own `pip.exe` and
116
+ `plexavo.exe` are unsigned as well, only `python.exe` is signed.
117
+
118
+ ### AI narration (optional)
119
+
120
+ Want each finding rewritten as a full narrative? Install `"plexavo[ai]"`
121
+ instead of `plexavo`, and set `ANTHROPIC_API_KEY`. See [Cost](#cost).
122
+
123
+ ## 🚀 Using Plexavo
124
+
125
+ Run it with no arguments and it walks you through everything: picking an
126
+ AWS profile, choosing HTML or PDF, then scanning and showing your score
127
+ with every finding.
128
+
129
+ ```bash
130
+ plexavo # macOS/Linux, and Windows Option 1
131
+ python -m plexavo # Windows Option 2
132
+ ```
133
+
134
+ <div align="center">
135
+ <img src="assets/screenshot-cli.png" alt="Plexavo interactive CLI" width="700">
136
+ </div>
137
+
138
+ ### Running it on a schedule
139
+
140
+ Plexavo can also run unattended from cron or a GitHub Actions workflow,
141
+ and flag a run when something regresses so you get notified without
142
+ opening a report. See [`docs/automation.md`](docs/automation.md).
143
+
144
+ > [!NOTE]
145
+ > **Think of a scan as a snapshot, not a finish line.** Run it repeatedly to catch regressions as your infrastructure changes.
146
+
147
+ ### 🤖 Using it from Claude Code
148
+
149
+ Using [Claude Code](https://claude.com/claude-code)? Install the
150
+ `plexavo-scan` plugin, then just ask: "scan my AWS account for security
151
+ issues using Plexavo." It relays exactly what Plexavo found, and never
152
+ runs a state-changing AWS command without asking first.
153
+
154
+ ```
155
+ /plugin marketplace add plexavo/Plexavo
156
+ /plugin install plexavo-scan@plexavo
157
+ ```
158
+
159
+ Prefer not to add a marketplace? Save
160
+ [`plexavo-scan/SKILL.md`](https://raw.githubusercontent.com/plexavo/Plexavo/main/.claude/skills/plexavo-scan/SKILL.md)
161
+ to `~/.claude/skills/plexavo-scan/SKILL.md`
162
+ (`%USERPROFILE%\.claude\skills\plexavo-scan\SKILL.md` on Windows) instead,
163
+ same skill, just without automatic updates.
164
+
165
+ ## 📊 The report
166
+
167
+ Reports are generated as HTML, PDF, or both. Every finding gets a free,
168
+ template-based fix by default, no key, no cost. Full AI-written
169
+ narration kicks in automatically once an `ANTHROPIC_API_KEY` is
170
+ detected, see [Cost](#cost).
171
+
172
+ <div align="center">
173
+ <img src="assets/screenshot-report.png" alt="Plexavo HTML report" width="700">
174
+ </div>
175
+
176
+ ## 💰 Cost
177
+
178
+ Detection and the free templates always cost nothing. Live AI only runs
179
+ with `--explain`, using **your own** `ANTHROPIC_API_KEY` in **your own**
180
+ Anthropic account.
181
+
182
+ Plexavo never sees your key and never calls the API without it. A full
183
+ scan with `--explain` typically costs a few cents.
184
+
185
+ > [!IMPORTANT]
186
+ > **No hidden AI bill.** If you don't provide an Anthropic API key, Plexavo does not make an AI API call.
187
+
188
+ ## 🤝 Contributing
189
+
190
+ ```bash
191
+ git clone https://github.com/plexavo/plexavo.git
192
+ cd plexavo
193
+ uv pip install -e .
194
+ ```
195
+
196
+ See [`CONTRIBUTING.md`](CONTRIBUTING.md) for the pattern used to add a
197
+ new check.
198
+
199
+ ### 🧨 Break Plexavo
200
+
201
+ Think you can make Plexavo miss something, or give confusing guidance?
202
+
203
+ [**Report it →**](../../issues/new?template=break-plexavo.yml)
204
+
205
+ Every confirmed, genuinely new finding gets fixed and shipped, and you
206
+ get a permanent credit in the [Hall of Bugs](HALL_OF_BUGS.md).
207
+
208
+ **No bounty. Public credit only.**
209
+
210
+ > [!TIP]
211
+ > **The best security tool is one that gets challenged.** If you find a blind spot, break it, report it, and help make the next scan better.
212
+
213
+ ## 🔐 Security
214
+
215
+ Found a vulnerability in the tool itself, not a misconfiguration in your
216
+ own AWS account (that's the tool working correctly)?
217
+
218
+ See [`SECURITY.md`](SECURITY.md) for a private reporting path.
219
+
220
+ ## 📄 License
221
+
222
+ AGPL-3.0, see [`LICENSE`](LICENSE).
223
+
224
+ Use, run, and modify it freely. If you run a modified version as a hosted
225
+ service, you're required to publish those modifications too.
226
+
227
+ ---
228
+
229
+ <div align="center">
230
+
231
+ **Plexavo · Open-source cloud security, built to be understood.**
232
+
233
+ <sub>Scan. Understand. Fix. Repeat.</sub>
234
+
235
+ </div>
@@ -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.3.0"
7
+ __version__ = "0.4.1"
@@ -12,6 +12,7 @@ credentials, the same way `aws s3 ls` does.
12
12
  """
13
13
 
14
14
  import argparse
15
+ import json
15
16
  import os
16
17
  import random
17
18
  import sys
@@ -38,6 +39,7 @@ from plexavo.findings import Severity
38
39
  from plexavo.scoring import calculate_score
39
40
  from plexavo.report.ai_narration import explain_finding, COMMON_CHECK_TEMPLATES
40
41
  from plexavo.report.html_report import build_report_data, generate_html
42
+ from plexavo.report.json_report import build_json_report
41
43
  from plexavo.report.pdf import generate_pdf
42
44
 
43
45
  console = Console()
@@ -147,10 +149,34 @@ def _build_parser() -> argparse.ArgumentParser:
147
149
  "non-zero exit makes GitHub Actions or cron flag the run, so a regression "
148
150
  "reaches you without opening a report by hand. Exit 1 still means the scan "
149
151
  "itself could not run. Off by default. See docs/automation.md.")
152
+ scan.add_argument("--format", choices=["json"], default=None,
153
+ help="Print one machine-readable JSON object to stdout instead of the normal "
154
+ "console output (findings table, panels, progress) — that output still "
155
+ "happens, it just goes to stderr, so stdout is always exactly one valid "
156
+ "JSON object. Meant for a calling agent/script, not a person at a terminal. "
157
+ "--report-html/--report-pdf still write their files as normal alongside it.")
150
158
  return parser
151
159
 
152
160
 
153
161
  def _run_scan(args) -> None:
162
+ """Thin wrapper around _run_scan_impl: when --format json is set,
163
+ every existing console.print call in the impl still runs unchanged,
164
+ it's just redirected to stderr for the duration, so stdout stays
165
+ exactly one JSON object printed via plain print() at the end. Always
166
+ restored afterward (try/finally), including on sys.exit paths, so a
167
+ later in-process call (tests, or a future caller) never inherits a
168
+ silently-redirected console."""
169
+ json_mode = args.format == "json"
170
+ original_file = console.file
171
+ if json_mode:
172
+ console.file = sys.stderr
173
+ try:
174
+ _run_scan_impl(args, json_mode)
175
+ finally:
176
+ console.file = original_file
177
+
178
+
179
+ def _run_scan_impl(args, json_mode: bool) -> None:
154
180
  console.print(f"[bold]Using AWS profile:[/bold] {args.profile or '(default)'}")
155
181
  try:
156
182
  session = get_local_session(profile_name=args.profile, region=args.region)
@@ -168,7 +194,11 @@ def _run_scan(args) -> None:
168
194
  # False (confirmed — Rich only renders it in real terminals), so
169
195
  # scripting users get the exact same plain progress lines as before,
170
196
  # not silence. This is a deliberate branch, not an oversight.
171
- is_tty = console.is_terminal
197
+ # Forced off in json_mode regardless of the actual terminal, so
198
+ # progress always uses plain print-per-stage lines (to stderr), never
199
+ # a Rich Live/Status spinner — deterministic output for a calling
200
+ # agent/script, not a cosmetic call.
201
+ is_tty = console.is_terminal and not json_mode
172
202
  findings = []
173
203
  principals = []
174
204
  chains = []
@@ -244,6 +274,8 @@ def _run_scan(args) -> None:
244
274
  # never make it into a report.
245
275
  if not findings and not chains:
246
276
  console.print("[green]No findings.[/green]")
277
+ if json_mode:
278
+ print(json.dumps(build_json_report(findings, result, account_id, [], chains=chains), indent=2))
247
279
  _apply_fail_on(args.fail_on, findings)
248
280
  return
249
281
 
@@ -352,6 +384,10 @@ def _run_scan(args) -> None:
352
384
  generate_pdf(report_data, args.report_pdf)
353
385
  console.print(f"[green]PDF report written to {os.path.abspath(args.report_pdf)}[/green]")
354
386
 
387
+ if json_mode:
388
+ json_payload = build_json_report(findings, result, account_id, explanations, chains=chains)
389
+ print(json.dumps(json_payload, indent=2))
390
+
355
391
  # Last thing in the scan: any report is on disk by now, so a non-zero
356
392
  # exit here never costs you the report.
357
393
  _apply_fail_on(args.fail_on, findings)
@@ -328,4 +328,5 @@ def run_interactive() -> None:
328
328
  report_html=options["report_html"],
329
329
  report_pdf=options["report_pdf"],
330
330
  fail_on=None, # scheduled-run flag only; a person watching the score doesn't need it
331
+ format=None, # agent/script output mode only; interactive mode always shows the normal console UI
331
332
  ))