Files
rengine/tools/runner
Yogesh OjhaandClaude Opus 5 7e5ebb6d70 fix(runner): stop a tool when the scan is halted, on both paths
aborting_on binds one stage's abort check for the whole worker process,
but only stream_json consulted it. CLIToolRunner.run was a blocking
subprocess.run, so nine tool paths ran to their own budget after a cancel
or a pause: naabu under host_discovery for up to an hour, ffuf per IP for
thirty minutes, wafw00f, urlfinder, alterx, cdncheck, dnsx and every
subdomain provider for theirs. revoke_scan_tasks deliberately does not
terminate, so nothing else was going to stop them.

run() now waits in poll-sized slices and raises StageAbortedError, which
moves to tools/runner/abort.py so a tool raises the same class the
orchestrator already catches. A finished tool still returns immediately:
the wait is proc.wait(timeout=slice), not a sleep.

Killing the direct child was not enough either. A tool that forks leaves
a grandchild holding the pipes, which keeps hitting the target and blocks
the reader threads until their join times out — twelve seconds to stop a
sleep in the test that found it. Every tool now starts in its own process
group and is stopped with killpg, on both paths.

stdin moves to its own thread beside the readers so a tool that never
reads it cannot deadlock the write.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X5roHYDYzSPRNaTkn8hSkJ
2026-09-13 11:30:05 +05:30
..