test(agents): capture inline sandbox __import__ escape regression (#107) #110

Open
CoreRasurae wants to merge 1 commits from tdd/m1-inline-sandbox-import-restriction into master
Member

Summary

Adds a failing-first Behave regression test proving issue #107: ToolAgent._execute_python_code (cleveractors.agents.tool) builds the inline-code sandbox's __builtins__ dict per docs/index.md §13.2.1's "Restricted Built-ins for Inline Code" table, which lists a single module-shaped facility (json) and states that table is exhaustive. §13.2.3 additionally prohibits "dynamic import of modules other than those explicitly listed". Despite this, safe_globals["__builtins__"]["__import__"] is bound directly to the real, unrestricted __import__ builtin, so inline code can write import os and reach exactly the filesystem/network/process facilities the standard was written to keep out.

Two scenarios drive the two documented entry points that share _execute_python_code — a type: tool agent's inline code: body, and the exec_python-gated python_exec built-in tool — through the public ToolAgent.process_message() API with code that does import os; result = os.getcwd(), and assert an ExecutionError is raised instead of the import succeeding. Today it isn't: both return the real working directory path.

Both scenarios are tagged @tdd_issue, @tdd_issue_107, and @tdd_expected_fail per the TDD issue-capture workflow.

The actual fix (a restricted __import__ shim permitting only json) lands separately on bugfix/m1-inline-sandbox-import-restriction per issue #107.

Test plan

  • nox -s lint green
  • nox -s format -- --check green
  • nox -s typecheck green
  • nox -s security_scan green
  • nox -s dead_code green
  • nox -s unit_tests green — confirms both assertions fail via AssertionError without the @tdd_expected_fail tag (verified locally by temporarily removing it), and TddExpectedFailPolicy inverts them to a pass with the tag present
  • nox -s coverage_report — 96.7% (>= 96.5% threshold)
  • nox -s integration_tests — green
  • nox -s e2e_tests — green
  • nox -s complexity, nox -s benchmark_regression — informational, unaffected by this test-only change

Closes #108

## Summary Adds a failing-first Behave regression test proving issue #107: `ToolAgent._execute_python_code` (`cleveractors.agents.tool`) builds the inline-code sandbox's `__builtins__` dict per `docs/index.md` §13.2.1's "Restricted Built-ins for Inline Code" table, which lists a single module-shaped facility (`json`) and states that table is exhaustive. §13.2.3 additionally prohibits "dynamic import of modules other than those explicitly listed". Despite this, `safe_globals["__builtins__"]["__import__"]` is bound directly to the real, unrestricted `__import__` builtin, so inline code can write `import os` and reach exactly the filesystem/network/process facilities the standard was written to keep out. Two scenarios drive the two documented entry points that share `_execute_python_code` — a `type: tool` agent's inline `code:` body, and the `exec_python`-gated `python_exec` built-in tool — through the public `ToolAgent.process_message()` API with code that does `import os; result = os.getcwd()`, and assert an `ExecutionError` is raised instead of the import succeeding. Today it isn't: both return the real working directory path. Both scenarios are tagged `@tdd_issue`, `@tdd_issue_107`, and `@tdd_expected_fail` per the TDD issue-capture workflow. The actual fix (a restricted `__import__` shim permitting only `json`) lands separately on `bugfix/m1-inline-sandbox-import-restriction` per issue #107. ## Test plan - [x] `nox -s lint` green - [x] `nox -s format -- --check` green - [x] `nox -s typecheck` green - [x] `nox -s security_scan` green - [x] `nox -s dead_code` green - [x] `nox -s unit_tests` green — confirms both assertions fail via `AssertionError` without the `@tdd_expected_fail` tag (verified locally by temporarily removing it), and `TddExpectedFailPolicy` inverts them to a pass with the tag present - [x] `nox -s coverage_report` — 96.7% (>= 96.5% threshold) - [x] `nox -s integration_tests` — green - [x] `nox -s e2e_tests` — green - [x] `nox -s complexity`, `nox -s benchmark_regression` — informational, unaffected by this test-only change Closes #108
CoreRasurae added this to the v2.1.0 milestone 2026-08-04 21:26:22 +00:00
CoreRasurae added 1 commit 2026-08-04 21:26:27 +00:00
test(agents): capture inline sandbox __import__ escape regression (#107)
CI / lint (pull_request) Successful in 47s
CI / typecheck (pull_request) Successful in 1m32s
CI / security (pull_request) Successful in 1m16s
CI / quality (pull_request) Successful in 1m34s
CI / build (pull_request) Successful in 1m42s
CI / integration_tests (pull_request) Successful in 3m38s
CI / unit_tests (pull_request) Successful in 4m57s
CI / coverage (pull_request) Successful in 4m2s
CI / status-check (pull_request) Successful in 17s
CI / benchmark (pull_request) Failing after 21m22s
bac4868abd
Adds a failing-first Behave regression test proving issue #107:
ToolAgent._execute_python_code (cleveractors.agents.tool) builds the
inline-code sandbox's __builtins__ dict per docs/index.md §13.2.1's
"Restricted Built-ins for Inline Code" table, which lists a single
module-shaped facility (json) and states the table is exhaustive. §13.2.3
additionally prohibits "dynamic import of modules other than those
explicitly listed". Despite this, safe_globals["__builtins__"] binds
"__import__" directly to the real, unrestricted __import__ builtin, so
inline code can write `import os` and reach exactly the filesystem/
network/process facilities the standard was written to keep out.

Two scenarios drive the two documented entry points that share
_execute_python_code -- a "type: tool" agent's inline `code:` body, and
the exec_python-gated `python_exec` built-in tool -- through the public
ToolAgent.process_message() API with code that does `import os; result =
os.getcwd()`, and assert an ExecutionError is raised instead of the
import succeeding. Confirmed both assertions fail via AssertionError when
@tdd_expected_fail is removed (os.getcwd() returns a real path today),
and pass via TddExpectedFailPolicy's inversion with the tag present.

Both scenarios are tagged @tdd_issue, @tdd_issue_107, and
@tdd_expected_fail per the TDD issue-capture workflow.

The actual fix (a restricted __import__ shim permitting only `json`)
lands separately on bugfix/m1-inline-sandbox-import-restriction per
issue #107.

Refs: #107, #108
CoreRasurae added the
Type
Testing
label 2026-08-04 21:27:06 +00:00
hurui200320 approved these changes 2026-08-05 05:47:31 +00:00
hurui200320 left a comment
Member

PR Review: !110 (Ticket #108)

Verdict: Approve

The PR correctly implements the TDD regression test for issue #107 as specified in #108. The two Behave scenarios cover both documented entry points into ToolAgent._execute_python_code, carry the required @tdd_issue @tdd_issue_107 @tdd_expected_fail tags, and rely on AssertionError so the TddExpectedFailPolicy inversion works as intended. No critical or major technical issues were found.

Critical Issues

None

Major Issues

None

Minor Issues

  1. Coverage threshold discrepancynoxfile.py:27 sets COVERAGE_THRESHOLD = 96.5, while CONTRIBUTING.md §"Project-Specific Guidelines" and .gitea/workflows/ci.yml state the enforced coverage gate is 97%. The PR test plan reports 96.7% and passes noxfile.py's threshold, but this inherited project-level inconsistency could mask a real coverage regression. Recommend aligning noxfile.py with the documented 97% gate (separate from this PR, or clarify if 96.5% is intentional).

Nits

  1. Import-form coverage gapfeatures/inline_sandbox_import_restriction.feature:44,56 only tests the import os form. Other dynamic-import forms (e.g., from os import getcwd or __import__('os')) share the same __import__ bypass and could be added in the fix PR (#107) to harden the restriction.

Summary

This is a clean, focused TDD capture PR. The scenarios correctly exercise the sandbox escape through both the python_exec built-in tool and a type: tool inline code: body, and they will flip from inverted-fail to outright pass once the fix in #107 replaces the raw __import__ reference. The code is statically typed, lint-clean, and follows the project's BDD/TDD conventions. Approving.

## PR Review: !110 (Ticket #108) ### Verdict: Approve The PR correctly implements the TDD regression test for issue #107 as specified in #108. The two Behave scenarios cover both documented entry points into `ToolAgent._execute_python_code`, carry the required `@tdd_issue @tdd_issue_107 @tdd_expected_fail` tags, and rely on `AssertionError` so the `TddExpectedFailPolicy` inversion works as intended. No critical or major technical issues were found. ### Critical Issues None ### Major Issues None ### Minor Issues 1. **Coverage threshold discrepancy** — `noxfile.py:27` sets `COVERAGE_THRESHOLD = 96.5`, while `CONTRIBUTING.md` §"Project-Specific Guidelines" and `.gitea/workflows/ci.yml` state the enforced coverage gate is **97%**. The PR test plan reports 96.7% and passes noxfile.py's threshold, but this inherited project-level inconsistency could mask a real coverage regression. Recommend aligning `noxfile.py` with the documented 97% gate (separate from this PR, or clarify if 96.5% is intentional). ### Nits 1. **Import-form coverage gap** — `features/inline_sandbox_import_restriction.feature:44,56` only tests the `import os` form. Other dynamic-import forms (e.g., `from os import getcwd` or `__import__('os')`) share the same `__import__` bypass and could be added in the fix PR (#107) to harden the restriction. ### Summary This is a clean, focused TDD capture PR. The scenarios correctly exercise the sandbox escape through both the `python_exec` built-in tool and a `type: tool` inline `code:` body, and they will flip from inverted-fail to outright pass once the fix in #107 replaces the raw `__import__` reference. The code is statically typed, lint-clean, and follows the project's BDD/TDD conventions. Approving.
Some checks are pending
CI / lint (pull_request) Successful in 47s
CI / typecheck (pull_request) Successful in 1m32s
CI / security (pull_request) Successful in 1m16s
CI / quality (pull_request) Successful in 1m34s
CI / build (pull_request) Successful in 1m42s
CI / integration_tests (pull_request) Successful in 3m38s
CI / unit_tests (pull_request) Successful in 4m57s
CI / coverage (pull_request) Successful in 4m2s
CI / status-check (pull_request) Successful in 17s
CI / benchmark (pull_request) Failing after 21m22s
This pull request can be merged automatically.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin tdd/m1-inline-sandbox-import-restriction:tdd/m1-inline-sandbox-import-restriction
git checkout tdd/m1-inline-sandbox-import-restriction
Sign in to join this conversation.
No Reviewers
No Label
Type
Testing
2 Participants
Notifications
Due Date
No due date set.
Reference: cleveragents/cleveractors-core#110