Repository navigation
Python: feat(core): add session-scoped file access isolation - #8542
Conversation
Add an opt-in session_scoped mode (with an optional explicit scope) that confines file-access tool operations to a working folder derived from the session id via the shared _storage_key_segment derivation under the file-access-specific "~access-" prefix, mirroring FileMemoryProvider. The mode fails closed (ValueError) when neither a scope nor a session id is available, creates the session folder in before_run, appends a session-isolation note to the tool instructions, and logs the derived folder at debug level. All eight tools route store calls through a single _session_path helper; ls/grep treat an empty directory as the session root and grep results stay session-relative. Default mode is byte-for-byte unchanged. Adds seven regression tests, including the COLLIDING_IDENTIFIERS attack strings parametrization, fail-closed coverage, scope override, and shared-store default regression. All harness file-access tests pass; the only full-suite failure is the pre-existing test_feature_stage.py::test_feature_id_allows_lowercase_values on main. Addresses microsoft#8539.
Expose the FileAccessProvider session-scoped mode from create_harness_agent via a new file_access_session_scoped flag (default False, preserving shared-store semantics), threaded through _assemble_context_providers and synchronized across the .pyi stub and the package AGENTS.md file-access section. Adds a pass-through regression test. Addresses microsoft#8539.
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Scoped instructions and directory validation are inconsistent with the new API’s documented behavior.
Get a fresh assessment by requesting another Copilot review.
Review effort: Balanced
Findings: 1
Open (1)
What changed in this PR
Adds opt-in session-scoped isolation for Python harness file-access tools.
Changes:
- Derives per-session or explicit-scope workspace paths.
- Exposes session scoping through
create_harness_agent. - Adds documentation and isolation tests.
| File | Description |
|---|---|
python/packages/core/agent_framework/_harness/_file_access.py |
Implements scoped file-access routing. |
python/packages/core/agent_framework/_harness/_agent.py |
Wires the new harness option. |
python/packages/core/agent_framework/_harness/_agent.pyi |
Updates the public signature stub. |
python/packages/core/tests/core/test_harness_file_access.py |
Tests isolation and compatibility. |
python/packages/core/tests/core/test_harness_agent.py |
Tests harness option wiring. |
python/packages/core/AGENTS.md |
Documents scoped file access. |
💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.
…kspace The session-scoped instruction suffix claimed files are never visible to other sessions, which is wrong when an explicit scope intentionally shares a workspace across sessions. Rephrase the suffix, the class docstring, and the session_scoped parameter docs to describe isolation relative to the resolved workspace (session or configured scope). Addresses review feedback on PR microsoft#8542.
Address review feedback on PR microsoft#8542: - Normalize ls/grep directories with _normalize_relative_path(..., is_directory=True) in scoped mode so a ".." directory cannot escape the session workspace through a permissive custom store. - Place every scoped working folder under a fixed ~access- namespace directory, so file access and file memory working folders cannot collide when both providers share one store root and a literal-safe identifier. - Treat a non-empty explicit scope as enabling scoped mode by itself, aligning with FileMemoryProvider(scope=...). Adds parent-traversal, namespace-collision, and scope-only regression tests and updates layout assertions to the namespaced folder shape. All harness suites pass; ruff clean.
|
JHf0912, thanks for addressing the review feedback. The remaining blocker is the PR body: it does not retain and complete the current template’s four required sections, all three Description & Review Guide prompts, a valid closing reference to #8539, or the contribution checklist. Please update the body to the current template and re-request review. |
|
Eduard van Valkenburg (@eavanvalkenburg) thanks — I've rewritten the PR body to the current template: Motivation & Context, Description & Review Guide (all three prompts), Related Issue with a closing Fixes #8539 reference, and the Contribution Checklist. Requesting re-review. |
Eduard van Valkenburg (eavanvalkenburg)
left a comment
There was a problem hiding this comment.
JHf0912, the review feedback is addressed on the current head, and the complete change looks good to me.
…ft#8542) * feat(core): add session-scoped mode to FileAccessProvider Add an opt-in session_scoped mode (with an optional explicit scope) that confines file-access tool operations to a working folder derived from the session id via the shared _storage_key_segment derivation under the file-access-specific "~access-" prefix, mirroring FileMemoryProvider. The mode fails closed (ValueError) when neither a scope nor a session id is available, creates the session folder in before_run, appends a session-isolation note to the tool instructions, and logs the derived folder at debug level. All eight tools route store calls through a single _session_path helper; ls/grep treat an empty directory as the session root and grep results stay session-relative. Default mode is byte-for-byte unchanged. Adds seven regression tests, including the COLLIDING_IDENTIFIERS attack strings parametrization, fail-closed coverage, scope override, and shared-store default regression. All harness file-access tests pass; the only full-suite failure is the pre-existing test_feature_stage.py::test_feature_id_allows_lowercase_values on main. Addresses microsoft#8539. * feat(core): wire file_access_session_scoped through create_harness_agent Expose the FileAccessProvider session-scoped mode from create_harness_agent via a new file_access_session_scoped flag (default False, preserving shared-store semantics), threaded through _assemble_context_providers and synchronized across the .pyi stub and the package AGENTS.md file-access section. Adds a pass-through regression test. Addresses microsoft#8539. * docs(core): describe scoped file access isolation relative to the workspace The session-scoped instruction suffix claimed files are never visible to other sessions, which is wrong when an explicit scope intentionally shares a workspace across sessions. Rephrase the suffix, the class docstring, and the session_scoped parameter docs to describe isolation relative to the resolved workspace (session or configured scope). Addresses review feedback on PR microsoft#8542. * fix(core): harden session-scoped file access boundaries Address review feedback on PR microsoft#8542: - Normalize ls/grep directories with _normalize_relative_path(..., is_directory=True) in scoped mode so a ".." directory cannot escape the session workspace through a permissive custom store. - Place every scoped working folder under a fixed ~access- namespace directory, so file access and file memory working folders cannot collide when both providers share one store root and a literal-safe identifier. - Treat a non-empty explicit scope as enabling scoped mode by itself, aligning with FileMemoryProvider(scope=...). Adds parent-traversal, namespace-collision, and scope-only regression tests and updates layout assertions to the namespaced folder shape. All harness suites pass; ruff clean.

Motivation & Context
create_harness_agent'sfile_access_storeexpects a caller-suppliedAgentFileStorewhose root is already the desired working directory. UnlikeFileMemoryProvider,FileAccessProviderprovides no session isolation, so hosts that compile the harness agent before a session exists (AG-UI entrypoints, workflow executors restored from checkpoints) cannot give each session an isolated workspace without baking the session id into the path, recreating the agent per session, or mutating private store fields. Sessions therefore share one workspace, or hosts rely on private-API workarounds. This PR adds an opt-in session-scoped mode so per-session/tenant workspaces (downloads, uploads, sandbox-adjacent artifacts) are a first-class framework feature, mirroring how file memory already isolates by session.Description & Review Guide
FileAccessProvidergainssession_scoped: bool = Falseandscope: str | None = None. When enabled (or when a non-emptyscopeis passed),before_runderives a working folder fromscope or context.session_idvia the shared_storage_key_segmentderivation inside a fixed~access-namespace directory, fails closed (ValueError) when neither is available, and creates the folder. All eight tools route store calls through a single_session_pathhelper;ls/grepnormalize theirdirectoryargument with_normalize_relative_path(..., is_directory=True)in scoped mode and treat an empty directory as the session root; grep results stay session-relative.create_harness_agentexposes the mode viafile_access_session_scoped(assembly pass-through,.pyistub, docstring), andpackages/core/AGENTS.mddocuments it.COLLIDING_IDENTIFIERSattack strings, fail-closed behavior, scope override and scope-only activation, parent-traversal rejection, cross-component namespace separation fromFileMemoryProvideron a shared store root, and a shared-store default regression...escape the session folder), and file-access working folders can no longer collide with file-memory folders when both providers share one store root. The only full-suite failure is the pre-existingtest_feature_stage.py::test_feature_id_allows_lowercase_values, which also fails on a clean checkout of main (verified via stash)._storage_key_segmentreturns literal-safe identifiers unchanged, so the fixed~access-directory is what separates file access from file memory on a shared store root.scopeis treated as unconfigured (falsy), matchingFileMemoryProvider's resolution semantics.Related Issue
Fixes #8539 — no other open PR covers this issue.
Contribution Checklist
breaking changelabel (or add "[BREAKING]" to the title prefix, before or after any language prefix) — a workflow keeps the label and title prefix in sync automatically.