Commit Graph
709 Commits
Author SHA1 Message Date
oyasumiandClaude Opus 5 32bd2a2181 fix(core): raise the open-file limit so many-agent scans don't exhaust fds
A scan runs dozens of agents concurrently, each holding a sandbox session, a
browser session, a model client, and a SQLite handle. At the common 1024 soft
file-descriptor limit that budget is exhausted around ~32 agents, after which
SQLite can no longer open agents.db and agents fail en masse with
"unable to open database file" (an fd-exhaustion symptom, not DB corruption).

Measured directly: fd usage scales ~linearly with concurrent agents and hits
1024 at 32 agents; fds are reclaimed as agents finish, so this is a ceiling
problem, not a leak. Strix never set its own limit, inheriting whatever the
launching shell had (often 1024).

Raise RLIMIT_NOFILE toward the hard cap at scan start (best-effort, idempotent,
POSIX-guarded; warns when the hard cap is itself too low to lift without a
privileged operator). Runs no longer depend on the operator setting ulimit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-09 00:53:44 +00:00
oyasumiandClaude Opus 5 806a2f81ea fix(safety): narrow the compound "must be split" rule to uninspectable execution
Trace review showed the split rule firing on commands with no execution at all:
curl downloading a `.js` asset (`curl …/app.js > app.js`), glob and grep
patterns containing a script suffix, and running an inspectable workspace script
with an output redirect (`python3 probe.py > out.jsonl`). It blocked on any
interpreter segment or any token ending in a script suffix.

Block only the shapes whose executed code no artifact can describe: an
interpreter that reads from a pipe, stdin, or heredoc, and create-then-run where
a script-suffixed file is written (`> x.py`, `-o x.py`) and executed in the same
expression. Running an inspectable script with its output redirected or piped,
and downloading a script-named asset, now go to review — the script itself is
still read into the packet. Destructive-in-a-chain detection is unchanged.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 18:03:37 +00:00
oyasumiandClaude Opus 5 3c4be45d34 feat(safety): collect target-list files passed via -w/-l flags
Recon tools route their target list through a flag — `ffuf -w wordlist.txt`,
`httpx -l hosts.txt`, `nuclei --list targets.txt` — not the `<` redirect the
input-file collector already handled, so the reviewer kept blocking "probes
every host listed in hosts.txt" because the list was never in the packet. Parse
the value of the common list-file flags and collect it the same bounded way,
alongside redirect inputs. The value is only read when it resolves to a
workspace file, so a boolean `-l` (grep, wc) whose next token is not a file
collects nothing and never makes the packet incomplete.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 17:57:08 +00:00
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 d6c5b410ad fix(tui): keep color across every wrapped row of a tool result line
A long blocked-safety reason showed its amber only on the first row. wrapBlock
wraps an over-width line with ansi.Wrap, which emits the opening SGR on the
first row and the reset on the last, leaving the continuation rows unstyled — so
a wrapped colored line (a safety block reason, a long error) lost its color
after the first row.

carryStyle re-opens the active style on each continuation row and terminates
each with a reset. Any colored line wider than the chat width was affected;
block reasons are just the first routinely-long one.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 02:05:49 +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 f1356ac33c chore(safety): satisfy the pinned lint gates and drop the brand strings
The versions in .pre-commit-config.yaml are stricter than the ones uv resolves,
so these were invisible to `make lint`:

- ruff 0.11.13 reports N802 for `ast.NodeVisitor`'s `visit_*` methods; 0.15.20
  exempts them. The names are dispatch keys and cannot be lowercased, so add the
  per-file ignore next to the existing stdlib-handler precedent.
- mypy 1.17.1 does not narrow `str` to `SafetyMode` through a membership test
  against the tuple. Return the matched element instead.
- bandit does not read `# noqa`; pair it with `# nosec` as the other 33 sites do.

The trailing-whitespace hook rewrites the built viewer bundle, stripping a space
and a tab that are content inside a highlight.js character class. Exclude the
generated assets rather than let a hook corrupt shipped JS.

Upstream removed every "Strix" literal from model-facing text; this branch
predated that and reintroduced one in the prompt template and one as an agent
name.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-08 00:56:18 +00:00
oyasumiandClaude Opus 5 58d8a9b7c4 fix(tui,viewer): show the safety verdict for every blocked tool
Only the terminal renderers learned about the `blocked` status. `apply_patch`
and `repeat_request` are also refused by the safety runtime — `apply_patch`
unconditionally in observe mode, `repeat_request` unconditionally in guarded —
and both rendered as though nothing had happened. A blocked patch was
byte-identical to one that was applied.

Extract the verdict line into `safetyBlockLine` in the Go renderers and a
`SafetyBlock` component in the viewer, then call it from the patch and
repeat-request renderers as well. The viewer's terminal renderer was reading
the envelope's `error`, which is a fixed string, so it now reads
`safety.reason` like the TUI already did.

Go tests assert a blocked patch no longer matches an applied one.

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 f8a8801d56 docs(skills): rename skills to descriptive names and broaden descriptions for discoverability (#1013) 2026-08-07 14:24:19 -04:00
Ahmed Allam 22750077da chore: release v1.5.1 v1.5.1 2026-08-07 20:28:06 +03:00
Ahmed Allam 0607abf9e5 fix(tui): scrollbar visibility, findings scrolling, and report navigation (#1006) 2026-08-07 06:14:22 -07:00
alex s 9dae76667b expand firebase storage rules coverage (#1002) 2026-08-06 23:22:06 -07:00
Ahmed Allam b08662449d ci: publish nested standalone archives as release assets v1.5.0 2026-08-06 22:03:57 +03:00
Ahmed Allam bda0f54342 ci: tolerate repr-escaped backslashes in the release TUI-sidecar check 2026-08-06 21:55:12 +03:00
Ahmed Allam c6c8bb5ca6 ci: match Windows backslash paths in the release TUI-sidecar check 2026-08-06 21:26:23 +03:00
Ahmed Allam 28747e682e chore(image): bump sandbox tag 1.2.0 -> 1.3.0 2026-08-06 20:50:07 +03:00
Ahmed Allam e71bf127fd chore: release v1.5.0 2026-08-06 20:50:07 +03:00
Ahmed Allam 709a7a1b39 docs(skills): skipped symbol search must be disclosed in reachability evidence 2026-08-06 17:06:00 +03:00
Ahmed Allam ec07f0f68f docs(skills): require per-CVE affected-symbol matching in dependency reachability analysis 2026-08-06 17:06:00 +03:00
alex s 2a9ab1d6cd feat: agent-ready — installable SKILL.md skills, AGENTS.md, coding-ag… (#926) 2026-08-06 06:54:40 -07:00
Ahmed Allam 51bcf70722 update readme 2026-08-06 15:47:45 +03:00
Ahmed Allam cea52cce8d prompt changes 2026-08-06 15:39:43 +03:00
Ahmed Allam 77c7b0df09 prompt changes 2026-08-06 15:39:43 +03: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
Ahmed Allam 82dcd31357 fix(tui): keep a long error inside the status row (#970) 2026-08-04 07:26:22 -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 ea6d53f4e9 build: add types-requests to dev deps
The old openai-agents pin pulled types-requests in transitively; 0.19.0 does
not, so mypy lost the requests stubs. Depend on them directly.
2026-08-04 06:14:54 +03: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
Ahmed Allam 6f70b6f319 fix(tui): drop the shift+enter newline hint from the setup footer 2026-08-04 06:05:46 +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 797b37467e perf(cli): ~10x faster startup via lazy imports (#920)
* perf(cli): fast startup — lazy heavy imports + onedir standalone build

* perf(cli): drop legacy single-file compat from install/self-update

* perf(cli): simplify — drop constants module and extra lazy-import refactors

* refactor(update): strix --update just re-runs the install script

* perf(cli): drop packaging/install/update changes; deepen lazy imports instead

Reverts the onedir build, install.sh, and self-update changes so release
mechanics stay untouched. Startup cost is addressed purely by deferring
heavy imports (agents/openai, config.models, report state/writer, docker)
until a scan actually runs; DEFAULT_MAX_TURNS moves to strix.config.settings
so argparse no longer pulls the agents SDK.

---------

Co-authored-by: Ahmed Allam <ahmed39652003@gmail.com>
2026-08-02 06:24:31 +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