Expose sandboxed read_file/write_file helpers to inline code (Python_exec), gated by safe_mode #93
Labels
No labels
auto/blocked-by-deps
auto/ci-timeout
auto/claimed-implementer
auto/claimed-merge
auto/claimed-reviewer
auto/driver-down
auto/invariant-violation
auto/last-attempt-tier-0
auto/last-attempt-tier-1
auto/last-attempt-tier-2
auto/last-attempt-tier-min
Automation Tracking
auto/needs-conflict-resolution
auto/needs-implementer
auto/postmortem
auto/ready-to-merge
auto/restart-throttled
auto/revert
auto/sentinel
auto/stale-inactivity
auto/unstable
Blocked
Bounty
$100
Bounty
$1000
Bounty
$10000
Bounty
$20
Bounty
$2000
Bounty
$250
Bounty
$50
Bounty
$500
Bounty
$5000
Bounty
$750
MoSCoW
Could have
MoSCoW
Must have
MoSCoW
Should have
Needs Feedback
Points
1
Points
13
Points
2
Points
21
Points
3
Points
34
Points
5
Points
55
Points
8
Points
88
Priority
Backlog
Priority
CI Blocker
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Signed-off: Owner
Signed-off: Scrum Master
Signed-off: Tech Lead
Spike
State
Completed
State
Duplicate
State
In Progress
State
In Review
State
Paused
State
Unverified
State
Verified
State
Wont Do
Type
Automation
Type
Bug
Type
Discussion
Type
Documentation
Type
Epic
Type
Feature
Type
Legendary
Type
Refactor
Type
Support
Type
Task
Type
Testing
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Blocks
Depends on
#77 Epic: LLM Agent Runtime Stabilization — reliability, resource enforcement & correctness hardening
cleveragents/cleveractors-core
#103 feat(agents): expose sandboxed file helpers to inline code
cleveragents/cleveractors-core
Reference
cleveragents/cleveractors-core#93
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Metadata
feat(agents): expose sandboxed file helpers to inline codefeature/m1-inline-code-sandboxed-file-accessBackground and context
Inline-code tools (§4.5.2) — e.g. a
Python_exec-styletype: toolagent witha
codebody — run in the restricted sandbox (§13.2). Today that sandboxexposes no filesystem access at all:
open()is not in the §13.2.1 built-in setand §13.2.3 prohibits arbitrary filesystem I/O unconditionally. That is
conformant, but it means inline code cannot read or write file contents
dynamically from within a single code body; the only sanctioned path is static
composition (
file_readtool → inline tool →file_writetool), which does notcover dynamic or multi-file access.
ADR-2035 (
docs/adr/ADR-2035-inline-code-sandboxed-file-access.md) decidesto close this gap with sanctioned helper functions rather than raw
open():two callables,
read_file/write_file, always injected into the inlinesandbox, reusing the existing
file_read/file_writevalidated cores. Per theADR's D-7 correction, the two callables are gated solely by the tool agent's
own
safe_modeconfig field — the same flag that already governs thefile_read/file_writetools — rather than by the per-invocation_unsafe_modecontext flag. This issue implements that decision and appliesthe specification amendments the ADR mandates.
Current behavior
open()in any mode; noread_file/write_filefacility exists.
input_datafrom a separately-wired
file_readtool.Expected behavior
Per ADR-2035 (as corrected by D-7), the inline sandbox always gains exactly
two injected local callables (like
json), and nothing else widens. Theirbehavior is gated solely by the tool agent's own
safe_modeconfig field —mirroring how
safe_modealready gates thefile_read/file_writetools:read_file(path, max_chars=None, offset=0) -> str— returns the raw decodedfile contents, reusing the
file_readcore (incl. ADR-2033 offset/max_charswindowing). Returns content, not the
[FILE_READ_SUCCESS]LLM envelope.Confined to the sandbox root when
safe_modeistrue; unrestricted whenfalse.write_file(path, content, mode="w") -> int— writes via thefile_writecore (§4.5.5 modes), returns characters written. Refused unconditionally
when
safe_modeistrue; unrestricted whenfalse.Neither callable is ever absent — referencing
read_file/write_fileneverraises
NameError.Acceptance criteria
read_fileandwrite_fileare always available as injected localsinside every inline-code body, regardless of
safe_mode; referencingeither name never raises
NameError.open,os,io,pathlib, and file descriptors remain unavailable toinline code (the §13.2.1 built-in table is unchanged).
read_filereturns the raw decoded content asstr, honoringmax_charsand
offsetwith the same semantics as thefile_readtool.write_filewrites via thefile_writecore, honorsw/a/insertmodes, and returns the number of characters written.
safe_mode: trueonly):read_filerejects..traversal,~expansion, and any path whose resolved real path (symlinks followed)falls outside the sandbox root; a violation raises
ValueErrornamingthe offending path.
safe_mode: true,write_fileis refusedunconditionally, raising
ValueErrorbefore any I/O is attempted,regardless of the invocation context. With
safe_mode: false, bothread_fileandwrite_fileare unrestricted — no sandbox-root checkapplies to either.
docs/index.mdis updated per ADR-2035 D-6 (§13.2.3 reworded, §4.5.2 liststhe helpers, §13.2.1 note, §13.3 cross-reference) in the same change.
transform.fn, bridge predicates) isunchanged and gains no file access.
Supporting information
docs/adr/ADR-2035-inline-code-sandboxed-file-access.md(Status: Approved; amended by D-7 to correct the mode-gating model).
docs/index.md— §4.5.2 (inline tools / injected facilities), §4.5.1 &§4.5.5 (
file_read/file_writetools and modes), §13.2.1 (inline built-ins),§13.2.3 (prohibited capabilities), §13.3 (filesystem boundaries), §4.5.4
(safe-mode restrictions).
offset/max_charswindowing forread_file.Subtasks
file_read/file_writevalidation+I/O cores so they can backboth the built-in tools and the injected helpers (single validation
surface).
symlink-escape rejection,
../~rejection), raisingValueError.read_fileandwrite_fileover those cores; gate bothsolely on the agent's own
safe_mode(read_fileconfined,write_filerefused, whentrue; both unrestricted whenfalse).are never absent, in either mode.
docs/index.mdper ADR-2035 D-6/D-7, in the same commit as thecode.
sandbox root under
safe_mode: true, write refused undersafe_mode: true, read/write unrestricted undersafe_mode: false, offset/max_chars,write modes, and sandbox-escape attempts (
.., absolute,~,symlink-out-of-root).
real file within the sandbox (
safe_mode: false), and rejecting anescape attempt (
safe_mode: true).nox -s coverage_report.nox(all default sessions), fix any errors.Definition of Done
This issue is complete when:
docs/index.mdin this change.
Metadata exactly.
master, reviewed, and merged.Expose sandboxed read_file/write_file helpers to inline code (Python_exec) in unsafe modeto Expose sandboxed read_file/write_file helpers to inline code (Python_exec), gated by safe_mode