Commit Graph
534 Commits
Author SHA1 Message Date
Ayush7614andAhmed Allam 86b6ff85ec Address Greptile review: GCP and Auth0 recon guidance
- Use curl instead of gsutil for anonymous GCS checks
- Document userinfo requires bearer access token
2026-07-10 08:15:22 -07:00
Ayush7614andAhmed Allam 2f466c2ebf Add GCP and Auth0 security skills
Expand cloud and technology coverage for GCP IAM/storage
and Auth0 tenant/API misconfiguration testing.
2026-07-10 08:15:22 -07:00
0xallamandAhmed Allam f0e8741705 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 f2b812a678 test(providers): cover wrapped bedrock import errors 2026-07-10 07:21:47 -07:00
Ousama Ben YounesandAhmed Allam dedfb36ff2 fix(providers): show vertex extra hint for wrapped import errors 2026-07-10 07:21:47 -07:00
770c7a2fe5 fix(tui): key render cache by content string and return copies
Co-Authored-By: Ahmed Allam <ahmed39652003@gmail.com>
2026-07-10 06:55:38 -07:00
Hardik-369andAhmed Allam 69df3b35d1 fix(tui): reduce scroll stutter by throttling UI refresh and caching renders
- Increased UI update interval from 350ms to 500ms
- Reduced dot animation frequency from 60ms to 250ms
- Reduced splash animation frequency from 50ms to 100ms
- Added content hash cache for rendered agent messages to avoid
  re-parsing markdown and re-running Pygments on every tick
- Added guard to prevent redundant scroll_end callbacks from queuing
  during rapid updates

Closes #581
2026-07-10 06:55:38 -07:00
alex sandGitHub f0475a8c38 fix(report): omit SARIF provenance for multiple repos (#726) 2026-07-10 09:41:18 -04:00
ed9bac8cb0 fix(ci): lower Linux release glibc baseline (#707)
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
Co-authored-by: Ahmed Allam <49919286+0xallam@users.noreply.github.com>
2026-07-10 06:13:14 -07:00
a2b6647008 fix(logging): keep verbose openai.agents DEBUG off sandbox stdout (#704)
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-07-10 06:00:40 -07:00
alex sandGitHub e6bcbb8326 fix(container): allow configured Caido UI domains (#723) 2026-07-10 00:38:29 -04:00
alex sandGitHub 4ebe7777c3 fix(session): use HTTPS scheme for Caido endpoint if TLS is enabled (#722) 2026-07-10 00:23:27 -04:00
seanturner83andGitHub 6a8ef475a4 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.
2026-07-10 00:13:35 -04:00
Rome ThorstensonandGitHub ee5f6014cf 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


* 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 5f2bd8ca03 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
seanturner83andGitHub 41f7432b4a 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).
2026-07-06 21:19:53 -04:00
Felix-AyushandGitHub 380ad991f5 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 397b33609b 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
Ahmed AllamandGitHub 2464a98925 Update README (#705) 2026-07-06 07:38:52 -07:00
Viper DroidandGitHub 8c1c9c14fd Add LLM Prompt Injection skill (vulnerabilities) (#616) 2026-07-06 03:52:24 -07:00
sean-kim05andGitHub c4a3b58af4 fix(tui): show 'more content available' for view_request over 15 lines (#687) 2026-07-06 03:50:02 -07:00
a93d9d5de7 feat(report): SARIF 2.1.0 emitter for CI / code-scanning integration (#626)
* feat(report): SARIF 2.1.0 emitter for CI / code-scanning integration

Strix emits CSV + markdown + JSON but no SARIF, so findings can't feed
GitHub code-scanning, an ASPM, or any SARIF-consuming CI gate. Add a
stdlib-only emitter (strix/report/sarif.py) and always write findings.sarif
from ReportState._save_artifacts, beside the existing artifacts.

Design invariants (learned from running this in production):
- Stable partialFingerprints.primaryLocationLineHash per finding, so a
  re-scan that re-words a title doesn't churn code-scanning alert IDs.
- Class/category hashing so the same vuln class maps to a stable ruleId
  across scans rather than drifting.
- Findings with no code location anchor to SECURITY.md with a synthetic
  location marker instead of being silently dropped.
- Always emit (even with zero findings) so a clean re-scan overwrites a
  stale findings.sarif and code-scanning auto-resolves fixed alerts.
- tool.driver.version reports the strix package version.
- Fully isolated in its own try/except: a SARIF build error must never
  break the CSV/MD/run-record path.

Verified end-to-end on v1.0.4 against a SQLi/cmd-inj/weak-hash fixture:
3 findings -> valid SARIF 2.1.0, 3 results, real code locations, distinct
per-finding fingerprints.


* fix(report): complete SARIF code scanning metadata

---------
Co-authored-by: bearsyankees <bearsyankees@gmail.com>
2026-07-03 10:43:31 -04:00
876f74153a Add five security skills: OAuth, AWS, prototype pollution, deserialization, Django (#617)
* Add five community security skills for agent specialization

Expand coverage with OAuth flow testing, AWS misconfigurations, prototype
pollution, insecure deserialization, and Django framework playbooks.

* Address Greptile review feedback on AWS and deserialization skills

- Use head-bucket for S3 existence checks instead of duplicating s3 ls
- Add Node.js to insecure_deserialization frontmatter description

* Clarify S3 existence vs public listing checks in aws skill

Split unauthenticated enumeration into separate head-bucket/HTTP
and s3 ls steps with interpretation guidance per review.

* some tools ads

---------

Co-authored-by: bearsyankees <bearsyankees@gmail.com>
2026-07-03 00:15:53 -04:00
Sonai BiswasandGitHub 3b023feaba fix: report cost for streamed OpenRouter calls (#634)
* fix: capture cost for streamed LiteLLM responses

* docs: note LiteLLM streaming metadata callbacks
2026-07-03 00:10:28 -04:00
Sadovoi GrigoriiandGitHub 77203c22e8 fix: avoid note ID collisions (#630) 2026-07-02 22:54:44 -04:00
7a98f32a8d fix grammer (#642)
Co-authored-by: Alex Schapiro <46074070+bearsyankees@users.noreply.github.com>
2026-07-02 22:47:02 -04:00
Alex Schapiro df995abf5e fix(report): correct csv_path indentation in write_vulnerabilities (#637)
Line 72 was over-indented, causing an IndentationError on import of strix/report/writer.py and breaking main. Also bump the mirrors-mypy pre-commit hook to v1.17.1 to avoid the mypy 1.16.0 internal crash (python/mypy#19412) on openai/_client.py.
2026-07-02 15:27:24 -04:00
ASTITVA BHARDWAJandGitHub 8bc6ee9d62 Fix non-atomic CSV and MD writes to prevent corruption on crash (#628) (#631) 2026-07-02 07:53:30 -07:00
Rome ThorstensonandGitHub 47d70ed38d test: add unit tests for config loader (strix/config/loader.py) (#596) 2026-06-30 04:31:29 -07:00
Dominic WhiteandGitHub b26902f553 Remove collection of unhandled exception error messages from telemetry (#585) 2026-06-29 19:22:06 -07:00
Ahmed AllamandGitHub ba2ccc1507 chore(deps): refresh uv.lock to latest compatible versions (#606) 2026-06-29 19:10:18 -07:00
Ahmed AllamandGitHub 71d3861769 Update readme (#607) 2026-06-29 19:09:58 -07:00
Ahmed AllamandGitHub e9445535fd Readme update 2026-06-29 19:00:46 -07:00
Rome ThorstensonandGitHub b0a5e31a03 fix: stop gracefully with resume hint on persistent RateLimitError (#261) (#593) 2026-06-29 07:31:54 -07:00
Rome ThorstensonandGitHub 6c63051f11 fix(core): collapse child agent initial input into a single user message (#589) 2026-06-29 06:51:47 -07:00
Mads HvelplundandGitHub c15416a3b9 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
Mads HvelplundandGitHub 55fcee29aa Add configurable token / cost usage limits (#576)
* 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

* feat(cli): add --max-budget-usd flag

Raises BudgetExceededError in ReportUsageHooks after each LLM call when
accumulated cost reaches the limit, with clean "stopped" status and
child-agent cancellation in non-interactive mode.

* test: add budget enforcement unit tests

7 tests covering no-budget, under-budget, at-limit, over-limit, error
message content, None report state, and exception hierarchy.
Also adds pytest/pytest-asyncio to dev deps and a mypy override for tests.

* fix(budget): validate positive budget and check the live cost ledger

Two hardening fixes for --max-budget-usd enforcement:

- Reject non-positive budgets. ReportUsageHooks now raises ValueError for
  max_budget_usd <= 0, and the CLI validates the flag via a custom argparse
  type so '--max-budget-usd 0' fails fast with a friendly message instead of
  silently killing the scan on the first model response.
- Read the live cost. The budget check now reads ReportState.get_total_llm_cost()
  (the live ledger) instead of the persisted run-record snapshot, so it stays
  accurate even when a usage save fails after a model call.

* fix(budget): stop the entire scan deterministically when the limit is hit

Previously a BudgetExceededError was handled per-agent: it was swallowed in
interactive mode (the loop kept waiting), a child's error escaped its detached
task as an unretrieved-exception warning, the parent was never released from
wait_for_message, and the stop was logged at ERROR with a traceback as if the
agent had failed.

Replace that with a single scan-wide signal on the coordinator:

- AgentCoordinator.trigger_budget_stop() sets a flag and wakes every parked
  agent; wait_for_message returns as soon as the flag is set.
- The run loops check coordinator.budget_stopped and raise to exit cleanly,
  marking themselves 'stopped'. The root's exception reaches run_strix_scan's
  handler, which cancels descendants and tears the scan down once; child
  exceptions are swallowed in their detached task.
- The budget stop is logged at INFO, not as a failure.

This is deterministic regardless of tree depth or which agent first sees the
limit, fixing the interactive/TUI hang where a deep agent's stop never reached
a parked root. Also re-raises BudgetExceededError explicitly in the stream
handler so it can't be mistaken for the LiteLLM 'after shutdown' race.

* fix(budget): treat a budget stop as a clean stop in the TUI

Add an explicit BudgetExceededError handler in the TUI scan thread so that, if
the error ever reaches it, the budget stop is logged as a graceful stop rather
than surfaced as a red scan error by the broad 'except Exception'. The runner
normally absorbs the error and returns cleanly, so this is defensive depth for
a money-spending feature.

* docs(cli): document --max-budget-usd behavior and limitations

Clarify that the budget is cumulative across all agents, checked after each
model response, that the scan stops cleanly (not as a failure), that the value
must be > 0, and that spend can slightly overshoot due to in-flight calls and
best-effort cost estimation.

* Apply suggestions from code review


---------
2026-06-22 11:17:08 -04:00
cb4ee13a31 fix: route ollama models through ollama_chat so tool calling works (#562)
Co-authored-by: 0xallam <ahmed39652003@gmail.com>
2026-06-15 17:39:21 -07:00
Ahmed AllamandGitHub 39db242fc8 Bump 1.0.3 -> 1.0.4 (#557) 2026-06-09 09:41:44 -07:00
Ahmed AllamandGitHub 99864c39c1 Strip ANSI escapes and control bytes from terminal tool output (#554) 2026-06-09 09:22:50 -07:00
Ahmed AllamandGitHub 03448f78bb Strip all images from session on vision-rejection, not just the latest (#553) 2026-06-09 02:48:30 -07:00
Ahmed AllamandGitHub 053ddfee27 Swallow sandbox container races in the stream consumer (#552) 2026-06-09 01:46:23 -07:00
Ahmed AllamandGitHub 9fb44751c8 Make TUI quit instant by SIGKILL-ing the sandbox container (#548) 2026-06-08 23:40:45 -07:00
Ahmed AllamandGitHub de81ce911f Bump 1.0.2 -> 1.0.3 (#537) 2026-06-08 18:05:02 -07:00
Ahmed AllamandGitHub 438162fb53 Simplify cost ledger to one bucket (#531) 2026-06-08 15:56:28 -07:00
Ahmed AllamandGitHub 746719de7f Use observed LiteLLM cost for LiteLLM-routed calls (#529)
Register a litellm.success_callback that captures kwargs['response_cost']
into a new observed-cost bucket on LLMUsageLedger. record() skips the
tokens-times-registry estimate for LiteLLM-routed models so we do not
double-count with the callback; OpenAI direct routes keep estimating
since LiteLLM is not invoked for them. Per-agent attribution for
LiteLLM-routed calls is apportioned by token share at to_record() time.
2026-06-08 15:01:48 -07:00
Ahmed AllamandGitHub 43f147178f Gate Reasoning(effort=...) on registry support (#528)
OpenAI's Responses API rejects reasoning.effort on non-reasoning
models like gpt-4o with `unsupported_parameter`, so any scan with
the default STRIX_REASONING_EFFORT=high against gpt-4o crashed at
the first model call. drop_params=True absorbs the rejected param
on LiteLLM-routed models but the SDK's native OpenAI path has no
equivalent.

Lift model_supports_reasoning to a public helper that strips
litellm/, any-llm/, openai/ prefixes and falls back to last-segment
lookup so prefixed forms like anthropic/claude-opus-4-7 resolve
through the bare model_cost entry. make_model_settings regains
model_name and skips Reasoning() when the registry doesn't confirm
support. uses_chat_completions_tool_schema reuses the same helper
(was duplicating the lookup under a misleading name).
2026-06-08 13:18:07 -07:00
Ahmed AllamandGitHub 24bdb33623 Show "Send message to resume" on the left of the status bar (#525) 2026-06-07 17:41:06 -07:00
0xallamandAhmed Allam 563f87ce25 Use function-tool schema for non-reasoning OpenAI models
OpenAI's Responses API rejects tools[i].type="custom" on non-reasoning
models like gpt-4o (400 with code=unknown_parameter, param=tools).
Strix's SDK-native Filesystem capability registers CustomTool entries
by default, so a bare STRIX_LLM=gpt-4o run failed at the first tool
invocation even though warm-up (a tool-less call) succeeded.

uses_chat_completions_tool_schema now consults
litellm.model_cost[<name>].supports_reasoning for OpenAI routes and
flips to the chat-completions function-tool schema for models that
don't carry the reasoning flag. Same registry-lookup pattern as
is_known_openai_bare_model. Non-OpenAI prefixes and configs with
LLM_API_BASE are unchanged (still function tools).
2026-06-07 17:36:19 -07:00
0xallamandAhmed Allam 53a95ca724 Bump litellm 1.83.7 -> 1.88.0 2026-06-07 17:36:19 -07:00