Commit Graph
87 Commits
Author SHA1 Message Date
Ahmed AllamandAhmed Allam 6bda366065 fix(context): bound native filesystem tool output in Responses mode
Chat-completions mode converts filesystem CustomTools to FunctionTools
(which bounds their result), but the Responses-API path kept them native
and unbounded, so a large read_file could still exhaust the context
window. Always configure the Filesystem capability to head+tail bound
tool output in both modes.
2026-07-26 14:38:12 -07:00
Ahmed AllamandAhmed Allam 1f36f5d401 fix(context): clamp shell output cap and count byte-trimmed dropped lines
Treat tool_output_max_tokens as a ceiling so an explicit model-supplied
cap can't exceed it, and derive the truncation notice's dropped-line
count from the lines actually kept after the byte-trim pass. Also cast
the pygments fallback lexer so it satisfies the resolve_lexer return
type under the pre-commit mypy hook.
2026-07-26 14:38:12 -07:00
Ahmed AllamandAhmed Allam a70a87f272 feat(context): bound per-tool output before it enters agent history
Cap the size of every tool result so a single verbose command (recursive
find, noisy scanner, full page dump) can't pin the conversation near the
model's context window for the rest of a scan.

- New ContextSettings config group with env-tunable caps.
- Default the SDK shell tools' max_output_tokens so exec_command /
  write_stdin truncate head+tail instead of returning unbounded output.
- Bound Strix's own FunctionTool/CustomTool results (line + UTF-8 byte
  head+tail preview with a truncation notice) and cap error strings.
2026-07-26 14:38:12 -07:00
devin-ai-integration[bot]andGitHub d2fbcb726d feat(reporting): add read-only list_reports + get_report tools (#889) 2026-07-26 14:05:53 -07:00
Ahmed AllamandAhmed Allam d1e8225d5f refactor: move strix/viewer under strix/interface 2026-07-26 13:11:14 -07:00
Ahmed AllamandAhmed Allam 8157ccba27 refactor(reports): fold fence helpers into report writer 2026-07-25 13:09:57 -07:00
Ahmed AllamandAhmed Allam 21243486e2 fix(reports): safe-fence markdown PoC export and share fence helpers 2026-07-25 13:09:57 -07:00
Ahmed AllamandAhmed Allam 97ed7e79a1 fix(reports): auto-detect PoC language with Python fallback 2026-07-25 13:09:57 -07:00
Ahmed AllamandAhmed Allam 31c18f8f75 fix(reports): strip markdown code fence from poc_script_code before rendering 2026-07-25 13:09:57 -07:00
08126eb518 feat(dedupe): add dedicated deduplication model (#823)
Co-authored-by: oyasumi <oyasumi@kantilabs.xyz>
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-07-25 06:29:39 -07:00
Utku TugrulandGitHub d4f4697533 runtime: resolve staged local-dir path to avoid symlink rejection on macOS (#857) 2026-07-25 05:45:31 -07:00
cd8270c98b Sign in with a ChatGPT subscription for inference (#854)
Co-authored-by: Jonathan Singer <jonathansinger@Jonathans-MacBook-Pro.local>
Co-authored-by: Jonathan Singer <jonathansinger@Mac-3004.lan>
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-07-24 15:41:19 -07:00
alex sandGitHub d1a73a24f8 feat(cli): update notifications + self-update (strix --update) (#807)
* feat(cli): update notifications + self-update (strix --update)

* fix(update): verify release checksum, clean up staged binary, roll back Windows rename on failure

* feat(update): 3-way pre-scan prompt (update now / not now / skip this version) + package-manager upgrade

* fix(update): never show update prompt/notice in non-interactive runs
2026-07-22 16:29:03 -04:00
Ahmed AllamandGitHub 1f7373714b Local viewer: prominent scan switcher + rename to "pentest" terminology (#848) 2026-07-22 09:17:52 -07:00
yoni-at-strixandGitHub f600f99103 Local run viewer: email reports, run history, and the platform suite (#813) 2026-07-21 08:13:03 -07:00
f967e6017b fix(report): prevent code-fence breakout in vulnerability markdown (#817)
* fix(report): prevent code-fence breakout in vulnerability markdown

render_vulnerability_md wrapped LLM-authored poc_script_code and code
snippet values in a fixed three-backtick fence, so a triple-backtick inside
the value closed the fence early and the rest rendered as live markdown
(headings, tracking-beacon images) in the shareable report deliverable.

Open each such block with a fence one backtick longer than the longest
backtick run in the payload (CommonMark: a block closes only on a fence at
least as long as the opener), so the content always renders verbatim. The
adjacent ```diff block is already safe (its lines are '- '/'+ ' prefixed and
so can never be a bare-backtick closing fence) and is left unchanged.

Fixes #815

* fix(report): indent multiline snippets

---------

Co-authored-by: thejesh23 <thejesh23@users.noreply.github.com>
Co-authored-by: Alex Schapiro <bearsyankees@gmail.com>
2026-07-20 22:07:44 -04:00
alex sandGitHub f9890a672d strip transfer encoding (#820)
* test(proxy): drop transfer encoding on replay

* test(proxy): drop transfer encoding on replay
2026-07-20 21:56:34 -04:00
599f7c7526 fix(proxy): recompute Content-Length when replaying a modified body (#816)
build_raw_request kept the Content-Length inherited from the captured
request, so replaying a modified body (repeat_request) emitted a request
whose declared length did not match the body — truncating the payload or
stalling the target. Drop any inherited Content-Length (case-insensitively)
and recompute it from the body actually being sent.

Adds tests covering a lengthened body, an emptied body, and the
no-inherited-header path.

Fixes #814

Co-authored-by: thejesh23 <thejesh23@users.noreply.github.com>
2026-07-20 21:43:49 -04:00
Ahmed AllamandAhmed Allam 7d5a67d234 chore(llm): shorten timeout helper docstring; update tests 2026-07-17 19:45:32 -07:00
Ahmed AllamandAhmed Allam 88ad3e4472 fix(llm): use a JSON-serializable per-turn model timeout
An httpx.Timeout in ModelSettings.extra_args crashes
ModelSettings.to_json_dict() (PydanticSerializationError) on the Chat
Completions and LiteLLM model paths, which serialize settings for their
tracing generation span — failing every model turn on those paths. Pass
the timeout as a plain float, which httpx-based clients apply as the
read (inactivity) timeout.
2026-07-17 19:45:32 -07:00
Ahmed AllamandAhmed Allam cf7689e927 fix(llm): use httpx.Timeout read-inactivity for per-turn model timeout 2026-07-17 18:40:23 -07:00
Ahmed AllamandAhmed Allam 3bb95ab43d fix(llm): add per-turn model request timeout so stalled streams fail fast and retry 2026-07-17 18:40:23 -07:00
Ahmed AllamandAhmed Allam b9c2592b53 fix(llm): retry statusless mid-stream provider errors (quota/billing)
The SDK's http_status retry policy only retries errors carrying a known
HTTP status code, but quota/billing (and other provider-side) failures
often surface inside a streamed response as a bare error with no status
code, so they were failing on the first attempt. Add a statusless retry
policy to DEFAULT_MODEL_RETRY so they are retried (before any content is
streamed; user aborts are never retried), restoring the pre-SDK engine's
resilience. If the provider is genuinely exhausted, the error still
propagates and fails the scan after retries.
2026-07-17 16:47:14 -07:00
devin-ai-integration[bot]andGitHub f54ecb74f9 fix(report): restore cost tracking for OpenRouter and other LiteLLM-routed models (#801) 2026-07-17 13:38:23 -07:00
96ca7e544d revert(proxy): drop overfit Caido reconnect/HTTPQL band-aids, keep serialization lock (#799)
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-07-17 13:18:40 -07:00
e4548cb28c fix(proxy,tooling): serialize+reconnect Caido client, actionable HTTPQL errors, sandbox tool guidance (#794)
* fix(proxy,tooling): serialize+reconnect Caido client, actionable HTTPQL errors, sandbox tool guidance

Addresses the top recurring agent tool-call failures observed in telemetry:

- proxy: the shared Caido client had no locking or reconnect, so concurrent
  agent calls raced ("Transport is already connected") and a dead transport
  poisoned the rest of the run ("Connector is closed"/"Server disconnected").
  Add an asyncio lock + bounded reconnect in caido_api.call_with_client (sandbox
  path) and a scan-wide caido_lock in the run context that host-side proxy tools
  hold around every call. Deterministic errors are not retried.
- proxy: list_requests now returns Caido's exact parser message, echoes the
  offending query, and includes a corrected-syntax hint so agents self-correct
  instead of retrying a broken HTTPQL filter.
- shell/prompt: document that write_stdin requires a process started with
  tty=true; nudge toward writing Python to a file over deeply-nested one-liners;
  note the venv pre-installs common libs.
- agent-browser: distinguish daemon/connection failures (run doctor, don't loop)
  from malformed commands; invoke directly (no sh -c wrapper).
- containers: use POSIX '.' instead of the bashism 'source' in generated rc
  files (fixes 'sh: source: not found'); add file + xxd and pre-install
  requests/httpx/beautifulsoup4/lxml/pyjwt/cryptography in the sandbox venv.
- tests: cover proxy serialization/reconnect/no-retry and HTTPQL errors.

* fix(proxy): host-side reconnect, close stale clients, don't retry mutations

Addresses Greptile review on the reconnect logic:

- Host path had no reconnect: a dead shared context client (Caido restart /
  network blip) previously disabled proxy tools for the rest of the scan. Add
  SharedCaidoClient, a serialized reconnect-safe holder stored once per scan in
  the run context and shared across agents. On a dead transport it rebuilds via
  reconnect_caido, which re-selects the SAME Caido project (preserving captured
  traffic) instead of creating a new empty one.
- Don't repeat completed mutations: call_with_client / SharedCaidoClient.call
  take idempotent=. Reads retry once on reconnect; replay + scope
  create/update/delete heal the client but re-raise instead of risking a
  double-apply.
- Don't leak replaced clients: the stale client is aclose()d (best-effort) on
  every reconnect.
- Extend tests to cover close-on-reconnect, non-idempotent re-raise, and the
  SharedCaidoClient holder.

* fix(proxy): close replacement Caido client when project.select fails

Addresses Greptile P1: in reconnect_caido (and bootstrap_caido) a successful
connect() followed by a failing project.select()/create() discarded the
connected client without closing it, so a missing/unavailable project could
leak a transport on every retry. Close the client before re-raising.

---------

Co-authored-by: Alex Schapiro <bearsyankees@gmail.com>
2026-07-17 13:31:57 -04:00
Devin AIandAhmed Allam 38c2936f69 Revert "fix(runtime): retry transient sandbox startup failures (#768)"
This reverts commit 40f4e67320.
2026-07-16 04:09:08 -07:00
devin-ai-integration[bot]andGitHub 899e07d3a2 fix(core): bound per-agent image memory (proactive budget + inherited-context scrub) (#779) 2026-07-15 18:13:42 -07:00
alex sandGitHub 40f4e67320 fix(runtime): retry transient sandbox startup failures (#768)
* fix(runtime): retry transient sandbox startup failures

* fix(runtime): fail closed when sandbox teardown fails
2026-07-14 23:27:06 -04:00
alex sandGitHub d44ca88a18 fix(runtime): stage symlink-safe copies for LocalDir uploads (#766)
The sandbox SDK's LocalDir walker rejects any symlink outright
(LocalDirReadError, reason=symlink_not_supported), so uploading a cloned
repository that commits symlinks (common in JS/TS monorepos) aborts before
the agent starts. Stage such trees into a temp copy first: in-tree links
are dereferenced; out-of-tree, dangling, and cyclic links are dropped and
never followed, preserving the walker's path-escape safety. Symlink-free
trees are uploaded as-is.
2026-07-14 17:40:23 -04:00
e69c8f6633 Default sandbox exec commands to Bash (#764)
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-07-14 03:44:05 -07:00
b959d528a2 Warn when configured LLM is not frontier-recommended (#586)
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-07-13 17:41:44 -07:00
a87bfb4881 fix(reporting): require advisory_cvss for dependency findings + add SCA TUI renderer (#753)
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-07-12 17:31:49 -07:00
alex sandGitHub 4537f33f11 Add dependency reporting fields (#751) 2026-07-12 15:30:33 -04:00
alex sandGitHub a5f28c6b4b Add root scan prompt options (#750) 2026-07-12 12:31:15 -04:00
alex sandGitHub 4b46a748e4 Add skill directory registration (#746) 2026-07-12 12:05:58 -04:00
alex sandGitHub 205e0b3707 Allow scan agent tool registration (#733) 2026-07-11 23:58:51 -04:00
alex sandGitHub c13960ae01 Support routed OpenAI required tool choice (#732) 2026-07-10 18:43:07 -04:00
alex sandGitHub 22d327d21f feat(settings): add force_required_tool_choice to LlmSettings (#730)
feat(inputs): implement logic for required tool choice based on model

test(inputs): add tests for force_required_tool_choice behavior

test(runner): update tests to include force_required_tool_choice in settings
2026-07-10 18:36:33 -04:00
882664f70b fix(providers): match google submodule imports and walk full exception chain
Co-Authored-By: Ahmed Allam <ahmed39652003@gmail.com>
2026-07-10 07:21:47 -07:00
Ousama Ben YounesandAhmed Allam e1abac0f0f test(providers): cover wrapped bedrock import errors 2026-07-10 07:21:47 -07:00
Ousama Ben YounesandAhmed Allam df4bfafcd3 fix(providers): show vertex extra hint for wrapped import errors 2026-07-10 07:21:47 -07:00
alex sandGitHub 9f6d0b106b fix(report): omit SARIF provenance for multiple repos (#726) 2026-07-10 09:41:18 -04:00
0fb005c73f fix(runtime): swallow torn-down docker socket in sandbox delete() (#721)
StrixDockerSandboxClient.delete() best-effort-kills the sandbox container via
containers.get(id).kill() before delegating to the SDK's delete(), suppressing
docker NotFound/APIError. But when the docker daemon socket is already going
away — the normal case on a host/CI teardown — containers.get() ->
inspect_container raises requests' ConnectionError, which is a *sibling* of
docker.errors.APIError under requests.RequestException, not a subclass. So it
escapes the APIError-only suppress and surfaces a full traceback on teardown
even though the kill is meant to be best-effort.

Add RequestException to the suppress so the best-effort kill is genuinely
best-effort regardless of daemon reachability.

Test: tests/test_docker_client_delete.py — the kill raising ConnectionError
(and NotFound/APIError) is swallowed and delete() still delegates; unrelated
errors still propagate; no-container_id is a no-op. The ConnectionError case
fails against the pre-fix APIError-only suppress.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 00:13:35 -04:00
Rome ThorstensonandGitHub e1940769de fix(providers): declare bedrock + vertex extras and add provider import-error hints (#588)
* feat: add bedrock + vertex optional extras with install docs and import hints (#574)

Declare [project.optional-dependencies] with vertex (google-auth) and
bedrock (boto3) extras so "strix-agent[vertex]" / "strix-agent[bedrock]"
install the provider SDKs. Add an Installation section to the Bedrock docs
mirroring Vertex, and a _provider_import_hint helper in warm_up_llm that
surfaces a pip-install hint when a provider dependency is missing.

Fixes #574, #573

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(providers): use pipx in install hint to match docs

A pipx-installed strix can't add an extra with 'pip install' (wrong env);
mirror the documented 'pipx install "strix-agent[...]"' command. Addresses
Greptile review.
2026-07-07 10:24:49 -04:00
alex sandGitHub 9f278b9a5c 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
375fc9c3d0 feat(report): tag SARIF rules with STRIDE legs derived from CWE (#708)
Builds on the SARIF 2.1.0 emitter (#626): give each SARIF rule one or more
`stride:<leg>` tags (Spoofing / Tampering / Repudiation / Information
disclosure / Denial of service / Elevation of privilege) derived from the
finding's CWE, so consumers — the GitHub code-scanning Security tab, ASPM
dashboards, coverage reports — can group and filter findings by
threat-model leg. SARIF results inherit their rule's tags via ruleId, so
tagging the rule is sufficient.

- _CWE_TO_STRIDE maps common CWEs to legs (dominant leg first where a CWE
  spans several); unmapped / no-CWE findings fall back to a default
  (tampering + information-disclosure) so every finding carries >=1 leg
  and downstream reports have no coverage gaps.
- Includes mappings for CWEs surfaced by real scans: 798 (hardcoded
  creds), 862 (missing authz), 259 (hardcoded password), 1391 (weak
  credential).

Tests: tests/report/test_sarif_stride.py (14 cases — mapping, normalization
of CWE-306/306/"cwe: 306" forms, default fallback, rule-tag emission).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-06 21:19:53 -04:00
Felix-AyushandGitHub 754508c70b test: add report writer artifact tests (#667)
Cover run record I/O, vulnerability markdown rendering,
CSV severity ordering, and executive report output.
2026-07-06 11:45:29 -04:00
sean-kim05andGitHub a5112f9433 fix(config): make env vars win over persisted JSON across all aliases (#689)
_read_json_overrides is documented to let env vars outrank the
persisted cli-config.json, but it decided per-alias and broke on the
first alias found in either env or the file. When a multi-alias field
(e.g. api_key via LLM_API_KEY/OPENAI_API_KEY) was set in the env under
one alias but stored in the file under another, the stale file value
was surfaced as an init kwarg and overrode the live env var. A
lowercase env var was also missed (settings use case_sensitive=False).

Decide whether a field is already set in the environment by checking
all of its aliases case-insensitively before consulting the file. Add
regression tests for the cross-alias and case-insensitive cases.

Closes #688
2026-07-06 11:36:41 -04:00
sean-kim05andGitHub aec5f14455 fix(tui): show 'more content available' for view_request over 15 lines (#687) 2026-07-06 03:50:02 -07:00