Add optional local web UI: upload domains, download reports, diff runs (#23)#24
Merged
Merged
Conversation
Add a thin, optional Flask-based web layer over the existing analysis engine so domain lists can be analyzed from the browser without the command line. Web UI (domain_security_analyzer/web/, installed via the new [web] extra): - Upload domains by pasting (one per line, '#' comments ignored) or dropping a .txt file. - Analysis runs in a background thread with a live progress bar (polled via a JSON status endpoint); the page stays responsive. - Download the standard 29-column CSV for any run. - Changes view diffs the two most recent runs and classifies per-domain field deltas into security regressions (e.g. SPF/DMARC lost, SRI coverage dropped) vs. improvements, plus domains added/removed. - Launched with the new `domain-analyzer-web` console command (or `python -m domain_security_analyzer.web`); binds to 127.0.0.1 only and stores runs under ~/.domain-security-analyzer/runs/ (override via DSA_DATA_DIR). Engine refactor (backward compatible): - Extract the inline CSV writing in analyze_domains_from_file into a reusable write_results_csv() helper plus a shared CSV_COLUMNS constant. - Add an optional progress_callback(completed, total) parameter so the web UI can drive its progress bar without scraping stdout. Packaging / CI: - New optional dependency group [web] = flask>=3.0; flask also added to [dev]. - Register the domain-analyzer-web entry point and package the web templates and static assets in both wheel and sdist. - CI installs the [web] extra and smoke-tests the new entry point. Tests: add tests/test_web.py (network-free) covering domain parsing, the run-diff classification, and the full HTTP flow (run -> progress -> results -> download) with the engine monkeypatched, plus path-traversal rejection. Full suite: 45 passing. Implements the MVP scope of #23; cross-run history beyond the last two runs (SQLite) remains out of scope there. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XYvSCw1sjoG2AHbLPCsX7S
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Implements the MVP scope of #23 — a thin, optional Flask web layer over the existing analysis engine, so a list of domains can be analyzed from the browser without touching the command line. Core analysis logic is untouched; the package stays fully usable without the web extra.
What you get
Install the extra and launch:
The UI lets you:
#comments ignored) or dropping a.txtfile.Binds to
127.0.0.1only; runs are stored under~/.domain-security-analyzer/runs/(override viaDSA_DATA_DIR). Single-user local tool by design.Changes
New
domain_security_analyzer/web/subpackageapp.py— Flask app factory, in-memory job registry, routes (/,/run,/run/<id>,/run/<id>/status,/results/<run>,/download/<run>,/changes). Download path is validated against traversal.runs.py— timestamped-CSV storage + the run-diff classifier.cli.py/__main__.py— thedomain-analyzer-weblauncher (--host/--port/--open/--debug), with a clear message if thewebextra isn't installed.templates/+static/style.css— minimal dark UI.Engine refactor in
analyzer.py(backward compatible)write_results_csv()helper + a sharedCSV_COLUMNSconstant.progress_callback(completed, total)toanalyze_domains_from_fileso the UI gets real progress without scraping stdout. Existing callers/behavior unchanged.Packaging / CI
[web]extra (flask>=3.0; also added to[dev]);domain-analyzer-webentry point; web templates/static packaged in both wheel and sdist (verified)..[web]and smoke-testsdomain-analyzer-web --help.Verification
tests/test_web.py, all network-free — domain parsing, run-diff classification incl. timestamp-ignore, and the full run → progress → results → download flow with the engine monkeypatched, plus path-traversal rejection).python -m build+twine check→ PASSED on wheel and sdist./,/changes, and/static/style.cssall 200.domain-analyzer-webandpython -m domain_security_analyzer.weblaunch.Out of scope (stays on #23)
Full cross-run history / trend charts / SQLite — this MVP diffs the last two runs only, as agreed.
🤖 Generated with Claude Code
Generated by Claude Code