Commit Graph
142 Commits
Author SHA1 Message Date
oyasumiandClaude Opus 5 dad35b9e5f fix(safety): do not treat data tools reading script-named files as execution
Trace review of two guarded-mode runs found the unresolved-execution guard
firing on ordinary commands: curl fetching a .js asset, rg over a .py file, sed
and cat and cp on script-named files — 24 blocks in one run. The guard was meant
to fail closed on an unknown interpreter handed a script, but a read, transfer,
or text tool takes such a file as data, not as a program to run.

Exclude known read commands, HTTP clients, and a set of text/data tools from the
script-suffix branch, so only a genuinely unknown executable given a script still
fails closed. awk moves from the interpreter set to the data tools: its program
is an inline positional argument, not a -c or script file the entrypoint reader
can resolve.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 17:32:09 +00:00
oyasumiandClaude Opus 5 57149b51e3 feat(safety): attach input-redirect data files, and scope subdomains
Two guarded-mode false-positives from a recon run.

A command that reads a workspace data file — `while read host; do dig "$host";
done < hosts_passive.txt` — reached the reviewer with an empty artifact list,
because the evidence compiler only collects script entrypoints and their Python
imports, never a data file consumed via input redirection. The reviewer, asked
whether the queried hosts were in scope, had no way to see them and fail-closed
on unresolved scope. Parse single `<` input redirections (not `<<` heredocs or
`<(` process substitution) and attach each workspace-resident file as an
artifact with role "input", bounded by max_artifact_bytes and flagged when
truncated. Files outside /workspace are not read.

Separately, the reviewer treated scope as the exact authorized host, so it
blocked resolving admin.fiuu.com under an authorized fiuu.com. State in the
prompt that an authorized domain covers its subdomains, and point the reviewer
at the new role "input" artifacts for scope checks.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 06:09:05 +00:00
oyasumiandClaude Opus 5 a7336fa194 fix(safety): judge in-scope testing by effect, and stop the shell:bash misread
Two guarded-mode false-positives surfaced in real scan traces.

The reviewer blocked a boolean SQL injection probe
(`curl "…/login?username='+OR+'1'='1"`) for being an injection attempt at all,
though it is a read-only GET that changes nothing. The prompt said "allow only
non-destructive" but never established that in-scope offensive testing is the
tool's authorized purpose, so the model blocked on the technique. Rewrite the
guarded-mode guidance to judge by effect: in-scope injection probes, recon,
enumeration, and fuzzing pass, while destructive or persistent effects block —
with SQL spelled out (boolean/UNION/time-based read probes pass; DROP, DELETE,
INSERT, INTO OUTFILE, stacked statements, and command execution block).
Ambiguous evidence still fails closed, and every deterministic block, the
completeness gate, observe's passive-only rule, and scope enforcement are kept.

Separately the reviewer blocked a plain `curl` as "use of bash shell within a
curl command". The shell wrapper stamps `shell: bash` onto every exec_command
for execution, and the evidence packet passed that transport default straight
to the reviewer, which read it as the agent invoking a shell. Strip the
harness-injected transport keys (`shell`, `max_output_tokens`) from the packet's
original_arguments; the command itself is still parsed from `cmd`, so an
agent-authored `bash -c` payload is unaffected.

Note: the effect-based prompt also lets in-scope recon tools (nmap, subfinder,
ffuf, katana) through, which the old prompt blocked as "scanning" or "high
volume". That follows directly from judging by effect rather than technique.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 01:22:03 +00:00
oyasumiandClaude Opus 5 bf475fbf46 test(tui): match the de-branded lifecycle nudge
77c7b0d changed the message to "the autonomous run" in both execution.py and
live_view.py but left this case asserting the older wording, so the classifier
test has been failing on main since that commit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 00:56:18 +00:00
oyasumiandClaude Opus 5 c5fca380ef fix(safety): close three evidence bypasses and make workspace staging idempotent
Grouped browser verbs were classified by their verb alone. `tab` and `session`
sit in the passive set, so `tab new <url>` — documented as navigating — and
`session clear` earned a deterministic allow and executed unreviewed in guarded
mode and unblocked in observe, while `open <url>`, the same navigation, was
reviewed. Passivity is now decided from verb plus subcommand, and the packet
carries the result so observe mode stops maintaining a second copy of the rule
that could drift more permissive than guarded. The blocked-action list still
matches on the bare verb, so `auth login` keeps matching `auth`.

Interpreters were a seven-name allowlist, so `python3.12`, `/usr/bin/python3`,
`php`, and `deno` set no script path and produced a packet with no artifacts
that was still stamped complete — the exact shape the reviewer is told it may
allow. Recognize versioned and common interpreters so their sources are
actually collected, and fail closed when a command runs code that cannot be
resolved to an inspectable script.

`from pkg import payload` collected only the package initializer, because an
imported name was treated as an attribute and never as a submodule. Effectful
code in `pkg/payload.py` executed without appearing in the evidence.

Workspace staging runs twice per run and was not idempotent: the second pass
read the origin from `source_path`, which the first pass had already rewritten
to the copy. With the completion marker absent it cleared the destination and
then copied from that same emptied directory, silently handing the agent an
empty workspace. The origin is now read back from `original_source_path`.

Each fix is covered by a test that fails when the fix is reverted.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 00:47:21 +00:00
oyasumiandClaude Opus 5 d45b99e551 fix(safety): gate browser safety guidance on the active mode, and close test gaps
The `agent_browser` skill is always loaded, so its safety paragraph shipped to
`off`-mode agents. Its prohibitions do not hold there — Strix only assigns a
browser session in a safety mode, while multi-session browsing is a normal
documented workflow — so the paragraph misdescribed the tools those agents
have. Move it into the already mode-gated block in the system prompt, and pin
the gating in both directions.

Test changes:

- `test_observe_mode_blocks_browser_click` asserted nothing about observe mode.
  The same call blocks in guarded for a different reason (no prior snapshot),
  so the observe rule was never reached. Give it a snapshot and assert the
  block's source and category, plus the passive-read inverse.
- Neither workspace-epoch bump was pinned; removing either left the suite
  green. Both are now covered, along with the read-only case that must not
  bump, and an end-to-end pairing where a patch during review invalidates a
  script decision.
- Cover `invoke_mutating_tool`'s observe-block and off-mode paths, the
  reviewer's low-confidence, block, missing-model and failed-inspection rules,
  the inline `bash -c` source path, and the two dependency-budget guards.
- Assert browser sessions are disjoint across agents rather than freezing one
  agent's command string.
- Fold the compound-separator and safety-config tests into the parametrized
  cases that already covered them.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 00:47:21 +00:00
oyasumiandClaude Opus 5 6e5bb2e76e feat(safety): add contextual action review with guarded and observe modes
Introduce a pre-execution safety layer that reviews effectful agent actions
against compiled, frozen evidence before they run.

`--safety-mode guarded` allows non-destructive interaction after review;
`--safety-mode observe` permits passive target interaction only. `off` stays
the default, so existing runs are unchanged.

Deterministic rules decide what they can on their own: destructive commands,
code-loading environment overrides, blocked browser actions, and mutating
requests in observe mode are refused without a model call, and a small set of
read-only commands is allowed outright. Everything else compiles an evidence
packet — command, scope, script source and its local import closure, prior
tool-call evidence, and browser snapshot context — for a bounded reviewer that
may make one isolated inspection call. Incomplete evidence fails closed.

In safety modes, user-owned local directories are copied into the run
directory so the originals are never mounted writable, while `.git`,
`.agents`, and `.codex` inside the copy stay read-only.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 00:47:21 +00:00
alex s 9dae76667b expand firebase storage rules coverage (#1002) 2026-08-06 23:22:06 -07:00
Ahmed Allam b69af37cb2 feat(report): keep dependency findings from distinct manifests separate in dedupe 2026-08-06 02:20:46 +03:00
Ahmed Allam 72cb15a20a feat(reporting): require repo-relative manifest_path on dependency CVE findings 2026-08-06 02:20:46 +03:00
Alex Schapiro 97336d53e4 feat(reporting): structured reachability evidence ladder for dependency CVE findings 2026-08-06 00:25:08 +03:00
devin-ai-integration[bot]andAhmed Allam 0abe82d622 fix(agents): collapse repeated waits queued inside one model turn (#979)
* fix(agents): collapse repeated waits queued inside one model turn

* fix(agents): state that one wait is enough in every prompt variant

---------

Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-08-06 00:07:30 +03:00
devin-ai-integration[bot]andAhmed Allam 6735a6f89e fix(llm): abandon a model stream that stops producing events (#978)
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-08-06 00:07:14 +03:00
devin-ai-integration[bot]andAhmed Allam 8bd6c8e87a fix(llm): cap the tool calls one assistant response may queue (#977)
* fix(llm): cap the tool calls one assistant response may queue

* fix(llm): cap the subscription backend's responses too

---------

Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-08-06 00:06:59 +03:00
devin-ai-integration[bot]andAhmed Allam 68ea6fca65 fix(llm): keep tool-call ids unique so a recycled id can't erase history (#976)
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-08-06 00:06:46 +03:00
devin-ai-integration[bot]andAhmed Allam 657aa5cbe6 feat(reporting): record transitive dependency chain on SCA findings (#971)
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-08-04 12:34:52 -07:00
Anurag Mewar 6719a70611 feat: support API specs and Postman collections as targets (#866) 2026-08-03 21:07:44 -07:00
Ahmed Allam 3bcf3778f0 fix(core): settle a non-interactive agent's status before its exception unwinds
An exception escaping a non-interactive cycle re-raised before the status
handling, so a dying child stayed 'running' and its parent waited out the
timeout on a completion report the child could no longer send. Set the
terminal status and wake the parent on the way out too.
2026-08-04 06:14:54 +03:00
Ahmed Allam 4a455b1e62 fix(core): recover from hallucinated tool names instead of ending the scan
A tool call for a name Strix does not register raised ModelBehaviorError
from the SDK turn resolver, which nothing retries: the root agent's raise
tore down the whole scan and a sub-agent died before its status was set.
Opt into the SDK's tool_not_found_behavior="return_error_to_model" so the
unknown call comes back as a tool result and the agent self-corrects.

The setting landed in openai-agents 0.19.0, which requires openai>=2.45,
so both pins move.
2026-08-04 06:14:54 +03:00
Tech GuyandAhmed Allam 23f1d76d4c Create credential files with owner-only permissions (#945)
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-08-03 19:36:59 -07:00
oyasumi 5bb9fe896b feat(tui): replace Textual with a Go/Bubble Tea interface (#941) 2026-08-03 19:23:07 -07:00
bearsyankees a51ca18666 fix: calibrate vulnerability severity to demonstrated impact 2026-08-03 23:40:32 +03:00
devin-ai-integration[bot]andAhmed Allam dbc427d816 feat(runtime): mount local targets instead of copying them in (#958)
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-08-02 07:45:10 -07:00
Ahmed Allam b6cf156e95 fix(tools): tell a waiting parent when stop_agent stops its child 2026-08-02 15:43:43 +03:00
Ahmed Allam 002712284a fix(core): wake the parent when a child ends without a completion report 2026-08-02 15:43:43 +03:00
devin-ai-integration[bot]andAhmed Allam c240068c2c fix(tools): accept both the string and structured form of every tool argument (#957)
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-08-01 18:53:24 -07:00
devin-ai-integration[bot]andAhmed Allam 2e7040240d feat(config): accept STRIX_REASONING_EFFORT=max for providers that support it (#956)
Co-authored-by: Ahmed Allam <allam@usestrix.com>
2026-08-01 17:10:01 -07:00
Ahmed Allam 1c1fa49961 refactor(tools): split wait_for_message into respond_to_user + wait_for_agents
One tool was doing three jobs (wait on the user, wait on other agents, and
- wrongly - wait for a long-running command), so the driver had to guess which
one an agent meant and used parent_id as the proxy: the root waits for a human,
everyone else waits for agents. That proxy is wrong, since the user can message
any agent from the TUI's agent tree.

Tool identity now carries the intent, and the coordinator records it as a
wait_kind that survives snapshot/restore:

  respond_to_user  -> wait_kind="user",   never auto-resumed (root or not)
  wait_for_agents  -> wait_kind="agents", auto-resumed on a 300s timer
  recovery exhaust -> wait_kind="stalled"

respond_to_user fuses the message and the yield into one call, so there is no
way to answer and then forget to stop - the two-step that gpt-4o-mini skipped
2/2 in live testing. Plain text still renders as before.

Auto-resume is also bounded now: an agent that re-parks after every timeout
burned a model turn every 300s for the rest of the scan (and, since parked
children notify their parent, spammed the parent's inbox on the same cycle).
After _MAX_IDLE_AUTO_RESUMES it stays parked until a real message arrives.
2026-08-02 02:15:51 +03:00
Ahmed Allam 742f382836 docs(core): correct the rationale for notifying a stalled child's parent
The user can message any agent from the TUI, not only the root, so the
justification is that the parent is an agent with no other way to learn
the child parked - not that the child has no human resumer.
2026-08-02 02:15:51 +03:00
Ahmed Allam 8f1bb64d16 fix(core): tell the parent when an interactive subagent parks
Parking is self-service only for the root, which the user is watching.
A parked child owes its parent a report it can no longer send, so the
parent would wait out its full timeout for nothing.
2026-08-02 02:15:51 +03:00
Ahmed Allam 6eec34df24 fix(core): persist the tool-call recovery counter across resumes
An exhausted agent parked in 'waiting' got a fresh nudge budget on every
600s auto-resume, so a wedged agent could nudge-park-nudge indefinitely.
Track the count on the coordinator, snapshot it, and reset it only on
real input or an explicit lifecycle tool.
2026-08-02 02:15:51 +03:00
Ahmed Allam f6f9469e00 fix(core): stop interactive runs stalling on a missing tool call
Interactive turns ended by plain text left the agent parked in 'waiting'
forever. Require an explicit lifecycle tool in both modes and nudge a
text-only turn back into a tool call, bounded by a recovery limit.
2026-08-02 02:15:51 +03:00
devin-ai-integration[bot] 5602bc23ca fix: pre-v1-style lifecycle resilience — mailbox delivery, uniform revival, unexitable runner, waiting timeout, broader retries, crash-safe identity (#923) 2026-08-01 11:17:08 -07:00
alex s a9deb84260 fix(llm): surface structured provider refusals (#944)
* fix(llm): surface structured provider refusals

* fix(llm): settle refused autonomous agents
2026-07-31 10:57:42 -04:00
chunguscodes 76e97e6a59 fix(llm): avoid auth during ChatGPT lookup
LiteLLM treats provider-qualified metadata lookups as an auth path.
Use the underlying model slug so context sizing cannot block the scan
loop in a device-code poll.
2026-07-31 03:45:41 +03:00
Ahmed Allam 885b2ca5c5 test(llm): cover the full run loop against a non-streaming gateway; drop README note
Adds an integration test that drives Runner.run_streamed against a
non-streaming gateway through _NonStreamingModel: the synthetic terminal
event feeds the runner, which executes the tool call and continues to a
final answer over two non-streaming turns. Removes the README env-var note.
2026-07-30 08:30:06 +03:00
Ahmed Allam 980216860e feat(llm): opt-in LLM_DISABLE_STREAMING for non-streaming OpenAI-compatible endpoints
Some OpenAI-compatible gateways don't support Server-Sent Events (or
deliver them unreliably), but the SDK run loop Strix uses only issues
streamed requests, so such a gateway fails every turn. Add an opt-in
LLM_DISABLE_STREAMING setting that wraps the resolved model in
_NonStreamingModel: each turn makes one non-streaming get_response and
replays the completed result as a single terminal stream event, so tool
calls, usage, and the rest of the agent loop are unchanged. Subscription
(ChatGPT) models are always streamed and are not wrapped.
2026-07-30 08:30:06 +03:00
devin-ai-integration[bot] d4e58b2cd0 fix(llm): pass LLM_EXTRA_HEADERS through ModelSettings so they reach the agent loop (#937) 2026-07-29 19:38:06 -07:00
Ahmed Allam e9ebdc502f fix(llm): apply LLM_EXTRA_HEADERS on native OpenAI route even without a custom base 2026-07-30 04:13:25 +03:00
Ahmed Allam ebb3a62a99 feat(llm): custom request headers for OpenAI-compatible endpoints via LLM_EXTRA_HEADERS 2026-07-30 04:13:25 +03:00
alex s 9de747d135 fix(cost): capture OpenRouter streamed usage.cost (fixes $0 kimi-k3 c… (#929)
* fix(cost): capture OpenRouter streamed usage.cost (fixes $0 kimi-k3 cost)

* refactor(cost): encapsulate streamed OpenRouter cost cache, clear per run

* test(cost): resolve OpenRouter handler via LiteLLM provider pipeline
2026-07-28 23:28:34 -04:00
yoni-at-strixandJonathan Singer b313d78f60 Scope viewer session cookie to the bound port (#922)
Co-authored-by: Jonathan Singer <jonathansinger@Mac-4078.lan>
2026-07-27 20:37:54 -04:00
devin-ai-integration[bot]andAhmed Allam e037d8d727 fix: recoverable guardrail blocks and decoupled crash-notify (#919)
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-07-27 16:28:48 -07:00
alex s fade37025d fix viewer tool call collisions across agents (#917) 2026-07-27 18:51:02 -04:00
86282e83a8 fix(tls): replace raw urllib with requests for external HTTPS calls (frozen-build cert failures) (#903)
Co-authored-by: Jonathan Singer <jonathansinger@Mac-4051.lan>
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-07-27 12:34:26 -07:00
Ahmed Allam 082d4ae62c fix(runtime): wake parent when child hits a terminal state (MaxTurnsExceeded) 2026-07-27 04:27:21 -07:00
devin-ai-integration[bot]andAhmed Allam c55a8fa4ba feat(runtime): graduated wrap-up warnings, budget reserve, and interactive budget pause/continue (#893)
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-07-26 20:37:14 -07:00
27f9750cdc feat(llm): enable Bedrock/Anthropic prompt caching for Claude models (#772)
Co-authored-by: Sean Turner <sean.turner@zerohash.com>
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-07-26 17:12:57 -07:00
Matthew Bright 427cdcd9d4 Add Linux ARM64 standalone release support (#886) 2026-07-26 16:27:02 -07:00
devin-ai-integration[bot]andAhmed Allam 384338cf31 fix(runtime): retry transient mid-stream provider errors instead of crashing the scan (#891)
Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-07-26 16:23:31 -07:00