Skip to content

Interactive terminal UI + free-by-default remediation (v0.2.0) - #3

Merged
kavee-dev merged 8 commits into
mainfrom
dev
Aug 26, 2026
Merged

Interactive terminal UI + free-by-default remediation (v0.2.0)#3
kavee-dev merged 8 commits into
mainfrom
dev

Conversation

@kavee-dev

Copy link
Copy Markdown
Contributor

Summary

  • New interactive terminal mode (bare plexavo): splash screen, numbered profile picker with live sts status check, new-profile setup (writes to ~/.aws/credentials/config), report-format selection, AI-narration toggle, confirm-and-run summary, live scan spinner/stats all driving the same _run_scan code path plexavo scan --flags already used, no logic duplicated.
  • plexavo scan --flags (scripting/CI path) is fully unaffected verified byte-identical plain-text output when piped/non-terminal.
  • Free remediation guidance (Next Step/Full Fix Detail) now shows by default for the 10 templated check types, no --explain/API key needed. --explain now means "full AI for every finding," bypassing templates entirely rather than only filling gaps.
  • Report-path prompts and post-scan messages now always show the resolved absolute path, fixing a real bug where a bare name like "Desktop" silently saved in the wrong place.
  • Version bumped to 0.2.0.

Bare `plexavo` in a real terminal now shows a splash panel (name,
version, tagline, website, tips) via a new plexavo/interactive.py
module. `plexavo scan --flags...` is unchanged. Non-TTY invocations
(CI/piped) fall back to --help instead of launching interactively.

First slice of a multi-step upgrade replacing flag-only usage with a
menu-driven flow (profile picker, report options, live scan stats) in
later slices.
Numbered menu (rich.prompt.IntPrompt, plain line-buffered input) lists
configured AWS profiles plus a "+ Configure new profile" stub. Picking
a profile runs a live sts get_caller_identity check via the existing
auth.get_local_session, showing green/red status before the scan runs.

Started with a questionary/prompt_toolkit arrow-key menu, but that
class of widget desyncs unreliably across Windows terminal hosts
(confirmed live in Windows Terminal) -- replaced with a numbered
type-a-number-and-Enter list instead, which has no raw-keystroke
capture to desync. questionary dependency removed; rich.prompt covers
everything this feature still needs, including the masked secret-key
input the next slice (new-profile write flow) requires.
New plexavo/aws_profile_setup.py writes a named profile's Access Key
ID / Secret Access Key / region into ~/.aws/credentials and
~/.aws/config, same layout `aws configure --profile NAME` produces.
Read-modify-write via configparser so other profiles are untouched;
respects AWS_SHARED_CREDENTIALS_FILE/AWS_CONFIG_FILE overrides.

interactive.py's "+ Configure new profile" option now actually works:
prompts for name (with overwrite confirmation) / access key / masked
secret key (getpass) / region, writes it, then flows straight into
the existing live sts status check from slice 2.

User-tested end to end with real AWS credentials -- new profile
configured and validated correctly (green/Active, correct account ID).
Report-format menu (HTML/PDF/both/console-only), file-name prompts,
live ANTHROPIC_API_KEY status check feeding an AI-narration toggle,
and a confirm+run summary panel. run_interactive() now drives the
whole thing end to end by lazily calling the existing cli._run_scan
with the collected answers -- no scan/report logic duplicated.

Also fixes a real UX bug found by manual testing: the report-file
prompts said "path", which read as "give me a folder" -- entering
"Desktop" saved a literal file named Desktop (no extension) in the
cwd instead of the Desktop folder. Reworded to "Name the HTML/PDF
report file (add a folder in front for a specific location)".
explain_finding() gains use_ai (default False): with AI off, a finding
still gets its free template (10 check types) if one exists, else None
(raw-only) -- no network call is ever attempted regardless of key
presence. With use_ai=True, the template shortcut is skipped entirely
and every finding, including templated ones, goes to the live API --
"AI narration on" always means fully AI-written content, never a mix.

Previously explain_finding was only ever called at all when --explain
was passed, so the 10 free templates sat unused unless a user opted
into AI, despite needing no key and costing nothing.

Updated 6 existing test calls that relied on the old implicit
"no template -> API" fallthrough to pass use_ai=True explicitly. Added
two new tests proving the new contract directly: default never touches
the network for a non-templated check, and use_ai=True bypasses the
template for a templated check_id in favor of the live response.
…h UX

cli.py's _run_scan:
- Always generates explanations now (free templates when --explain is
  off, live AI for every finding when it's on), instead of only running
  explain at all when --explain was passed. Console panels print for
  any finding with an explanation, not just under --explain, so free
  template remediation is visible on the console too, not only in
  HTML/PDF reports. --explain-limit now only caps live API calls, never
  the free (instant, uncapped) template lookups.
- Replaces the flat "Running checks..." print lines with a live spinner
  cycling through cloud-security-themed flavor words plus running stats
  (stage N/8, principals, findings so far, elapsed time) -- real
  terminal only. console.status() produces zero output when
  console.is_terminal is False, so piped/CI output stays byte-identical
  to before -- verified, not assumed.
- Report-written messages now show the absolute resolved path, not the
  raw --report-html/--report-pdf value, so a bare filename never leaves
  you guessing where it landed.

interactive.py:
- Report-file prompts reworded ("Name the HTML/PDF file", not "path")
  plus a one-time note that files save to the launch directory unless a
  full path is given -- fixes a real bug where typing "Desktop" saved a
  file literally named Desktop instead of using that folder. The
  "Ready to scan" summary now shows resolved absolute paths too.
- AI-toggle wording updated: "off" no longer implies raw-only, it means
  free templates.
- Splash panel's "TIPS" section replaced with "FEATURES" (three short
  accurate bullets).

README.md: Quick start, Cost section, and the example-output caption
corrected -- they previously said dropping --explain means "raw
technical findings only," which is no longer true.
Minor release: interactive terminal UI (profile picker, new-profile
setup, report options, live scan spinner/stats) and free-by-default
template remediation, replacing the old flag-only-and-AI-only-explain
default behavior.
explain_finding()'s new `Explanation | None` return annotation (PEP
604) is evaluated eagerly at import time without `from __future__
import annotations`, and the `X | Y` operator on plain classes isn't
supported before Python 3.10 -- broke CI on the project's declared
3.9 minimum (requires-python = ">=3.9"). Adding the future import
defers all annotations in this module to strings, matching the
pattern already used in interactive.py and auth.py.

Audited every other file touched this session for the same issue --
none found; this was the only one.
@kavee-dev
kavee-dev merged commit 3c8dd74 into main Aug 26, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant