Commit graph

892 commits

Author SHA1 Message Date
Ahmed Allam
6b7e3b77e8 fix(docker): drop the module docstring 2026-10-05 03:00:25 +03:00
Ahmed Allam
6dd164eebb fix(docker): keep DOCKER_HOST on from_env so TLS settings apply; a missing current context is an error 2026-10-05 03:00:25 +03:00
Ahmed Allam
828462cfc9 fix(docker): use the current docker context only, no DOCKER_CONTEXT override 2026-10-05 03:00:25 +03:00
Ahmed Allam
172246b5db fix(docker): drop the per-platform cause tables, show the endpoint and the raw error 2026-10-05 03:00:25 +03:00
Ahmed Allam
b46fc2fb19 fix(docker): connect like the docker CLI and explain why the daemon is unreachable
docker.from_env() ignores the current docker context, so Docker Desktop on
macOS (socket under ~/.docker/run unless the default-socket option is on),
OrbStack and Colima reported DOCKER NOT AVAILABLE while `docker ps` worked.
Every failure also printed the same "ensure Docker Desktop is running" text
followed by a RuntimeError traceback.

- resolve the endpoint as the CLI does: DOCKER_HOST, then DOCKER_CONTEXT or
  the current context, then the default socket; the sandbox backend uses the
  same resolution so startup and scan talk to the same daemon
- classify the SDK error (socket missing, permission denied, connection
  refused, Windows named pipe) and print the fix for the current platform,
  the endpoint that was tried and the underlying error
- exit 1 cleanly instead of raising after the panel
- telemetry reports docker_unavailable_<reason>
2026-10-05 03:00:25 +03:00
Ahmed Allam
fc85e0061e fix(cli): let --fail-on through when no terminal is attached
parse_arguments() rejected --fail-on without -n before main() could switch
to headless, so a CI job running `strix -t x --fail-on high` without -n
stopped at an argument error instead of scanning. The terminal check now
lives in cli_args as terminal_attached(); the parser only enforces the
headless-only flag when a terminal is attached and the TUI would open.
2026-10-05 00:37:27 +03:00
Ahmed Allam
1ee5c2bcc6 fix(cli): run headless when no terminal is attached instead of crashing the TUI
Without a tty on stdin and stdout (CI, nohup, pipes, cron, TERM=dumb) the Go
TUI handshakes fine and then exits 1 the moment Bubble Tea tries to take over
the screen. Because the backend was already activated, that exit escaped the
pre-activation mapping and surfaced as a raw traceback:
RuntimeError: Bubble Tea TUI exited with status 1.

Now main() checks for a terminal right after argument parsing. With a target
it switches to the headless path (same as -n) and prints one dim notice.
Without a target the start screen is the only way to enter one, so it prints
a panel telling the user to pass -t <target> -n and exits 1. A bare --resume
is left to the picker, which already lists runs when there is no terminal.

If the sidecar still dies after startup, check_return_code raises
TuiProcessExitedError, run_tui maps it to InteractiveInterfaceExitedError,
and main() prints an INTERACTIVE INTERFACE STOPPED panel with the -n hint
under its own telemetry name instead of re-raising.
2026-10-05 00:37:27 +03:00
Ahmed Allam
e3401c4fc7 test(preflight): exercise warm_up_llm with a dedicated dedupe model without touching process-wide SDK defaults 2026-10-04 23:12:23 +03:00
Ahmed Allam
0c33f5776f fix(preflight): name the dedupe endpoint setting in its timeout message and test the dedupe warm-up
preflight_request takes api_base_setting so a dedupe model that timed out
points the user at DEDUPE_LLM_API_BASE, not LLM_API_BASE. warm_up_llm is
now exercised with a dedicated dedupe model: own headers, same preflight
timeout, resolved through resolve_dedupe_model.
2026-10-04 23:12:23 +03:00
Ahmed Allam
3527d1f81d fix(preflight): give the startup model check its own 30s timeout instead of LLM_TIMEOUT
The warm-up request used settings.llm.timeout (LLM_TIMEOUT, 300s) both as
the request timeout and the wait_for bound, so a wrong LLM_API_BASE or a
dead proxy hung five minutes and then printed an empty Error line.

Add LlmSettings.preflight_timeout (LLM_PREFLIGHT_TIMEOUT, default 30) and
a shared preflight_request() used for the main and dedupe models. When it
expires the panel names the model, the limit and the setting.
2026-10-04 23:12:23 +03:00
Ahmed Allam
7ce44ef69a ci(package): check for a missing module without a bare negation so shellcheck is happy 2026-10-04 22:05:21 +03:00
Ahmed Allam
265e508d5c fix(deps): declare boto3 directly and exercise Vertex AI and Bedrock auth from the frozen binary in CI 2026-10-04 22:05:21 +03:00
Ahmed Allam
6a3d2ec9b8 ci(release): publish a GitHub release only from a tag so a manual run just builds 2026-10-04 22:05:21 +03:00
Ahmed Allam
86edf1c5ff fix(deps): ship google-auth with every install so Vertex AI works in release binaries 2026-10-04 22:05:21 +03:00
Ahmed Allam
881bc09a06 ci: drop the CodeQL workflow 2026-10-04 21:07:06 +03:00
Ahmed Allam
a5b80af428 ci: split CI into per-concern reusable workflows behind one ci-passed gate
Add uv lock --check, a wheel install smoke test, a PyInstaller dry run,
actionlint and zizmor on the workflows, CodeQL, and Dependabot for action
pins, uv, Go and npm dependencies. Release caches are disabled so zizmor's
cache-poisoning audit passes.
2026-10-04 21:07:06 +03:00
Ahmed Allam
2a7864a947 ci: run ruff, mypy, bandit, pytest, Go TUI and viewer checks on every pull request 2026-10-04 21:07:06 +03:00
Ahmed Allam
aa3144dac4 fix(resume-picker): cancel on ctrl+c during drawing too 2026-10-04 20:52:33 +03:00
Ahmed Allam
28fa7f7734 fix(resume-picker): treat ctrl+c as cancel instead of leaking a KeyboardInterrupt traceback 2026-10-04 20:52:33 +03:00
Ahmed Allam
7a31053348 test(pricing): accept any identically priced provider for bare grok-4.5 2026-10-04 20:38:45 +03:00
Ahmed Allam
cd3bc8011e fix(resume-picker): keep --instruction on a picked run, tolerate blank instructions, read UTF-8 keys, fit narrow terminals, cap the window at 8 rows 2026-10-04 20:07:47 +03:00
Ahmed Allam
e954301a09 feat(cli): pick a prior run interactively when --resume has no name
strix --resume with no run name now lists the runs in ./strix_runs inline
in the terminal (started, target, status, findings, run name), newest
first, with arrow-key selection, type-to-search and esc to cancel.
Picking a run continues through the same path as --resume <name>.
Headless or non-TTY launches error with the run list instead.
2026-10-04 20:07:47 +03:00
Ahmed Allam
deb6d81d79 refactor(telemetry): keep only the unraisable hook, no docstrings 2026-10-04 18:35:07 +03:00
Ahmed Allam
eaf16c6817 refactor(telemetry): collapse the exception hooks into one plain function
No install-once global, no hand-rolled traceback formatting, no SystemExit special case: one helper logs the report with exc_info on strix.telemetry when a handler exists, and both hooks call it.
2026-10-04 18:35:07 +03:00
Ahmed Allam
8ea2c99225 revert(runtime): drop the PTY teardown change in StrixDockerSandboxClient.delete()
Keep this PR to the logging change only: the finalizer reports are routed to strix.log by the unraisable hook, so the sandbox teardown stays as on main.
2026-10-04 18:35:07 +03:00
Ahmed Allam
fa5f99c4e0 fix(telemetry): route every unraisable and thread exception to strix.log, never stderr
Completes the previous commit, which only carried the test rename. sys.unraisablehook (finalizers, __del__, GC and weakref callbacks, files closed at exit) and threading.excepthook are replaced for the life of the process with hooks that log the report at WARNING on strix.telemetry: strix.log, and stderr only when the stream handler runs at DEBUG (STRIX_DEBUG=1). Nothing is delegated to Python's default printers; a report arriving after the strix handlers are torn down is dropped instead of reaching logging.lastResort, and failures inside logging itself are swallowed.
2026-10-04 18:35:07 +03:00
Ahmed Allam
121216096c fix(telemetry): route every unraisable and thread exception to strix.log, never stderr
Replaces the pattern-matched urllib3/http.client filter with a generic rule: sys.unraisablehook (finalizers, __del__, GC and weakref callbacks, files closed at exit) and threading.excepthook are replaced for the life of the process with hooks that log the report at WARNING on strix.telemetry. That goes to strix.log, and to stderr only when the stream handler runs at DEBUG (STRIX_DEBUG=1). Nothing is delegated to Python's default printers; a report arriving after the strix handlers are torn down is dropped instead of reaching logging.lastResort, and failures inside logging itself are swallowed so nothing can print mid-shutdown.

tests/test_hook_exceptions_logged.py covers both hooks in-process and end to end in a fresh interpreter (a __del__ raising at shutdown, a thread traceback, a urllib3 response whose file was closed first): stderr stays empty.
2026-10-04 18:35:07 +03:00
Ahmed Allam
d945eeee32 fix(telemetry): match only http.client responses in the finalizer filter; test PTY teardown through the real SDK session
The object-shape match accepted any http.* class; it now takes urllib3 and http.client only, so a closed-file error from another module still reaches the previous unraisable hook. New tests build a real DockerSandboxSession holding a PTY exec stream and run the real SDK delete() with the container gone: the SDK alone leaves the socket and its pinned response open, StrixDockerSandboxClient.delete() closes both.
2026-10-04 18:35:07 +03:00
Ahmed Allam
b4be726a3b fix(runtime): terminate PTY exec streams on teardown and silence 3.14 response finalizer noise
StrixDockerSandboxClient.delete() killed the container and then let the SDK's delete() run shutdown(), which only terminates the agent's PTY exec streams while the container still exists. Once the container was gone the hijacked exec sockets were left to the garbage collector and their HTTP responses failed to close at interpreter exit, which Python 3.14 reports as "Exception ignored while finalizing file <urllib3.response.HTTPResponse>" after the scan summary. delete() now awaits pty_terminate_all() first, whatever the container's state.

The unraisable filter now also matches Python 3.14's finalizer shape (object=None, repr in err_msg) and http.client responses, and logs the match at DEBUG on strix.telemetry instead of letting it reach stderr.
2026-10-04 18:35:07 +03:00
Ahmed Allam
25f3978804 fix(cli): install the stderr log handler at startup and prepare the run state before the TUI launches 2026-10-04 05:44:06 +03:00
Ahmed Allam
5325009f65 fix(cli): verify the model before the TUI opens on a direct launch 2026-10-04 05:44:06 +03:00
Ahmed Allam
d218c29ed1 fix(tui): blank row under panel headers; no panel controls when Agents is the only panel 2026-10-04 04:54:29 +03:00
Ahmed Allam
849671f288 fix(tui): drop the Model label from the stats panel 2026-10-04 04:54:29 +03:00
Ahmed Allam
faca0d4d1d fix(tui): pin the Model panel to the sidebar bottom and enlarge the show-sidebar button 2026-10-04 04:54:29 +03:00
Ahmed Allam
1a680f4aa3 fix(tui): keep sidebar panels inside the terminal height 2026-10-04 04:54:29 +03:00
Ahmed Allam
701c22b8a9 fix(tui): collapsible, zoomable sidebar panels and a sidebar toggle
Every sidebar panel gets a header with a click-to-collapse chevron and a
click-to-zoom glyph; a one-row chip on the viewer line hides the whole
sidebar and brings it back from a narrow rail. Tab skips collapsed and
hidden panels, scrollbar hit zones follow the rendered bars, and
fillBackground also repaints after the bare ESC[m reset so no cell shows
the terminal background.
2026-10-04 04:54:29 +03:00
Ahmed Allam
e1d7f5c433 fix(tui): keep blank lines inside fenced code when rendering report markdown 2026-10-04 02:11:45 +03:00
Ahmed Allam
64dae6f484 fix(tui): render report section bodies as markdown 2026-10-04 02:11:45 +03:00
Ahmed Allam
b49ac2fd9e fix(preflight): check extra headers for subscription models and the dedupe key as sent 2026-10-04 01:48:35 +03:00
Ahmed Allam
08df05db61 fix(preflight): skip unused credentials for subscription models, check dedupe credentials too 2026-10-04 01:48:35 +03:00
Ahmed Allam
4ca15a6e60 style: drop docstrings from the header-value check 2026-10-04 01:48:35 +03:00
Ahmed Allam
539960d953 fix(preflight): name a non-ASCII character in the API key instead of raising UnicodeEncodeError
httpx encodes header values as ASCII, so a smart quote, non-breaking
space or byte-order mark pasted into LLM_API_KEY (or LLM_EXTRA_HEADERS)
surfaced as a bare UnicodeEncodeError from inside the client, wrapped in
ModelConnectionError. The preflight now checks these settings first and
fails with the setting name, the code point, its Unicode name and its
position. Nothing is trimmed or rewritten and the key itself is never
printed.
2026-10-04 01:48:35 +03:00
Ahmed Allam
7280c40caa style: drop docstrings from the UTF-8 stream helpers 2026-10-04 01:19:48 +03:00
Ahmed Allam
5c3476795a fix(cli): force UTF-8 stdout/stderr on Windows so Rich output never raises
Windows hands a redirected or legacy console stream the ANSI code page
(cp1252), which cannot encode Rich's panels or the model's text: one
check mark in a finding ended a headless run with UnicodeEncodeError, and
the error handler raised again rendering its own panel. Reconfigure both
streams to UTF-8 at startup on win32, and open the Go TUI's os.devnull
sink as UTF-8 so logging into it stops producing --- Logging error ---
reports under the same code page.
2026-10-04 01:19:48 +03:00
Ahmed Allam
45b775dcd5 fix(cli): apply the --fail-on threshold regardless of run status
A stopped run with no findings already exits 0, so skipping the threshold
only when low findings exist made the gate depend on the wrong thing.
The threshold now always applies; reporting an unfinished run is a separate
exit-code concern.
2026-10-04 00:03:23 +03:00
siundu254
b11228192d Resolve PR Comments 2026-10-04 00:03:23 +03:00
siundu254
3cd6c93fa0 Fail on Severity 2026-10-04 00:03:23 +03:00
Ahmed Allam
65172fecd8 fix(tui): link every wrapped line of the viewer URL to the full URL
The sidebar wraps the viewer URL, and terminals that linkify by text only
pick up the first line, so the click opened the viewer with a truncated
token. Emit each wrapped line as an OSC 8 hyperlink to the whole URL.
2026-10-03 23:24:05 +03:00
Ahmed Allam
0107a15295 test: reject a leading heading in any finish_scan example field 2026-10-03 23:07:56 +03:00
Ahmed Allam
c0258b25fa fix(finish_scan): stop asking for a section heading in every report field
Every renderer of the final report already titles each section, so the
heading the docstring asked for printed twice. Describe the fields as
section bodies and drop the example headings.
2026-10-03 23:07:56 +03:00