From d1e8225d5f9653595442179924aa91de3c2ba6bb Mon Sep 17 00:00:00 2001 From: Ahmed Allam Date: Sun, 26 Jul 2026 20:00:51 +0000 Subject: [PATCH] refactor: move strix/viewer under strix/interface --- .gitignore | 6 +- CONTRIBUTING.md | 10 +-- Makefile | 4 +- pyproject.toml | 12 ++-- strix.spec | 14 ++-- strix/interface/main.py | 2 +- strix/interface/tui/app.py | 2 +- strix/{ => interface}/viewer/__init__.py | 2 +- strix/{ => interface}/viewer/auth.py | 4 +- strix/{ => interface}/viewer/cli.py | 6 +- .../viewer/frontend/index.html | 0 .../viewer/frontend/package-lock.json | 0 .../viewer/frontend/package.json | 0 .../viewer/frontend/public/logo.png | Bin .../viewer/frontend/src/App.tsx | 0 .../src/components/AddRepositoryDialog.tsx | 0 .../src/components/EmailReportView.tsx | 0 .../src/components/EmailVerifyInline.tsx | 0 .../frontend/src/components/FeedbackView.tsx | 0 .../src/components/IssueSeveritySummary.tsx | 0 .../frontend/src/components/PastRunsView.tsx | 0 .../viewer/frontend/src/components/ProCta.tsx | 0 .../frontend/src/components/RunDetails.tsx | 0 .../frontend/src/components/Sidebar.tsx | 0 .../frontend/src/components/TrustToast.tsx | 0 .../frontend/src/components/UpgradeModal.tsx | 0 .../src/components/live/AgentDetailModal.tsx | 0 .../src/components/live/AgentGraph.tsx | 0 .../src/components/live/AgentNode.tsx | 0 .../src/components/live/AgentTranscript.tsx | 0 .../src/components/live/GraphSkeleton.tsx | 0 .../components/live/ScanPromptComposer.tsx | 0 .../tool-renderers/AgentCommsRenderer.tsx | 0 .../tool-renderers/ApplyPatchRenderer.tsx | 0 .../live/tool-renderers/BrowserRenderer.tsx | 0 .../live/tool-renderers/ChatBubble.tsx | 0 .../live/tool-renderers/FallbackRenderer.tsx | 0 .../live/tool-renderers/FileEditRenderer.tsx | 0 .../live/tool-renderers/FinishRenderer.tsx | 0 .../live/tool-renderers/LoadSkillRenderer.tsx | 0 .../live/tool-renderers/Markdown.tsx | 0 .../live/tool-renderers/NotesRenderer.tsx | 0 .../live/tool-renderers/ProxyRenderer.tsx | 0 .../live/tool-renderers/PythonRenderer.tsx | 0 .../live/tool-renderers/ScanInfoRenderer.tsx | 0 .../live/tool-renderers/TerminalRenderer.tsx | 0 .../live/tool-renderers/ThinkRenderer.tsx | 0 .../live/tool-renderers/TodoRenderer.tsx | 0 .../live/tool-renderers/ToolCard.tsx | 0 .../live/tool-renderers/ViewImageRenderer.tsx | 0 .../tool-renderers/VulnReportRenderer.tsx | 0 .../live/tool-renderers/WebSearchRenderer.tsx | 0 .../components/live/tool-renderers/index.ts | 0 .../components/live/tool-renderers/utils.ts | 0 .../vulnerability/CodeDiffBlock.tsx | 0 .../vulnerability/ContentSection.tsx | 0 .../components/vulnerability/IssueSidebar.tsx | 0 .../components/vulnerability/MdCodeBlock.tsx | 0 .../src/components/vulnerability/PocBlock.tsx | 0 .../vulnerability/VulnerabilityDetail.tsx | 0 .../viewer/frontend/src/data/serverSource.ts | 0 .../viewer/frontend/src/index.css | 0 .../viewer/frontend/src/lib/cta.ts | 0 .../viewer/frontend/src/lib/display-number.ts | 0 .../viewer/frontend/src/lib/fenced-code.ts | 0 .../viewer/frontend/src/lib/hljs.ts | 0 .../frontend/src/lib/local-run-parser.ts | 0 .../viewer/frontend/src/lib/target-utils.ts | 0 .../viewer/frontend/src/lib/utils.ts | 0 .../frontend/src/lib/vulnerability-utils.ts | 0 .../viewer/frontend/src/main.tsx | 0 .../viewer/frontend/src/stores/auth.ts | 0 .../viewer/frontend/src/types/events.ts | 0 .../viewer/frontend/src/types/issues.ts | 0 .../viewer/frontend/tsconfig.json | 0 .../viewer/frontend/vite.config.ts | 2 +- strix/{ => interface}/viewer/report_pdf.py | 2 +- strix/{ => interface}/viewer/server.py | 6 +- .../viewer/static/assets/index-Dd1cyttN.js | 0 .../viewer/static/assets/index-vV8wxCG6.css | 0 .../{ => interface}/viewer/static/index.html | 0 strix/{ => interface}/viewer/static/logo.png | Bin strix/{ => interface}/viewer/transcript.py | 4 +- tests/test_fenced_code.py | 2 +- tests/test_report_pdf.py | 4 +- tests/test_viewer.py | 66 ++++++++++-------- tests/test_viewer_auth.py | 18 ++--- tests/test_viewer_runs_gating.py | 2 +- 88 files changed, 87 insertions(+), 81 deletions(-) rename strix/{ => interface}/viewer/__init__.py (84%) rename strix/{ => interface}/viewer/auth.py (98%) rename strix/{ => interface}/viewer/cli.py (94%) rename strix/{ => interface}/viewer/frontend/index.html (100%) rename strix/{ => interface}/viewer/frontend/package-lock.json (100%) rename strix/{ => interface}/viewer/frontend/package.json (100%) rename strix/{ => interface}/viewer/frontend/public/logo.png (100%) rename strix/{ => interface}/viewer/frontend/src/App.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/AddRepositoryDialog.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/EmailReportView.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/EmailVerifyInline.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/FeedbackView.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/IssueSeveritySummary.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/PastRunsView.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/ProCta.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/RunDetails.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/Sidebar.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/TrustToast.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/UpgradeModal.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/AgentDetailModal.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/AgentGraph.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/AgentNode.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/AgentTranscript.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/GraphSkeleton.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/ScanPromptComposer.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/tool-renderers/AgentCommsRenderer.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/tool-renderers/ApplyPatchRenderer.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/tool-renderers/BrowserRenderer.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/tool-renderers/ChatBubble.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/tool-renderers/FallbackRenderer.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/tool-renderers/FileEditRenderer.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/tool-renderers/FinishRenderer.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/tool-renderers/LoadSkillRenderer.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/tool-renderers/Markdown.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/tool-renderers/NotesRenderer.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/tool-renderers/ProxyRenderer.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/tool-renderers/PythonRenderer.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/tool-renderers/ScanInfoRenderer.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/tool-renderers/TerminalRenderer.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/tool-renderers/ThinkRenderer.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/tool-renderers/TodoRenderer.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/tool-renderers/ToolCard.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/tool-renderers/ViewImageRenderer.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/tool-renderers/VulnReportRenderer.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/tool-renderers/WebSearchRenderer.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/tool-renderers/index.ts (100%) rename strix/{ => interface}/viewer/frontend/src/components/live/tool-renderers/utils.ts (100%) rename strix/{ => interface}/viewer/frontend/src/components/vulnerability/CodeDiffBlock.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/vulnerability/ContentSection.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/vulnerability/IssueSidebar.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/vulnerability/MdCodeBlock.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/vulnerability/PocBlock.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/components/vulnerability/VulnerabilityDetail.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/data/serverSource.ts (100%) rename strix/{ => interface}/viewer/frontend/src/index.css (100%) rename strix/{ => interface}/viewer/frontend/src/lib/cta.ts (100%) rename strix/{ => interface}/viewer/frontend/src/lib/display-number.ts (100%) rename strix/{ => interface}/viewer/frontend/src/lib/fenced-code.ts (100%) rename strix/{ => interface}/viewer/frontend/src/lib/hljs.ts (100%) rename strix/{ => interface}/viewer/frontend/src/lib/local-run-parser.ts (100%) rename strix/{ => interface}/viewer/frontend/src/lib/target-utils.ts (100%) rename strix/{ => interface}/viewer/frontend/src/lib/utils.ts (100%) rename strix/{ => interface}/viewer/frontend/src/lib/vulnerability-utils.ts (100%) rename strix/{ => interface}/viewer/frontend/src/main.tsx (100%) rename strix/{ => interface}/viewer/frontend/src/stores/auth.ts (100%) rename strix/{ => interface}/viewer/frontend/src/types/events.ts (100%) rename strix/{ => interface}/viewer/frontend/src/types/issues.ts (100%) rename strix/{ => interface}/viewer/frontend/tsconfig.json (100%) rename strix/{ => interface}/viewer/frontend/vite.config.ts (87%) rename strix/{ => interface}/viewer/report_pdf.py (99%) rename strix/{ => interface}/viewer/server.py (99%) rename strix/{ => interface}/viewer/static/assets/index-Dd1cyttN.js (100%) rename strix/{ => interface}/viewer/static/assets/index-vV8wxCG6.css (100%) rename strix/{ => interface}/viewer/static/index.html (100%) rename strix/{ => interface}/viewer/static/logo.png (100%) rename strix/{ => interface}/viewer/transcript.py (95%) diff --git a/.gitignore b/.gitignore index 2e4e4e61..cc938c29 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,8 @@ # Node / local-viewer SPA source (the built bundle in -# strix/viewer/static/ is committed and shipped; do not ignore it) +# strix/interface/viewer/static/ is committed and shipped; do not ignore it) node_modules/ -strix/viewer/frontend/node_modules/ -strix/viewer/frontend/.vite/ +strix/interface/viewer/frontend/node_modules/ +strix/interface/viewer/frontend/.vite/ # Python __pycache__/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 20cb009a..7c7498c3 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -102,16 +102,16 @@ We welcome feature ideas! Please: ## 🖥️ Local viewer SPA `strix view` serves a prebuilt web UI whose source lives in -`strix/viewer/frontend/` (a Vite + React project) and whose built output is -committed to `strix/viewer/static/` and shipped in the package. End users never -run a JS build. If you change anything under `strix/viewer/frontend/`, rebuild +`strix/interface/viewer/frontend/` (a Vite + React project) and whose built output is +committed to `strix/interface/viewer/static/` and shipped in the package. End users never +run a JS build. If you change anything under `strix/interface/viewer/frontend/`, rebuild and commit the output: ```bash -make viewer # or: cd strix/viewer/frontend && npm ci && npm run build +make viewer # or: cd strix/interface/viewer/frontend && npm ci && npm run build ``` -Commit both the source change and the regenerated `strix/viewer/static/`. +Commit both the source change and the regenerated `strix/interface/viewer/static/`. ## 🤝 Community diff --git a/Makefile b/Makefile index 656c0346..da240367 100644 --- a/Makefile +++ b/Makefile @@ -69,8 +69,8 @@ clean: viewer: @echo "🖥️ Building the local-viewer SPA..." - cd strix/viewer/frontend && npm ci && npm run build - @echo "✅ Viewer built to strix/viewer/static/ (commit the changes)." + cd strix/interface/viewer/frontend && npm ci && npm run build + @echo "✅ Viewer built to strix/interface/viewer/static/ (commit the changes)." dev: format lint type-check @echo "✅ Development cycle complete!" diff --git a/pyproject.toml b/pyproject.toml index 2aae0541..6944dd28 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -79,10 +79,10 @@ build-backend = "hatchling.build" [tool.hatch.build.targets.wheel] packages = ["strix"] -# The prebuilt viewer bundle under strix/viewer/static/ ships automatically +# The prebuilt viewer bundle under strix/interface/viewer/static/ ships automatically # (hatchling includes non-.py files under the package). The Vite SOURCE lives -# under the package dir too (strix/viewer/frontend/) but must never ship in the wheel. -exclude = ["strix/viewer/frontend", "strix/viewer/frontend/**"] +# under the package dir too (strix/interface/viewer/frontend/) but must never ship in the wheel. +exclude = ["strix/interface/viewer/frontend", "strix/interface/viewer/frontend/**"] # ============================================================================ # Type Checking Configuration @@ -222,10 +222,10 @@ ignore = [ "tests/test_codex_streaming.py" = ["N802"] "tests/test_report_pdf.py" = ["S105", "S106"] # Stdlib HTTP handler overrides (do_GET/do_POST) and lazy imports that avoid a -# circular dependency with strix.telemetry / strix.viewer.report_pdf. -"strix/viewer/server.py" = ["N802", "PLC0415"] +# circular dependency with strix.telemetry / strix.interface.viewer.report_pdf. +"strix/interface/viewer/server.py" = ["N802", "PLC0415"] # Lazy telemetry import to avoid importing PostHog before the viewer starts. -"strix/viewer/cli.py" = ["PLC0415"] +"strix/interface/viewer/cli.py" = ["PLC0415"] # Lazy imports inside functions to avoid circular dependency with # strix.telemetry / strix.report.dedupe / cvss. "strix/tools/notes/tools.py" = ["PLC0415", "TC002"] diff --git a/strix.spec b/strix.spec index 7c94cca6..19e39b37 100644 --- a/strix.spec +++ b/strix.spec @@ -26,7 +26,7 @@ for tcss_file in strix_root.rglob('*.tcss'): datas.append((str(tcss_file), str(rel_path.parent))) # Prebuilt local-viewer SPA (served by `strix view`). -viewer_static = strix_root / 'viewer' / 'static' +viewer_static = strix_root / 'interface' / 'viewer' / 'static' for asset in viewer_static.rglob('*'): if asset.is_file(): rel_path = asset.relative_to(project_root) @@ -158,12 +158,12 @@ hiddenimports = [ 'strix.report.dedupe', 'strix.report.state', 'strix.report.writer', - 'strix.viewer', - 'strix.viewer.auth', - 'strix.viewer.cli', - 'strix.viewer.report_pdf', - 'strix.viewer.server', - 'strix.viewer.transcript', + 'strix.interface.viewer', + 'strix.interface.viewer.auth', + 'strix.interface.viewer.cli', + 'strix.interface.viewer.report_pdf', + 'strix.interface.viewer.server', + 'strix.interface.viewer.transcript', # PDF report generation + encryption 'reportlab', diff --git a/strix/interface/main.py b/strix/interface/main.py index 8ca10009..3a569717 100644 --- a/strix/interface/main.py +++ b/strix/interface/main.py @@ -952,7 +952,7 @@ def main() -> None: # `strix view []` is a viewer-only subcommand, dispatched before the # scan argument parser (which requires a target) and before any scan setup. if len(sys.argv) > 1 and sys.argv[1] == "view": - from strix.viewer.cli import run_view + from strix.interface.viewer.cli import run_view run_view(sys.argv[2:]) return diff --git a/strix/interface/tui/app.py b/strix/interface/tui/app.py index 21a45b9f..28d3ef08 100644 --- a/strix/interface/tui/app.py +++ b/strix/interface/tui/app.py @@ -1862,7 +1862,7 @@ class StrixTUIApp(App): # type: ignore[misc] webbrowser.open(self._viewer_url) return try: - from strix.viewer.server import authorized_url, bundle_is_built, serve + from strix.interface.viewer.server import authorized_url, bundle_is_built, serve if not bundle_is_built(): self._set_viewer_cta("[#eab308]Viewer UI not built[/]") diff --git a/strix/viewer/__init__.py b/strix/interface/viewer/__init__.py similarity index 84% rename from strix/viewer/__init__.py rename to strix/interface/viewer/__init__.py index 5a0842a7..0e48bb28 100644 --- a/strix/viewer/__init__.py +++ b/strix/interface/viewer/__init__.py @@ -6,7 +6,7 @@ directly from the run's on-disk files. No cloud dependency, no file picker. from __future__ import annotations -from strix.viewer.server import serve +from strix.interface.viewer.server import serve __all__ = ["serve"] diff --git a/strix/viewer/auth.py b/strix/interface/viewer/auth.py similarity index 98% rename from strix/viewer/auth.py rename to strix/interface/viewer/auth.py index c25d12b6..a330ed25 100644 --- a/strix/viewer/auth.py +++ b/strix/interface/viewer/auth.py @@ -4,7 +4,7 @@ The local viewer proxies email verification and encrypted-report delivery to the Strix relay (``STRIX_APP_URL``). The browser never talks to the relay directly, and the report password generated locally is never sent to it. -State lives in ``~/.strix/viewer-auth.json`` (0600). ``is_verified`` is a local +State lives in ``~/.strix/interface/viewer-auth.json`` (0600). ``is_verified`` is a local flag that unlocks browsing the run history list; the relay still enforces token expiry when a report is actually sent. """ @@ -155,7 +155,7 @@ def _post_json(path: str, payload: dict[str, Any], *, timeout: int) -> tuple[int method="POST", ) try: - with urllib.request.urlopen(request, timeout=timeout) as response: # noqa: S310 + with urllib.request.urlopen(request, timeout=timeout) as response: # noqa: S310 # nosec B310 return response.status, _parse_body(response.read()) except urllib.error.HTTPError as exc: return exc.code, _parse_body(exc.read()) diff --git a/strix/viewer/cli.py b/strix/interface/viewer/cli.py similarity index 94% rename from strix/viewer/cli.py rename to strix/interface/viewer/cli.py index 4a3f4d22..efef1efd 100644 --- a/strix/viewer/cli.py +++ b/strix/interface/viewer/cli.py @@ -16,8 +16,8 @@ from strix.core.paths import ( run_record_path, runs_base_dir, ) -from strix.viewer.server import authorized_url, bundle_is_built, serve -from strix.viewer.transcript import read_run_summary +from strix.interface.viewer.server import authorized_url, bundle_is_built, serve +from strix.interface.viewer.transcript import read_run_summary if TYPE_CHECKING: @@ -58,7 +58,7 @@ def run_view(argv: list[str]) -> None: if not bundle_is_built(): console.print( "[bold red]Viewer UI is not built.[/]\n" - "Build it with: [cyan]cd strix/viewer/frontend && npm ci && npm run build[/]" + "Build it with: [cyan]cd strix/interface/viewer/frontend && npm ci && npm run build[/]" ) raise SystemExit(1) diff --git a/strix/viewer/frontend/index.html b/strix/interface/viewer/frontend/index.html similarity index 100% rename from strix/viewer/frontend/index.html rename to strix/interface/viewer/frontend/index.html diff --git a/strix/viewer/frontend/package-lock.json b/strix/interface/viewer/frontend/package-lock.json similarity index 100% rename from strix/viewer/frontend/package-lock.json rename to strix/interface/viewer/frontend/package-lock.json diff --git a/strix/viewer/frontend/package.json b/strix/interface/viewer/frontend/package.json similarity index 100% rename from strix/viewer/frontend/package.json rename to strix/interface/viewer/frontend/package.json diff --git a/strix/viewer/frontend/public/logo.png b/strix/interface/viewer/frontend/public/logo.png similarity index 100% rename from strix/viewer/frontend/public/logo.png rename to strix/interface/viewer/frontend/public/logo.png diff --git a/strix/viewer/frontend/src/App.tsx b/strix/interface/viewer/frontend/src/App.tsx similarity index 100% rename from strix/viewer/frontend/src/App.tsx rename to strix/interface/viewer/frontend/src/App.tsx diff --git a/strix/viewer/frontend/src/components/AddRepositoryDialog.tsx b/strix/interface/viewer/frontend/src/components/AddRepositoryDialog.tsx similarity index 100% rename from strix/viewer/frontend/src/components/AddRepositoryDialog.tsx rename to strix/interface/viewer/frontend/src/components/AddRepositoryDialog.tsx diff --git a/strix/viewer/frontend/src/components/EmailReportView.tsx b/strix/interface/viewer/frontend/src/components/EmailReportView.tsx similarity index 100% rename from strix/viewer/frontend/src/components/EmailReportView.tsx rename to strix/interface/viewer/frontend/src/components/EmailReportView.tsx diff --git a/strix/viewer/frontend/src/components/EmailVerifyInline.tsx b/strix/interface/viewer/frontend/src/components/EmailVerifyInline.tsx similarity index 100% rename from strix/viewer/frontend/src/components/EmailVerifyInline.tsx rename to strix/interface/viewer/frontend/src/components/EmailVerifyInline.tsx diff --git a/strix/viewer/frontend/src/components/FeedbackView.tsx b/strix/interface/viewer/frontend/src/components/FeedbackView.tsx similarity index 100% rename from strix/viewer/frontend/src/components/FeedbackView.tsx rename to strix/interface/viewer/frontend/src/components/FeedbackView.tsx diff --git a/strix/viewer/frontend/src/components/IssueSeveritySummary.tsx b/strix/interface/viewer/frontend/src/components/IssueSeveritySummary.tsx similarity index 100% rename from strix/viewer/frontend/src/components/IssueSeveritySummary.tsx rename to strix/interface/viewer/frontend/src/components/IssueSeveritySummary.tsx diff --git a/strix/viewer/frontend/src/components/PastRunsView.tsx b/strix/interface/viewer/frontend/src/components/PastRunsView.tsx similarity index 100% rename from strix/viewer/frontend/src/components/PastRunsView.tsx rename to strix/interface/viewer/frontend/src/components/PastRunsView.tsx diff --git a/strix/viewer/frontend/src/components/ProCta.tsx b/strix/interface/viewer/frontend/src/components/ProCta.tsx similarity index 100% rename from strix/viewer/frontend/src/components/ProCta.tsx rename to strix/interface/viewer/frontend/src/components/ProCta.tsx diff --git a/strix/viewer/frontend/src/components/RunDetails.tsx b/strix/interface/viewer/frontend/src/components/RunDetails.tsx similarity index 100% rename from strix/viewer/frontend/src/components/RunDetails.tsx rename to strix/interface/viewer/frontend/src/components/RunDetails.tsx diff --git a/strix/viewer/frontend/src/components/Sidebar.tsx b/strix/interface/viewer/frontend/src/components/Sidebar.tsx similarity index 100% rename from strix/viewer/frontend/src/components/Sidebar.tsx rename to strix/interface/viewer/frontend/src/components/Sidebar.tsx diff --git a/strix/viewer/frontend/src/components/TrustToast.tsx b/strix/interface/viewer/frontend/src/components/TrustToast.tsx similarity index 100% rename from strix/viewer/frontend/src/components/TrustToast.tsx rename to strix/interface/viewer/frontend/src/components/TrustToast.tsx diff --git a/strix/viewer/frontend/src/components/UpgradeModal.tsx b/strix/interface/viewer/frontend/src/components/UpgradeModal.tsx similarity index 100% rename from strix/viewer/frontend/src/components/UpgradeModal.tsx rename to strix/interface/viewer/frontend/src/components/UpgradeModal.tsx diff --git a/strix/viewer/frontend/src/components/live/AgentDetailModal.tsx b/strix/interface/viewer/frontend/src/components/live/AgentDetailModal.tsx similarity index 100% rename from strix/viewer/frontend/src/components/live/AgentDetailModal.tsx rename to strix/interface/viewer/frontend/src/components/live/AgentDetailModal.tsx diff --git a/strix/viewer/frontend/src/components/live/AgentGraph.tsx b/strix/interface/viewer/frontend/src/components/live/AgentGraph.tsx similarity index 100% rename from strix/viewer/frontend/src/components/live/AgentGraph.tsx rename to strix/interface/viewer/frontend/src/components/live/AgentGraph.tsx diff --git a/strix/viewer/frontend/src/components/live/AgentNode.tsx b/strix/interface/viewer/frontend/src/components/live/AgentNode.tsx similarity index 100% rename from strix/viewer/frontend/src/components/live/AgentNode.tsx rename to strix/interface/viewer/frontend/src/components/live/AgentNode.tsx diff --git a/strix/viewer/frontend/src/components/live/AgentTranscript.tsx b/strix/interface/viewer/frontend/src/components/live/AgentTranscript.tsx similarity index 100% rename from strix/viewer/frontend/src/components/live/AgentTranscript.tsx rename to strix/interface/viewer/frontend/src/components/live/AgentTranscript.tsx diff --git a/strix/viewer/frontend/src/components/live/GraphSkeleton.tsx b/strix/interface/viewer/frontend/src/components/live/GraphSkeleton.tsx similarity index 100% rename from strix/viewer/frontend/src/components/live/GraphSkeleton.tsx rename to strix/interface/viewer/frontend/src/components/live/GraphSkeleton.tsx diff --git a/strix/viewer/frontend/src/components/live/ScanPromptComposer.tsx b/strix/interface/viewer/frontend/src/components/live/ScanPromptComposer.tsx similarity index 100% rename from strix/viewer/frontend/src/components/live/ScanPromptComposer.tsx rename to strix/interface/viewer/frontend/src/components/live/ScanPromptComposer.tsx diff --git a/strix/viewer/frontend/src/components/live/tool-renderers/AgentCommsRenderer.tsx b/strix/interface/viewer/frontend/src/components/live/tool-renderers/AgentCommsRenderer.tsx similarity index 100% rename from strix/viewer/frontend/src/components/live/tool-renderers/AgentCommsRenderer.tsx rename to strix/interface/viewer/frontend/src/components/live/tool-renderers/AgentCommsRenderer.tsx diff --git a/strix/viewer/frontend/src/components/live/tool-renderers/ApplyPatchRenderer.tsx b/strix/interface/viewer/frontend/src/components/live/tool-renderers/ApplyPatchRenderer.tsx similarity index 100% rename from strix/viewer/frontend/src/components/live/tool-renderers/ApplyPatchRenderer.tsx rename to strix/interface/viewer/frontend/src/components/live/tool-renderers/ApplyPatchRenderer.tsx diff --git a/strix/viewer/frontend/src/components/live/tool-renderers/BrowserRenderer.tsx b/strix/interface/viewer/frontend/src/components/live/tool-renderers/BrowserRenderer.tsx similarity index 100% rename from strix/viewer/frontend/src/components/live/tool-renderers/BrowserRenderer.tsx rename to strix/interface/viewer/frontend/src/components/live/tool-renderers/BrowserRenderer.tsx diff --git a/strix/viewer/frontend/src/components/live/tool-renderers/ChatBubble.tsx b/strix/interface/viewer/frontend/src/components/live/tool-renderers/ChatBubble.tsx similarity index 100% rename from strix/viewer/frontend/src/components/live/tool-renderers/ChatBubble.tsx rename to strix/interface/viewer/frontend/src/components/live/tool-renderers/ChatBubble.tsx diff --git a/strix/viewer/frontend/src/components/live/tool-renderers/FallbackRenderer.tsx b/strix/interface/viewer/frontend/src/components/live/tool-renderers/FallbackRenderer.tsx similarity index 100% rename from strix/viewer/frontend/src/components/live/tool-renderers/FallbackRenderer.tsx rename to strix/interface/viewer/frontend/src/components/live/tool-renderers/FallbackRenderer.tsx diff --git a/strix/viewer/frontend/src/components/live/tool-renderers/FileEditRenderer.tsx b/strix/interface/viewer/frontend/src/components/live/tool-renderers/FileEditRenderer.tsx similarity index 100% rename from strix/viewer/frontend/src/components/live/tool-renderers/FileEditRenderer.tsx rename to strix/interface/viewer/frontend/src/components/live/tool-renderers/FileEditRenderer.tsx diff --git a/strix/viewer/frontend/src/components/live/tool-renderers/FinishRenderer.tsx b/strix/interface/viewer/frontend/src/components/live/tool-renderers/FinishRenderer.tsx similarity index 100% rename from strix/viewer/frontend/src/components/live/tool-renderers/FinishRenderer.tsx rename to strix/interface/viewer/frontend/src/components/live/tool-renderers/FinishRenderer.tsx diff --git a/strix/viewer/frontend/src/components/live/tool-renderers/LoadSkillRenderer.tsx b/strix/interface/viewer/frontend/src/components/live/tool-renderers/LoadSkillRenderer.tsx similarity index 100% rename from strix/viewer/frontend/src/components/live/tool-renderers/LoadSkillRenderer.tsx rename to strix/interface/viewer/frontend/src/components/live/tool-renderers/LoadSkillRenderer.tsx diff --git a/strix/viewer/frontend/src/components/live/tool-renderers/Markdown.tsx b/strix/interface/viewer/frontend/src/components/live/tool-renderers/Markdown.tsx similarity index 100% rename from strix/viewer/frontend/src/components/live/tool-renderers/Markdown.tsx rename to strix/interface/viewer/frontend/src/components/live/tool-renderers/Markdown.tsx diff --git a/strix/viewer/frontend/src/components/live/tool-renderers/NotesRenderer.tsx b/strix/interface/viewer/frontend/src/components/live/tool-renderers/NotesRenderer.tsx similarity index 100% rename from strix/viewer/frontend/src/components/live/tool-renderers/NotesRenderer.tsx rename to strix/interface/viewer/frontend/src/components/live/tool-renderers/NotesRenderer.tsx diff --git a/strix/viewer/frontend/src/components/live/tool-renderers/ProxyRenderer.tsx b/strix/interface/viewer/frontend/src/components/live/tool-renderers/ProxyRenderer.tsx similarity index 100% rename from strix/viewer/frontend/src/components/live/tool-renderers/ProxyRenderer.tsx rename to strix/interface/viewer/frontend/src/components/live/tool-renderers/ProxyRenderer.tsx diff --git a/strix/viewer/frontend/src/components/live/tool-renderers/PythonRenderer.tsx b/strix/interface/viewer/frontend/src/components/live/tool-renderers/PythonRenderer.tsx similarity index 100% rename from strix/viewer/frontend/src/components/live/tool-renderers/PythonRenderer.tsx rename to strix/interface/viewer/frontend/src/components/live/tool-renderers/PythonRenderer.tsx diff --git a/strix/viewer/frontend/src/components/live/tool-renderers/ScanInfoRenderer.tsx b/strix/interface/viewer/frontend/src/components/live/tool-renderers/ScanInfoRenderer.tsx similarity index 100% rename from strix/viewer/frontend/src/components/live/tool-renderers/ScanInfoRenderer.tsx rename to strix/interface/viewer/frontend/src/components/live/tool-renderers/ScanInfoRenderer.tsx diff --git a/strix/viewer/frontend/src/components/live/tool-renderers/TerminalRenderer.tsx b/strix/interface/viewer/frontend/src/components/live/tool-renderers/TerminalRenderer.tsx similarity index 100% rename from strix/viewer/frontend/src/components/live/tool-renderers/TerminalRenderer.tsx rename to strix/interface/viewer/frontend/src/components/live/tool-renderers/TerminalRenderer.tsx diff --git a/strix/viewer/frontend/src/components/live/tool-renderers/ThinkRenderer.tsx b/strix/interface/viewer/frontend/src/components/live/tool-renderers/ThinkRenderer.tsx similarity index 100% rename from strix/viewer/frontend/src/components/live/tool-renderers/ThinkRenderer.tsx rename to strix/interface/viewer/frontend/src/components/live/tool-renderers/ThinkRenderer.tsx diff --git a/strix/viewer/frontend/src/components/live/tool-renderers/TodoRenderer.tsx b/strix/interface/viewer/frontend/src/components/live/tool-renderers/TodoRenderer.tsx similarity index 100% rename from strix/viewer/frontend/src/components/live/tool-renderers/TodoRenderer.tsx rename to strix/interface/viewer/frontend/src/components/live/tool-renderers/TodoRenderer.tsx diff --git a/strix/viewer/frontend/src/components/live/tool-renderers/ToolCard.tsx b/strix/interface/viewer/frontend/src/components/live/tool-renderers/ToolCard.tsx similarity index 100% rename from strix/viewer/frontend/src/components/live/tool-renderers/ToolCard.tsx rename to strix/interface/viewer/frontend/src/components/live/tool-renderers/ToolCard.tsx diff --git a/strix/viewer/frontend/src/components/live/tool-renderers/ViewImageRenderer.tsx b/strix/interface/viewer/frontend/src/components/live/tool-renderers/ViewImageRenderer.tsx similarity index 100% rename from strix/viewer/frontend/src/components/live/tool-renderers/ViewImageRenderer.tsx rename to strix/interface/viewer/frontend/src/components/live/tool-renderers/ViewImageRenderer.tsx diff --git a/strix/viewer/frontend/src/components/live/tool-renderers/VulnReportRenderer.tsx b/strix/interface/viewer/frontend/src/components/live/tool-renderers/VulnReportRenderer.tsx similarity index 100% rename from strix/viewer/frontend/src/components/live/tool-renderers/VulnReportRenderer.tsx rename to strix/interface/viewer/frontend/src/components/live/tool-renderers/VulnReportRenderer.tsx diff --git a/strix/viewer/frontend/src/components/live/tool-renderers/WebSearchRenderer.tsx b/strix/interface/viewer/frontend/src/components/live/tool-renderers/WebSearchRenderer.tsx similarity index 100% rename from strix/viewer/frontend/src/components/live/tool-renderers/WebSearchRenderer.tsx rename to strix/interface/viewer/frontend/src/components/live/tool-renderers/WebSearchRenderer.tsx diff --git a/strix/viewer/frontend/src/components/live/tool-renderers/index.ts b/strix/interface/viewer/frontend/src/components/live/tool-renderers/index.ts similarity index 100% rename from strix/viewer/frontend/src/components/live/tool-renderers/index.ts rename to strix/interface/viewer/frontend/src/components/live/tool-renderers/index.ts diff --git a/strix/viewer/frontend/src/components/live/tool-renderers/utils.ts b/strix/interface/viewer/frontend/src/components/live/tool-renderers/utils.ts similarity index 100% rename from strix/viewer/frontend/src/components/live/tool-renderers/utils.ts rename to strix/interface/viewer/frontend/src/components/live/tool-renderers/utils.ts diff --git a/strix/viewer/frontend/src/components/vulnerability/CodeDiffBlock.tsx b/strix/interface/viewer/frontend/src/components/vulnerability/CodeDiffBlock.tsx similarity index 100% rename from strix/viewer/frontend/src/components/vulnerability/CodeDiffBlock.tsx rename to strix/interface/viewer/frontend/src/components/vulnerability/CodeDiffBlock.tsx diff --git a/strix/viewer/frontend/src/components/vulnerability/ContentSection.tsx b/strix/interface/viewer/frontend/src/components/vulnerability/ContentSection.tsx similarity index 100% rename from strix/viewer/frontend/src/components/vulnerability/ContentSection.tsx rename to strix/interface/viewer/frontend/src/components/vulnerability/ContentSection.tsx diff --git a/strix/viewer/frontend/src/components/vulnerability/IssueSidebar.tsx b/strix/interface/viewer/frontend/src/components/vulnerability/IssueSidebar.tsx similarity index 100% rename from strix/viewer/frontend/src/components/vulnerability/IssueSidebar.tsx rename to strix/interface/viewer/frontend/src/components/vulnerability/IssueSidebar.tsx diff --git a/strix/viewer/frontend/src/components/vulnerability/MdCodeBlock.tsx b/strix/interface/viewer/frontend/src/components/vulnerability/MdCodeBlock.tsx similarity index 100% rename from strix/viewer/frontend/src/components/vulnerability/MdCodeBlock.tsx rename to strix/interface/viewer/frontend/src/components/vulnerability/MdCodeBlock.tsx diff --git a/strix/viewer/frontend/src/components/vulnerability/PocBlock.tsx b/strix/interface/viewer/frontend/src/components/vulnerability/PocBlock.tsx similarity index 100% rename from strix/viewer/frontend/src/components/vulnerability/PocBlock.tsx rename to strix/interface/viewer/frontend/src/components/vulnerability/PocBlock.tsx diff --git a/strix/viewer/frontend/src/components/vulnerability/VulnerabilityDetail.tsx b/strix/interface/viewer/frontend/src/components/vulnerability/VulnerabilityDetail.tsx similarity index 100% rename from strix/viewer/frontend/src/components/vulnerability/VulnerabilityDetail.tsx rename to strix/interface/viewer/frontend/src/components/vulnerability/VulnerabilityDetail.tsx diff --git a/strix/viewer/frontend/src/data/serverSource.ts b/strix/interface/viewer/frontend/src/data/serverSource.ts similarity index 100% rename from strix/viewer/frontend/src/data/serverSource.ts rename to strix/interface/viewer/frontend/src/data/serverSource.ts diff --git a/strix/viewer/frontend/src/index.css b/strix/interface/viewer/frontend/src/index.css similarity index 100% rename from strix/viewer/frontend/src/index.css rename to strix/interface/viewer/frontend/src/index.css diff --git a/strix/viewer/frontend/src/lib/cta.ts b/strix/interface/viewer/frontend/src/lib/cta.ts similarity index 100% rename from strix/viewer/frontend/src/lib/cta.ts rename to strix/interface/viewer/frontend/src/lib/cta.ts diff --git a/strix/viewer/frontend/src/lib/display-number.ts b/strix/interface/viewer/frontend/src/lib/display-number.ts similarity index 100% rename from strix/viewer/frontend/src/lib/display-number.ts rename to strix/interface/viewer/frontend/src/lib/display-number.ts diff --git a/strix/viewer/frontend/src/lib/fenced-code.ts b/strix/interface/viewer/frontend/src/lib/fenced-code.ts similarity index 100% rename from strix/viewer/frontend/src/lib/fenced-code.ts rename to strix/interface/viewer/frontend/src/lib/fenced-code.ts diff --git a/strix/viewer/frontend/src/lib/hljs.ts b/strix/interface/viewer/frontend/src/lib/hljs.ts similarity index 100% rename from strix/viewer/frontend/src/lib/hljs.ts rename to strix/interface/viewer/frontend/src/lib/hljs.ts diff --git a/strix/viewer/frontend/src/lib/local-run-parser.ts b/strix/interface/viewer/frontend/src/lib/local-run-parser.ts similarity index 100% rename from strix/viewer/frontend/src/lib/local-run-parser.ts rename to strix/interface/viewer/frontend/src/lib/local-run-parser.ts diff --git a/strix/viewer/frontend/src/lib/target-utils.ts b/strix/interface/viewer/frontend/src/lib/target-utils.ts similarity index 100% rename from strix/viewer/frontend/src/lib/target-utils.ts rename to strix/interface/viewer/frontend/src/lib/target-utils.ts diff --git a/strix/viewer/frontend/src/lib/utils.ts b/strix/interface/viewer/frontend/src/lib/utils.ts similarity index 100% rename from strix/viewer/frontend/src/lib/utils.ts rename to strix/interface/viewer/frontend/src/lib/utils.ts diff --git a/strix/viewer/frontend/src/lib/vulnerability-utils.ts b/strix/interface/viewer/frontend/src/lib/vulnerability-utils.ts similarity index 100% rename from strix/viewer/frontend/src/lib/vulnerability-utils.ts rename to strix/interface/viewer/frontend/src/lib/vulnerability-utils.ts diff --git a/strix/viewer/frontend/src/main.tsx b/strix/interface/viewer/frontend/src/main.tsx similarity index 100% rename from strix/viewer/frontend/src/main.tsx rename to strix/interface/viewer/frontend/src/main.tsx diff --git a/strix/viewer/frontend/src/stores/auth.ts b/strix/interface/viewer/frontend/src/stores/auth.ts similarity index 100% rename from strix/viewer/frontend/src/stores/auth.ts rename to strix/interface/viewer/frontend/src/stores/auth.ts diff --git a/strix/viewer/frontend/src/types/events.ts b/strix/interface/viewer/frontend/src/types/events.ts similarity index 100% rename from strix/viewer/frontend/src/types/events.ts rename to strix/interface/viewer/frontend/src/types/events.ts diff --git a/strix/viewer/frontend/src/types/issues.ts b/strix/interface/viewer/frontend/src/types/issues.ts similarity index 100% rename from strix/viewer/frontend/src/types/issues.ts rename to strix/interface/viewer/frontend/src/types/issues.ts diff --git a/strix/viewer/frontend/tsconfig.json b/strix/interface/viewer/frontend/tsconfig.json similarity index 100% rename from strix/viewer/frontend/tsconfig.json rename to strix/interface/viewer/frontend/tsconfig.json diff --git a/strix/viewer/frontend/vite.config.ts b/strix/interface/viewer/frontend/vite.config.ts similarity index 87% rename from strix/viewer/frontend/vite.config.ts rename to strix/interface/viewer/frontend/vite.config.ts index 696fbb84..a7704a8f 100644 --- a/strix/viewer/frontend/vite.config.ts +++ b/strix/interface/viewer/frontend/vite.config.ts @@ -5,7 +5,7 @@ import { fileURLToPath, URL } from "node:url"; // The viewer is served as static files by a stdlib Python server on an // arbitrary ephemeral port, so all asset URLs must be relative (base: "./"). -// The build output is committed at strix/viewer/static and shipped. +// The build output is committed at strix/interface/viewer/static and shipped. export default defineConfig({ base: "./", plugins: [react(), tailwindcss()], diff --git a/strix/viewer/report_pdf.py b/strix/interface/viewer/report_pdf.py similarity index 99% rename from strix/viewer/report_pdf.py rename to strix/interface/viewer/report_pdf.py index c3b011c9..951fb668 100644 --- a/strix/viewer/report_pdf.py +++ b/strix/interface/viewer/report_pdf.py @@ -38,7 +38,7 @@ from reportlab.platypus import ( TableStyle, ) -from strix.viewer.transcript import ( +from strix.interface.viewer.transcript import ( primary_target, read_run_summary, read_vulnerabilities, diff --git a/strix/viewer/server.py b/strix/interface/viewer/server.py similarity index 99% rename from strix/viewer/server.py rename to strix/interface/viewer/server.py index 77cee58d..1b5d0e9d 100644 --- a/strix/viewer/server.py +++ b/strix/interface/viewer/server.py @@ -27,8 +27,8 @@ from typing import TYPE_CHECKING, Any from urllib.parse import parse_qs, unquote, urlencode, urlsplit from strix.core.paths import run_record_path -from strix.viewer import auth -from strix.viewer.transcript import ( +from strix.interface.viewer import auth +from strix.interface.viewer.transcript import ( build_run_state, primary_target, read_report_markdown, @@ -367,7 +367,7 @@ def _make_handler(state: _ViewerState) -> type[BaseHTTPRequestHandler]: self._send_json(HTTPStatus.CONFLICT, {"error": "run_not_finished"}) return - from strix.viewer.report_pdf import build_encrypted_report + from strix.interface.viewer.report_pdf import build_encrypted_report pdf_bytes, password, filename = build_encrypted_report(run_dir) run_name = str(summary.get("run_name") or run_dir.name) diff --git a/strix/viewer/static/assets/index-Dd1cyttN.js b/strix/interface/viewer/static/assets/index-Dd1cyttN.js similarity index 100% rename from strix/viewer/static/assets/index-Dd1cyttN.js rename to strix/interface/viewer/static/assets/index-Dd1cyttN.js diff --git a/strix/viewer/static/assets/index-vV8wxCG6.css b/strix/interface/viewer/static/assets/index-vV8wxCG6.css similarity index 100% rename from strix/viewer/static/assets/index-vV8wxCG6.css rename to strix/interface/viewer/static/assets/index-vV8wxCG6.css diff --git a/strix/viewer/static/index.html b/strix/interface/viewer/static/index.html similarity index 100% rename from strix/viewer/static/index.html rename to strix/interface/viewer/static/index.html diff --git a/strix/viewer/static/logo.png b/strix/interface/viewer/static/logo.png similarity index 100% rename from strix/viewer/static/logo.png rename to strix/interface/viewer/static/logo.png diff --git a/strix/viewer/transcript.py b/strix/interface/viewer/transcript.py similarity index 95% rename from strix/viewer/transcript.py rename to strix/interface/viewer/transcript.py index 3f287168..0011315c 100644 --- a/strix/viewer/transcript.py +++ b/strix/interface/viewer/transcript.py @@ -44,8 +44,8 @@ def build_run_state(run_dir: Path) -> dict[str, Any]: Reuses the Textual-free ``TuiLiveView`` projection so the viewer and the TUI share one parser for ``agents.json`` + ``agents.db`` and never drift. """ - # Imported lazily so importing strix.viewer does not eagerly pull the TUI. - from strix.interface.tui.live_view import TuiLiveView # noqa: PLC0415 + # Imported lazily so importing strix.interface.viewer does not eagerly pull the TUI. + from strix.interface.tui.live_view import TuiLiveView view = TuiLiveView() view.hydrate_from_run_dir(run_dir) diff --git a/tests/test_fenced_code.py b/tests/test_fenced_code.py index bef2b8ae..be3b473c 100644 --- a/tests/test_fenced_code.py +++ b/tests/test_fenced_code.py @@ -4,13 +4,13 @@ from __future__ import annotations from pygments.lexers import BashLexer, PythonLexer +from strix.interface.viewer.report_pdf import _strip_code_fence from strix.report.writer import ( guess_language_name, parse_fenced_code, resolve_lexer, safe_fence, ) -from strix.viewer.report_pdf import _strip_code_fence def test_parse_fenced_code_extracts_language_and_body() -> None: diff --git a/tests/test_report_pdf.py b/tests/test_report_pdf.py index dc76ecef..305ad33f 100644 --- a/tests/test_report_pdf.py +++ b/tests/test_report_pdf.py @@ -10,7 +10,7 @@ import pytest from pypdf import PdfReader from pypdf.errors import WrongPasswordError -from strix.viewer.report_pdf import ( +from strix.interface.viewer.report_pdf import ( build_encrypted_report, encrypt_pdf, generate_password, @@ -91,7 +91,7 @@ def test_wrong_password_is_rejected(tmp_path: Path) -> None: run_dir = _make_run(tmp_path) encrypted = encrypt_pdf(generate_report_pdf(run_dir), "correct-horse-battery") with pytest.raises(WrongPasswordError): - PdfReader(BytesIO(encrypted), password="not-the-password") + PdfReader(BytesIO(encrypted), password="not-the-password") # nosec B106 def test_build_encrypted_report(tmp_path: Path) -> None: diff --git a/tests/test_viewer.py b/tests/test_viewer.py index 00fec4f1..faa306f6 100644 --- a/tests/test_viewer.py +++ b/tests/test_viewer.py @@ -1,4 +1,4 @@ -"""Tests for the local run viewer (strix.viewer) and its path helpers.""" +"""Tests for the local run viewer (strix.interface.viewer) and its path helpers.""" from __future__ import annotations @@ -9,8 +9,8 @@ import urllib.request from typing import TYPE_CHECKING from strix.core.paths import latest_run_dir, runs_base_dir -from strix.viewer.server import serve -from strix.viewer.transcript import ( +from strix.interface.viewer.server import serve +from strix.interface.viewer.transcript import ( build_run_state, read_report_markdown, read_run_summary, @@ -89,7 +89,7 @@ def test_build_run_state_from_agents_json(tmp_path: Path) -> None: def _get(url: str, *, cookie: str | None = None) -> tuple[int, str, bytes]: headers = {"Cookie": cookie} if cookie else {} req = urllib.request.Request(url, headers=headers) # noqa: S310 - localhost test server - with urllib.request.urlopen(req) as resp: # noqa: S310 - localhost test server + with urllib.request.urlopen(req) as resp: # noqa: S310 - localhost test server # nosec B310 return resp.status, resp.headers.get("Content-Type", ""), resp.read() @@ -100,7 +100,7 @@ def test_server_serves_api_and_static(tmp_path: Path, monkeypatch: pytest.Monkey (assets / "assets").mkdir(parents=True) (assets / "index.html").write_text("
", encoding="utf-8") (assets / "assets" / "app.js").write_text("console.log(1)", encoding="utf-8") - monkeypatch.setattr("strix.viewer.server.bundle_dir", lambda: assets) + monkeypatch.setattr("strix.interface.viewer.server.bundle_dir", lambda: assets) httpd, url, _ = serve(run_dir, open_browser=False) try: @@ -132,7 +132,7 @@ def test_server_event_endpoint_forwards_cta( assets = tmp_path / "bundle" assets.mkdir() (assets / "index.html").write_text("x", encoding="utf-8") - monkeypatch.setattr("strix.viewer.server.bundle_dir", lambda: assets) + monkeypatch.setattr("strix.interface.viewer.server.bundle_dir", lambda: assets) seen: list[tuple[str, str | None]] = [] monkeypatch.setattr( @@ -148,7 +148,7 @@ def test_server_event_endpoint_forwards_cta( req = urllib.request.Request( # noqa: S310 - localhost test server f"{url}/api/event", data=body, headers={"Content-Type": "application/json"} ) - with urllib.request.urlopen(req) as resp: # noqa: S310 + with urllib.request.urlopen(req) as resp: # noqa: S310 # nosec B310 assert resp.status == 204 assert seen == [("PR reviews", "sidebar_nav")] finally: @@ -163,7 +163,7 @@ def test_server_event_endpoint_forwards_email_funnel( assets = tmp_path / "bundle" assets.mkdir() (assets / "index.html").write_text("x", encoding="utf-8") - monkeypatch.setattr("strix.viewer.server.bundle_dir", lambda: assets) + monkeypatch.setattr("strix.interface.viewer.server.bundle_dir", lambda: assets) seen: list[tuple[str, str | None]] = [] monkeypatch.setattr( @@ -183,7 +183,7 @@ def test_server_event_endpoint_forwards_email_funnel( data=json.dumps(payload).encode(), headers={"Content-Type": "application/json"}, ) - with urllib.request.urlopen(req) as resp: # noqa: S310 + with urllib.request.urlopen(req) as resp: # noqa: S310 # nosec B310 assert resp.status == 204 assert seen == expected finally: @@ -207,7 +207,7 @@ def test_server_event_endpoint_forwards_agent_steered( data=json.dumps({"event": "agent_steered"}).encode(), headers={"Content-Type": "application/json"}, ) - with urllib.request.urlopen(req) as resp: # noqa: S310 + with urllib.request.urlopen(req) as resp: # noqa: S310 # nosec B310 assert resp.status == 204 assert seen == [True] finally: @@ -222,7 +222,7 @@ def test_feedback_records_telemetry_on_success( _bundle(tmp_path, monkeypatch) sent: list[bool] = [] - monkeypatch.setattr("strix.viewer.auth.feedback_submit", lambda *_a: None) + monkeypatch.setattr("strix.interface.viewer.auth.feedback_submit", lambda *_a: None) monkeypatch.setattr( "strix.telemetry.posthog.viewer_feedback_submitted", lambda: sent.append(True) ) @@ -257,7 +257,7 @@ def _post( url + path, data=json.dumps(payload).encode(), headers=headers, method="POST" ) try: - with urllib.request.urlopen(req) as resp: # noqa: S310 + with urllib.request.urlopen(req) as resp: # noqa: S310 # nosec B310 return resp.status, resp.read() except urllib.error.HTTPError as exc: return exc.code, exc.read() @@ -266,7 +266,7 @@ def _post( def _session_cookie(url: str, token: str) -> str: """Bootstrap a session via the tokened URL and return its ``name=value`` cookie.""" bootstrap = f"{url}/?token={token}" - with urllib.request.urlopen(bootstrap) as resp: # noqa: S310 - localhost test server + with urllib.request.urlopen(bootstrap) as resp: # noqa: S310 - localhost test server # nosec B310 raw = str(resp.headers.get("Set-Cookie", "")) return raw.split(";", 1)[0] @@ -275,7 +275,7 @@ def _get_status(url: str, *, cookie: str | None = None) -> int: headers = {"Cookie": cookie} if cookie else {} req = urllib.request.Request(url, headers=headers) # noqa: S310 - localhost test server try: - with urllib.request.urlopen(req) as resp: # noqa: S310 + with urllib.request.urlopen(req) as resp: # noqa: S310 # nosec B310 return int(resp.status) except urllib.error.HTTPError as exc: return int(exc.code) @@ -285,7 +285,7 @@ def _bundle(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: assets = tmp_path / "bundle" assets.mkdir() (assets / "index.html").write_text("
", encoding="utf-8") - monkeypatch.setattr("strix.viewer.server.bundle_dir", lambda: assets) + monkeypatch.setattr("strix.interface.viewer.server.bundle_dir", lambda: assets) def test_capability_issued_only_for_tokened_bootstrap( @@ -296,26 +296,26 @@ def test_capability_issued_only_for_tokened_bootstrap( (assets / "assets").mkdir(parents=True) (assets / "index.html").write_text("index", encoding="utf-8") (assets / "assets" / "app.js").write_text("1", encoding="utf-8") - monkeypatch.setattr("strix.viewer.server.bundle_dir", lambda: assets) + monkeypatch.setattr("strix.interface.viewer.server.bundle_dir", lambda: assets) httpd, url, token = serve(run_dir, open_browser=False) try: # A bare index load -- all a reachable client can do -- hands out nothing. - with urllib.request.urlopen(url + "/") as resp: # noqa: S310 + with urllib.request.urlopen(url + "/") as resp: # noqa: S310 # nosec B310 assert resp.headers.get("Set-Cookie") is None # A wrong token is likewise refused the capability. - with urllib.request.urlopen(f"{url}/?token=wrong") as resp: # noqa: S310 + with urllib.request.urlopen(f"{url}/?token=wrong") as resp: # noqa: S310 # nosec B310 assert resp.headers.get("Set-Cookie") is None # Only the correct bootstrap token mints the session cookie. - with urllib.request.urlopen(f"{url}/?token={token}") as resp: # noqa: S310 + with urllib.request.urlopen(f"{url}/?token={token}") as resp: # noqa: S310 # nosec B310 cookie = str(resp.headers.get("Set-Cookie", "")) assert "strix_viewer_session=" in cookie assert "HttpOnly" in cookie and "SameSite=Strict" in cookie # Static assets never carry it. - with urllib.request.urlopen(url + "/assets/app.js") as resp: # noqa: S310 + with urllib.request.urlopen(url + "/assets/app.js") as resp: # noqa: S310 # nosec B310 assert resp.headers.get("Set-Cookie") is None finally: httpd.shutdown() @@ -338,7 +338,7 @@ def test_unauthorized_client_cannot_acquire_capability( try: # A direct network client can reach the page but is handed no capability, # so replaying an empty/guessed cookie cannot steer a live scan. - with urllib.request.urlopen(url + "/") as resp: # noqa: S310 + with urllib.request.urlopen(url + "/") as resp: # noqa: S310 # nosec B310 assert resp.headers.get("Set-Cookie") is None status, _ = _post( url, @@ -356,9 +356,11 @@ def test_unauthorized_client_cannot_acquire_capability( def test_auth_status_reflects_expiry(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> None: run_dir = _make_run(tmp_path, "status", status="running", end_time=None) _bundle(tmp_path, monkeypatch) - monkeypatch.setattr("strix.viewer.auth.read_auth", lambda: {"email": "a@b.com", "token": "t"}) + monkeypatch.setattr( + "strix.interface.viewer.auth.read_auth", lambda: {"email": "a@b.com", "token": "t"} + ) verified = {"value": True} - monkeypatch.setattr("strix.viewer.auth.is_verified", lambda: verified["value"]) + monkeypatch.setattr("strix.interface.viewer.auth.is_verified", lambda: verified["value"]) httpd, url, token = serve(run_dir, open_browser=False) try: @@ -384,7 +386,7 @@ def test_auth_mutations_require_session(tmp_path: Path, monkeypatch: pytest.Monk run_dir = _make_run(tmp_path, "authmut", status="running", end_time=None) _bundle(tmp_path, monkeypatch) forgotten = {"value": False} - monkeypatch.setattr("strix.viewer.auth.forget", lambda: forgotten.update(value=True)) + monkeypatch.setattr("strix.interface.viewer.auth.forget", lambda: forgotten.update(value=True)) httpd, url, _ = serve(run_dir, open_browser=False) try: @@ -432,7 +434,9 @@ def test_report_send_requires_session_cookie( _bundle(tmp_path, monkeypatch) # A verified machine token exists, but that alone must not authorize a caller. - monkeypatch.setattr("strix.viewer.auth.read_auth", lambda: {"email": "a@b.com", "token": "t"}) + monkeypatch.setattr( + "strix.interface.viewer.auth.read_auth", lambda: {"email": "a@b.com", "token": "t"} + ) httpd, url, token = serve(run_dir, open_browser=False) try: @@ -456,7 +460,9 @@ def test_report_send_rejects_live_run(tmp_path: Path, monkeypatch: pytest.Monkey # fail closed even for a verified, session-holding caller. run_dir = _make_run(tmp_path, "live", status="running", end_time=None) _bundle(tmp_path, monkeypatch) - monkeypatch.setattr("strix.viewer.auth.read_auth", lambda: {"email": "a@b.com", "token": "t"}) + monkeypatch.setattr( + "strix.interface.viewer.auth.read_auth", lambda: {"email": "a@b.com", "token": "t"} + ) httpd, url, token = serve(run_dir, open_browser=False) try: @@ -475,7 +481,7 @@ def test_historical_run_data_requires_verification( _bundle(tmp_path, monkeypatch) verified = {"value": False} - monkeypatch.setattr("strix.viewer.auth.is_verified", lambda: verified["value"]) + monkeypatch.setattr("strix.interface.viewer.auth.is_verified", lambda: verified["value"]) httpd, url, token = serve(launched, open_browser=False) try: @@ -509,12 +515,12 @@ def test_runs_list_requires_session_and_verification( _make_run(tmp_path, "other", status="completed", end_time="2026-01-01T00:00:00Z") _bundle(tmp_path, monkeypatch) - monkeypatch.setattr("strix.viewer.auth.is_verified", lambda: True) + monkeypatch.setattr("strix.interface.viewer.auth.is_verified", lambda: True) def _runs(cookie: str | None) -> dict[str, object]: headers = {"Cookie": cookie} if cookie else {} req = urllib.request.Request(f"{url}/api/runs", headers=headers) # noqa: S310 - with urllib.request.urlopen(req) as resp: # noqa: S310 - localhost test server + with urllib.request.urlopen(req) as resp: # noqa: S310 - localhost test server # nosec B310 return dict(json.loads(resp.read())) httpd, url, token = serve(launched, open_browser=False) @@ -543,7 +549,7 @@ def test_server_rejects_path_traversal(tmp_path: Path, monkeypatch: pytest.Monke assets = tmp_path / "bundle" assets.mkdir() (assets / "index.html").write_text("index", encoding="utf-8") - monkeypatch.setattr("strix.viewer.server.bundle_dir", lambda: assets) + monkeypatch.setattr("strix.interface.viewer.server.bundle_dir", lambda: assets) httpd, url, _ = serve(run_dir, open_browser=False) try: diff --git a/tests/test_viewer_auth.py b/tests/test_viewer_auth.py index 049f80a2..662f84f1 100644 --- a/tests/test_viewer_auth.py +++ b/tests/test_viewer_auth.py @@ -8,7 +8,7 @@ from typing import TYPE_CHECKING, Any import pytest -from strix.viewer import auth +from strix.interface.viewer import auth def _iso(delta: timedelta) -> str: @@ -30,7 +30,7 @@ def test_write_read_forget_roundtrip() -> None: assert auth.read_auth() is None assert auth.is_verified() is False - auth.write_auth(email="user@example.com", token="tok-123", verified_at=_iso(timedelta(days=30))) + auth.write_auth(email="user@example.com", token="tok-123", verified_at=_iso(timedelta(days=30))) # nosec B106 record = auth.read_auth() assert record is not None @@ -47,23 +47,23 @@ def test_write_read_forget_roundtrip() -> None: def test_is_verified_enforces_expiry() -> None: # An expired record still reads back, but no longer unlocks history. - auth.write_auth(email="a@b.com", token="t", verified_at=_iso(timedelta(hours=-1))) + auth.write_auth(email="a@b.com", token="t", verified_at=_iso(timedelta(hours=-1))) # nosec B106 assert auth.read_auth() is not None assert auth.is_verified() is False # A future expiry unlocks it. - auth.write_auth(email="a@b.com", token="t", verified_at=_iso(timedelta(hours=1))) + auth.write_auth(email="a@b.com", token="t", verified_at=_iso(timedelta(hours=1))) # nosec B106 assert auth.is_verified() is True def test_is_verified_fails_closed_when_expiry_absent_or_unparseable() -> None: # No/blank expiry: fail closed rather than unlocking history forever. - auth.write_auth(email="a@b.com", token="t", verified_at="") + auth.write_auth(email="a@b.com", token="t", verified_at="") # nosec B106 assert auth.read_auth() is not None assert auth.is_verified() is False # Garbage expiry likewise requires re-verification. - auth.write_auth(email="a@b.com", token="t", verified_at="not-a-date") + auth.write_auth(email="a@b.com", token="t", verified_at="not-a-date") # nosec B106 assert auth.is_verified() is False @@ -73,9 +73,9 @@ def test_is_verified_accepts_epoch_expiry() -> None: past = (datetime.now(UTC) - timedelta(hours=1)).timestamp() # As a numeric string (how write_auth persists it). - auth.write_auth(email="a@b.com", token="t", verified_at=str(future)) + auth.write_auth(email="a@b.com", token="t", verified_at=str(future)) # nosec B106 assert auth.is_verified() is True - auth.write_auth(email="a@b.com", token="t", verified_at=str(past)) + auth.write_auth(email="a@b.com", token="t", verified_at=str(past)) # nosec B106 assert auth.is_verified() is False # As a raw JSON number, if a record is written that way. @@ -87,7 +87,7 @@ def test_is_verified_accepts_epoch_expiry() -> None: def test_write_auth_is_0600() -> None: - auth.write_auth(email="a@b.com", token="t", verified_at="") + auth.write_auth(email="a@b.com", token="t", verified_at="") # nosec B106 mode = stat.S_IMODE(auth.AUTH_PATH.stat().st_mode) assert mode == 0o600 diff --git a/tests/test_viewer_runs_gating.py b/tests/test_viewer_runs_gating.py index 380e2c9c..81780437 100644 --- a/tests/test_viewer_runs_gating.py +++ b/tests/test_viewer_runs_gating.py @@ -5,7 +5,7 @@ from __future__ import annotations import json from typing import TYPE_CHECKING -from strix.viewer.server import build_runs_payload, resolve_run_dir +from strix.interface.viewer.server import build_runs_payload, resolve_run_dir if TYPE_CHECKING: