Repository navigation
Conversation
The timeout escalation in `UnsafeLocalCodeExecutor._kill_execution` and `LocalEnvironment._kill_command` looked up `signal.SIGKILL` unconditionally. Windows has no SIGKILL, so a timed-out code execution or command raised `AttributeError: module 'signal' has no attribute 'SIGKILL'` instead of being killed and reported: the runaway process kept running and the agent saw the crash rather than the timeout result. Resolve the escalation signal with `getattr(signal, 'SIGKILL', signal.SIGTERM)`, the same fallback `dev_server.py` already uses; `_signal_group` no-ops on platforms without process groups, so the fallback value is never sent by it, and on POSIX nothing changes. Mark `test_kill_execution_signals_group_before_killing_it` as needing POSIX process groups: it asserts the group-signal order and references `signal.SIGKILL` itself, so it cannot run on Windows. CI only runs Linux, which is why the crash stayed invisible there.
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Link to Issue or Description of Change
No issue exists for this yet; the change is described below following the issue
template structure.
Problem:
A timed-out code execution or command crashes on Windows instead of being
killed and reported.
UnsafeLocalCodeExecutor._kill_executionescalates a timed-out execution with:signal.SIGKILLdoes not exist on Windows, so every execution that exceedstimeout_seconds(the default is 300) raisesAttributeError: module 'signal' has no attribute 'SIGKILL'from the timeouthandler. The process is never killed (
process.kill()on the next line neverruns), the agent sees the AttributeError instead of a
CodeExecutionResultwith the timeout note, and the runaway code keepsrunning. Three tests in
tests/unittests/code_executors/test_unsafe_local_code_executor.pyalready cover this path and fail on Windows with exactly this AttributeError;
CI only runs Linux, so the failure is invisible there.
LocalEnvironment._kill_commandhas the same unconditionalsignal.SIGKILLlookup in its escalation step (SIGTERM, 5 s grace, thenSIGKILL), so a timed-out command whose descendants keep the output pipes open
crashes the same way instead of returning a timed-out
ExecutionResult. Bothmodules document Windows explicitly ("Ignored on Windows, as
os.killpgis","
terminateandkillbelow reach the execution itself on the platforms thathave no group to signal"), so the crash contradicts their own intent.
Solution:
Resolve the escalation signal the way
cli/dev_server.pyalready does:_signal_groupreturns before using the signal value on platforms that haveno
os.killpg, so the fallback is never actually sent by it; on POSIX,signal.SIGKILLexists and behavior is unchanged. The module's ownprocess.kill()/proc.kill()continues to handle the process itself onWindows, as the existing comments describe.
The one remaining failing test,
test_kill_execution_signals_group_before_killing_it, asserts thePOSIX group-signal order and references
signal.SIGKILLin its own expectedlist, so it cannot run on a platform without
os.killpg; it is marked withthe repo's existing
not hasattr(os, "killpg")skip convention (astests/unittests/environment/test_local_environment.pyalready does for thesame reason). The timeout-path regression coverage that runs everywhere is
test_execute_code_timeoutandtest_kill_execution_gives_up_on_pipes_that_never_close,which went red→green with this fix on Windows.
Testing Plan
Unit Tests:
Red→green on Windows 11, Python 3.13.9, repo state
287c0b0e65899b0060efd5672c8f419c1119530d:pytest tests/unittests/code_executors/test_unsafe_local_code_executor.py→ 3 failed (
test_execute_code_timeout,test_kill_execution_signals_group_before_killing_it,test_kill_execution_gives_up_on_pipes_that_never_close), each withAttributeError: module 'signal' has no attribute 'SIGKILL'atunsafe_local_code_executor.py:112.UnsafeLocalCodeExecutorwithtimeout_seconds=2runningtime.sleep(8)→ATTRIBUTEERROR.LocalEnvironment.execute(command, timeout=2.0)witha pipe-holding grandchild →
ATTRIBUTEERROR.pytest tests/unittests/code_executors/test_unsafe_local_code_executor.py→ 26 passed, 4 skipped (3 pre-existing skips + the newly POSIX-marked
ordering test).
(
timed_out=True, timeout note in stderr).pytest tests/unittests/environment/test_local_environment.py→ 15 passed,2 skipped (unchanged).
pytest tests/unittests/code_executors tests/unittests/environment(excluding the docker/kubernetes modules, whose extras this machine does
not have) → 128 passed, 6 skipped.
git diff --checkclean;pyink --check,ruff check,isort --check-onlyand the repo's
scripts/compliance_checks.pyclean on the changed files.Manual End-to-End (E2E) Tests:
Not applicable beyond the repro above: the change only alters the
already-covered timeout-escalation path, and the repro exercises the exact
call (
execute_codewith a sleeping program;executewith a timed-outcommand) on the affected platform.
Checklist
Additional context
account when the PR opens (prior contributions to this repo: fix(agents): treat root-relative config_path as absolute on Windows #7979, fix(tools): compare a parameter default with the empty sentinel by identity #7985).
(reproduction, patch, and test runs were executed locally on Windows and are
reported above as they happened).
287c0b0e65899b0060efd5672c8f419c1119530d;d05e482later touchedworking_dirhandling in_local_environment.pyin hunks disjoint from thischange (no conflict).