Commit Graph
37 Commits
Author SHA1 Message Date
alex sandGitHub 90d00a98cb Add target list CLI option (#711)
* Add target list CLI option

* Handle target list comments and encoding errors
2026-07-06 23:33:08 -04:00
Mads HvelplundandGitHub 519750c1cc Support large target repos with with bind-mount option. (#577)
* fix: resolve pre-commit check failures

- Change RuntimeError to TypeError for type validation in report/writer.py
- Update pyupgrade to v3.21.2 for Python 3.14 compatibility

* chore: add pytest test infrastructure

Mirror the layout introduced on feature/438-token_budget: pytest +
pytest-asyncio dev deps, asyncio_mode auto, a tests.* mypy override, and
pytest in the mypy pre-commit hook deps so the tests/ package type-checks.

* feat: add --mount and large-target pre-flight for local repos (#492)

Large local targets were copied into the sandbox file-by-file via the SDK
LocalDir entry, which stalls on big repos and could leave /workspace empty.

- --mount <path> bind-mounts a host directory read-only at /workspace/<subdir>
  instead of copying it, bypassing the per-file stream.
- A size pre-flight (STRIX_MAX_LOCAL_COPY_MB, default 1024) fails fast with a
  clear message suggesting --mount when a non-mounted local target is too big.

* fix: reject empty --mount paths

An empty or whitespace-only --mount value resolves to the current working
directory and would silently bind-mount it into the sandbox. Reject it.

* fix: dedupe local targets so a dir is never both copied and mounted

If the same directory is passed via --target and --mount (or as duplicate
values), it previously produced two targets — copied AND bind-mounted, and
the copied one could trip the size pre-flight. Dedupe by resolved path,
preferring the bind mount.

* fix: treat non-positive STRIX_MAX_LOCAL_COPY_MB as disabled

Previously a value of 0 (or negative) made every local target count as
oversized, aborting all local scans. Now <= 0 disables the pre-flight.

* fix: log unreadable subtrees during size pre-flight

os.walk silently swallowed directory-listing errors, so a permission-denied
subtree could make a large repo under-count and slip past the pre-flight.
Surface such omissions via an onerror warning.

* docs: document --mount and STRIX_MAX_LOCAL_COPY_MB

Add CLI reference + example for --mount, document the size pre-flight env var,
note the read-only-is-not-a-hard-boundary caveat and that remote repos are not
size-checked, and clarify the backends docstring on when bind mounts apply.

* Update strix/interface/main.py


* Update strix/runtime/docker_client.py


---------
2026-06-22 12:41:42 -04:00
0xallam 6e4b065e0e Strip narrative comments and module/helper docstrings
Five rounds of sweep across the tree. Net ~544 lines removed.

Removed:
- Section-divider banners and one-line section labels (# Display
  utilities, # ----- list_requests -----, # CVSS breakdown, etc.).
- Module-level prose docstrings on internal modules. Kept one-line
  summaries; trimmed multi-paragraph narration about SDK/Strix
  responsibility splits, cache strategies, three-source precedence.
- Internal-helper docstrings that just restate the function name —
  caido_api helpers (caido_url, get_client, view_request, etc.),
  settings-class one-liners (LLMSettings, RuntimeSettings, ...),
  UI helper docstrings.
- Args/Returns blocks on non-LLM-facing internal helpers
  (build_strix_agent, render_system_prompt, create_or_reuse,
  bootstrap_caido) — kept only the genuinely non-obvious params.
- Internal-history phrasing — "Mirrors main-branch shape",
  "pre-SDK harness", "previous lookup matched no attribute".
- Narrative comments inside function bodies that explained what the
  next line does, design rationale obvious from the surrounding code,
  or "we used to..." asides.
- Trailing periods on every error-string literal across the tool tree.
- Duplicated roundtripTime quirk comment (kept the LLM-facing copy in
  tools/proxy/tools.py).

Kept (every one names an upstream bug, vendored-code provenance, or
non-obvious data quirk):
- core/runner.py: SDK replay-with-empty-initial-input + on_agent_end
  lifecycle gap.
- runtime/docker_client.py: VERBATIM COPY block of the upstream
  _create_container body, pinned to SDK v0.14.6.
- runtime/session_manager.py: NO_PROXY for agent-browser CDP loopback.
- tools/proxy/caido_api.py: generated-pydantic Request.raw quirk,
  replay double-history pitfall.
- tools/proxy/tools.py: Caido roundtripTime=0 quirk for proxy
  captures.
2026-05-26 14:02:40 -07:00
0xallam 8ba2d6a663 Record usage per SDK LLM response 2026-04-26 15:54:45 -07:00
0xallam 6e57739734 Track SDK LLM usage 2026-04-26 15:38:41 -07:00
0xallam 49623ee625 chore: remove generated migration docs 2026-04-26 14:36:58 -07:00
0xallam b963e269ca refactor: remove custom llm provider layer 2026-04-26 14:04:32 -07:00
0xallam eee65eec9e Simplify SDK-native orchestration 2026-04-26 11:30:00 -07:00
0xallam 01f80e2dd4 feat(interface): show resume hint on the existing exit panel
When a scan ends without calling ``finish_scan`` (Ctrl+C, TUI quit,
crash), ``display_completion_message`` now appends one extra line
inside the existing completion panel:

    Resume  strix --run-name <run_name>

Same ``dim``-label / coloured-value styling as the panel's ``Target``
and ``Output`` rows. Only rendered when ``scan_completed`` is False —
a finished scan doesn't need a resume nudge.

Triggers ``orchestration/scan.py``'s implicit-resume path on the next
invocation (presence of ``{run_dir}/bus.json`` is the trigger), so
the user gets back exactly where they left off — root + every
non-terminal subagent's full LLM history, bus topology, prior
findings.

Covers both ``run_cli`` and ``run_tui`` paths since
``display_completion_message`` is called from ``main()`` regardless
of which front-end ran.
2026-04-26 00:38:17 -07:00
0xallam d26fe76b88 feat(interface): show resume hint on user-initiated exit
When the user shuts down a run (Ctrl+C in CLI, Ctrl+Q / quit dialog
in TUI, or an uncaught exception during the scan), print a Rich
panel telling them the exact command to pick up where they left off:

    strix --run-name <run_name>

The panel only appears when ``strix_runs/<run_name>/bus.json``
exists — i.e. the scan registered at least the root agent and has
snapshot state worth resuming from. Suppressed when:

  * No run-name was assigned (Ctrl+C before sandbox bring-up).
  * The run dir doesn't exist or has no bus.json yet.

Implementation:

  * ``strix/interface/utils.py`` gains ``format_resume_hint(run_name)
    -> Panel | None``.
  * ``cli.py`` calls it in the SIGINT/SIGTERM/SIGHUP handler before
    ``sys.exit(1)``, and in the ``except Exception`` arm before the
    re-raise.
  * ``tui.py:run_tui`` calls it in a ``finally`` after
    ``app.run_async()`` so the hint lands on the real terminal once
    Textual has restored it (whether the user pressed Ctrl+Q,
    confirmed the quit dialog, or the run completed naturally).
2026-04-26 00:34:44 -07:00
0xallam bc6303b5a3 refactor(config): pydantic-settings revamp + drop `is_whitebox` plumbing
Replaces 200+ lines of bespoke env-loader / persist / change-detection
machinery with ``pydantic_settings.BaseSettings`` (already a transitive
of ``openai-agents → mcp``, no new direct dep).

What was wrong with ``Config``:

- 14 knobs flat in one namespace, weak grouping by comment-block.
- ``Config._applied_from_default`` and ``Config._config_file_override``
  were externally mutated from ``interface/main.py:532-534``. Private
  members were part of the public contract.
- Stringly-typed values: every caller had to coerce
  (``int(Config.get("llm_timeout") or "300")``,
  ``... not in {"0", "false", "no", "off"}``).
- Dead knob: ``strix_llm_max_retries`` declared, persisted, listed in
  ``_LLM_CANONICAL_NAMES`` — zero readers (``DEFAULT_RETRY``
  hardcodes ``max_retries=5``). Dropped.
- ``_LLM_CANONICAL_NAMES`` tuple maintained alongside class vars —
  duplicate source of truth.
- ``_tracked_names()`` introspected ``vars(cls).items()`` filtered on
  ``(v is None or isinstance(v, str))`` — fragile.
- Awkward path: ``strix/config/config.py`` inside ``strix/config/``
  with ``__init__.py`` just re-exporting.
- Dual access for the same fact: ``web_search`` read
  ``os.getenv("PERPLEXITY_API_KEY")`` while ``main.py`` read
  ``Config.get("perplexity_api_key")``.

New shape:

- ``strix/config/settings.py`` — typed dataclass tree:
  ``Settings.{llm,runtime,telemetry,integrations}``. Each sub-model is
  its own ``BaseSettings`` so it reads env independently. Field-level
  ``alias=`` and ``validation_alias=AliasChoices(...)`` mirror the
  existing flat env-var names — user-facing env contract is unchanged.
  Bool fields auto-parse ``"0"``/``"false"``/``"no"``/``"off"``;
  int fields auto-coerce.
- ``strix/config/loader.py`` — thin ``load_settings()``,
  ``apply_config_override(path)``, ``persist_current()`` with module
  cache. JSON file reader walks aliases to populate sub-models, dropping
  entries already covered by env (so env still wins).
- 13 callsites migrated from ``Config.get("...")`` to
  ``load_settings().<group>.<field>``.
- ``posthog._is_enabled()`` collapses to one line.
- ``--config <path>`` flow simplified: one
  ``apply_config_override(...)`` call replaces three lines of
  class-private mutation.

Drive-by — drop ``is_whitebox`` from ``scan_config`` dict:

- It was being derived as ``bool(args.local_sources)`` in three places
  (``cli.py``, ``tui.py``, ``main.py``) and stuffed into the dict for
  ``entry.py`` to read back. The fact is fully derivable from
  ``scan_config["targets"]`` — any target with ``type == "local_code"``.
- New helper ``is_whitebox_scan(targets)`` in ``interface/utils.py``
  alongside the other target-classification utilities.
- ``entry.py`` computes once; ``main.py``'s posthog start uses the same
  helper. Triplicate derivation gone.

Verified: ruff at baseline (3), mypy at baseline (69). Six smoke tests
pass — defaults / JSON-only / env-wins-over-JSON / alias-chain
fallback / bool parsing / ``is_whitebox_scan``.
2026-04-25 16:05:40 -07:00
0xallam 4d2fa45db6 refactor: scrub migration scars, dead code, and unused helpers
- Strip PLAYBOOK / AUDIT / Phase-N / C-numbered references from
  module docstrings across 16 files; rename
  ``_PHASE1_PARALLEL_DEFAULT`` → ``_PARALLEL_TOOL_CALLS_DEFAULT``.
- Delete unused exception classes: ``SandboxInitializationError``,
  ``ImplementedInClientSideOnlyError``.
- Delete the no-op ``on_handoff`` hook (we don't use SDK handoffs).
- Delete the unreachable backward-compat tab-delimited fallback in
  ``_parse_git_diff_output``.
- Delete orphaned ``strix/tools/load_skill/`` (dir contained only a
  pycache) and stale pycache files.
- Rewrite ``strix/skills/__init__.py``: 168 → 56 LoC. Drop seven
  helper functions (``get_available_skills``, ``get_all_skill_names``,
  ``validate_skill_names``, ``parse_skill_list``,
  ``validate_requested_skills``, ``generate_skills_description``,
  ``_get_all_categories``) — none had external callers; only
  ``load_skills`` is used.
- Drop the stale ``strix/agents/sdk_factory.py`` per-file ruff ignore
  (file no longer exists).
2026-04-25 12:05:24 -07:00
0xallam 5606504563 refactor: nuke legacy harness, drop sdk_ prefixes
The SDK harness is the only path now; legacy host-side code is gone.
File names no longer carry the ``sdk_`` distinction.

Deleted legacy host-side modules:
- strix/agents/StrixAgent/ (template moved to strix/agents/prompts/)
- strix/agents/base_agent.py, state.py
- strix/llm/llm.py, config.py
- strix/runtime/docker_runtime.py, runtime.py
- strix/tools/executor.py, agents_graph/agents_graph_actions.py
- strix/interface/sdk_dispatch.py + the env-flag dispatch in cli.py

Renamed (drop ``sdk_`` prefix):
- strix/sdk_entry.py → strix/entry.py
- strix/agents/sdk_factory.py → strix/agents/factory.py
- strix/agents/sdk_prompt.py → strix/agents/prompt.py
- strix/tools/<x>/<x>_sdk_tool[s].py → strix/tools/<x>/tool[s].py
- strix/tools/_legacy_adapter.py → strix/tools/_state_adapter.py
- ``_legacy`` aliases inside the wrappers → ``_impl``

CLI + TUI now call ``run_strix_scan`` directly — they build the
sandbox image / sources_path locally and rely on
``session_manager.cleanup`` (called inside ``run_strix_scan``'s finally)
for teardown. Three TUI handlers that reached into legacy multi-agent
globals (``_agent_instances``, ``send_user_message_to_agent``,
``stop_agent``) are now no-ops with a TODO; reconnecting them to the
``AgentMessageBus`` is a follow-up.

Tracer.get_total_llm_stats no longer reaches into the deleted
``agents_graph_actions`` globals — the orchestration hooks now feed the
tracer via ``Tracer.record_llm_usage`` (live + completed buckets).
finish_scan's ``_check_active_agents`` and load_skill's runtime
``_agent_instances`` reach-in are no-op stubs; the
``AgentMessageBus`` is the source of truth post-migration.

llm/utils.py rewritten to keep only the streaming-parser helpers
(``normalize_tool_format``, ``parse_tool_invocations``,
``fix_incomplete_tool_call``, ``format_tool_call``, ``clean_content``).
``STRIX_MODEL_MAP`` moved to ``llm/multi_provider_setup.py`` (its only
remaining caller).

Per-file ruff ignores added for legacy interface modules (TUI / main /
CLI / utils / streaming_parser / tool_components) and tracer.py —
pre-existing PLC0415/BLE001/PLR0915 patterns are out of scope.

Tests: 287/287 passing. Renamed test files to drop ``sdk_`` prefix.
``test_tracer.py::test_get_total_llm_stats_aggregates_live_and_completed``
rewritten to feed ``Tracer.record_llm_usage`` instead of legacy globals.
Test file annotations added so pre-commit's strict mypy passes.
2026-04-25 09:30:23 -07:00
0xallam 0339ba85ba feat(migration): phase 5b — STRIX_USE_SDK_HARNESS dispatch flag
Adds the env-var gate that lets users opt into the SDK harness without
disturbing the legacy default. Per PLAYBOOK §7.1, this is the cutover
mechanism: STRIX_USE_SDK_HARNESS=1 routes scans through run_strix_scan
(the Phase 5 entry point); anything else continues to use
StrixAgent.execute_scan.

- strix/interface/sdk_dispatch.py:
  - should_use_sdk_harness(): truthy-string parse of the env var.
  - _resolve_sandbox_image(): reads strix_image from Config; falls
    back to "strix-sandbox:latest" with a warning if unset.
  - _resolve_sources_path(): when --local-sources is given, mounts
    its parent so the agent walks down to the source tree; otherwise
    creates a per-run scratch dir under XDG_CACHE_HOME/strix/sources/.
    Phase 6 will replace this with the legacy clone-into-container
    flow once we port that.
  - run_scan_via_sdk(): the adapter — translates the legacy CLI
    (scan_config dict + argparse Namespace + Tracer) into the keyword
    arguments run_strix_scan expects. Returns the SDK RunResult; lets
    failures bubble up.

- strix/interface/cli.py: adds the dispatch branch inside the existing
  Live/status loop. Legacy default unchanged; SDK path is reached only
  when STRIX_USE_SDK_HARNESS is truthy. Two pre-existing lazy imports
  hoisted to module level (cleanup_runtime + sdk_dispatch helpers) so
  ruff is happy.

Pre-existing legacy lint/type issues surfaced when pre-commit checked
the edited cli.py and chased imports — fixed or ignored in passing:
- utils.py:1052 duplicate ``metadata`` annotation removed.
- utils.py:1251 unused ``# type: ignore[import-not-found]`` for yarl.
- main.py:456 ``panel_parts`` inferred type rejected later string
  entries — explicit ``list[Text | str]`` annotation.
- utils.py:resolve_diff_scope_context PLR0912 (16 branches) per-file
  ignore — branches map 1:1 to scope-mode × target-type combinations.

Tests: 18 new tests in tests/interface/test_sdk_dispatch.py — env
flag parsing parametrized over truthy/falsy variants, image lookup
with config hit + miss-with-warning, sources path resolution for
local_sources / alternative key names / scratch-dir creation, and
the adapter's kwarg handoff verified against a patched
run_strix_scan (run_name from args + run_name from scan_config
fallback + failure propagation).

Refs: PLAYBOOK.md §7.1 (cutover), §7.2 (rollback).
2026-04-25 08:03:00 -07:00
alex sandGitHub 51834e6649 feat: Better source-aware testing (#391) 2026-03-31 11:53:49 -07:00
0xallamandAhmed Allam 35174dced2 feat: Expose Caido proxy port to host for human-in-the-loop interaction
Users can now access the Caido web UI from their browser to inspect traffic,
replay requests, and perform manual testing alongside the automated scan.

- Map Caido port (48080) to a random host port in DockerRuntime
- Add caido_port to SandboxInfo and track across container lifecycle
- Display Caido URL in TUI sidebar stats panel with selectable text
- Bind Caido to 0.0.0.0 in entrypoint (requires image rebuild)
- Bump sandbox image to 0.1.12
- Restore discord link in exit screen
2026-02-23 18:37:25 -08:00
0xallamandAhmed Allam c226d7405c feat: Redesign vulnerability reporting with nested XML code locations and CVSS
Replace 12 flat parameters (code_file, code_before, code_after, code_diff,
and 8 CVSS fields) with structured nested XML fields: code_locations with
co-located fix_before/fix_after per location, cvss_breakdown, and cwe.

This enables multi-file vulnerability locations, per-location fixes with
precise line numbers, data flow representation (source/sink), CWE
classification, and compatibility with GitHub/GitLab PR review APIs.
2026-02-15 17:25:59 -08:00
0xallamandAhmed Allam 21e543d856 fix: Replace hardcoded git host detection with HTTP protocol probe
Remove hardcoded github.com/gitlab.com/bitbucket.org host lists from
infer_target_type. Instead, detect git repositories on any host by
querying the standard /info/refs?service=git-upload-pack endpoint.

Works for any self-hosted git instance.
2026-01-31 23:24:59 -08:00
0xallam 7a2d38ef26 chore: unify token stats color scheme 2026-01-22 11:37:21 -08:00
0xallam 26b4d35bc1 chore: improve stats panel layout 2026-01-22 11:17:32 -08:00
b453a96cae refactor: simplify --config implementation to reuse existing config system
- Reuse apply_saved() instead of custom override logic
- Add force parameter to override existing env vars
- Move validation to utils.py
- Prevent saving when using custom config (one-time override)
- Fix: don't modify ~/.strix/cli-config.json when --config is used

Co-Authored-By: FeedClogger <feedclogger@users.noreply.github.com>
2026-01-20 17:02:29 -08:00
0xallam 7cfb2e9cf9 refactor: improve stats panel styling and add version display 2026-01-19 21:46:13 -08:00
0xallamandAhmed Allam c7b016d726 refactor: redesign finished dialogs and UI elements 2026-01-19 16:52:02 -08:00
0xallamandAhmed Allam dc26a440b5 Simplify stats panel display format 2026-01-09 14:25:00 -08:00
0xallamandAhmed Allam 3f19ab1188 fix: add timeout handling for Docker operations and improve error messages
- Add SandboxInitializationError exception for sandbox/Docker failures
- Add 60-second timeout to Docker client initialization
- Add _exec_run_with_timeout() method using ThreadPoolExecutor for exec_run calls
- Catch ConnectionError and Timeout exceptions from requests library
- Add _handle_sandbox_error() and _handle_llm_error() methods in base_agent.py
- Handle sandbox_error_details tool in TUI for displaying errors
- Increase TUI truncation limits for better error visibility
- Update all Docker error messages with helpful hint:
  'Please ensure Docker Desktop is installed and running, and try running strix again.'
2026-01-08 17:41:44 -08:00
0xallamandAhmed Allam ae9719e648 fix(tui): hide cost in stats panel when zero 2026-01-08 12:21:18 -08:00
0xallamandAhmed Allam 3ec2609f6d fix(tui): rename 'Tokens' to 'Total Tokens' in stats display 2026-01-08 12:21:18 -08:00
0xallamandAhmed Allam 532a15127f feat(tui): add vulnerability detail dialog with markdown copy support
- Add VulnerabilityDetailScreen modal with full vulnerability details
- Add Copy button that exports report as markdown to clipboard
- Add VulnerabilitiesPanel in sidebar showing found vulnerabilities
- Add clickable VulnerabilityItem widgets with severity-colored dots
- ESC key closes modal dialogs
- Remove emojis from TUI stats panel for cleaner display
- Add build_tui_stats_text() for minimal TUI-specific stats
2026-01-08 12:21:18 -08:00
0xallam 18ce29ab25 feat(reporting): improve vulnerability display and reporting format 2026-01-07 19:51:41 -08:00
0xallamandAhmed Allam f2138c87f8 feat: enable container access to host localhost services
Rewrite localhost/127.x.x.x/0.0.0.0 target URLs to use host.docker.internal,
allowing the container to reach services running on the host machine.

- Add extra_hosts mapping for host.docker.internal on Linux
- Add HOST_GATEWAY env var to container
- Add rewrite_localhost_targets() to transform localhost URLs
- Support full 127.0.0.0/8 loopback range and IPv6 ::1
2026-01-07 12:04:21 -08:00
0xallamandAhmed Allam 5bdb59001a feat(tui): enhance splash screen and agent status display
- Reduced animation timer for splash screen to improve responsiveness.
- Added URL display to the splash screen.
- Improved start line animation with dynamic character styling.
- Updated agent status display to show "Initializing Agent" when no real activity is detected.
- Enhanced waiting and animated verb text with dynamic styling.
- Implemented sidebar visibility toggle based on window size.
- Updated live stats to include model information from agent configuration.
- Refined TUI styles for better visual consistency.
2026-01-06 16:44:22 -08:00
2faf23d79b feat: Show Model Name in Live Stats Panel (#169)
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2025-12-03 18:45:01 +00:00
976faaaebd Real-time display panel for agent stats (#134)
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2025-11-25 12:06:20 +00:00
Ahmed AllamandAhmed Allam 2b2b7967b8 feat: enhance run name generation to include target information 2025-11-22 22:54:07 +04:00
Ahmed AllamandAhmed Allam dffdc50a98 feat: support scanning IP addresses 2025-11-14 01:38:58 +04:00
Ahmed AllamandAhmed Allam e5dd46e534 fix: replace raise with sys.exit(1) in clone_repository for better error handling 2025-11-01 02:38:37 +02:00
Ahmed AllamandAhmed Allam 23ace6aac2 feat: implement multi-target scanning 2025-11-01 02:38:37 +02:00