Skip to content

feat(sdk): scope permissions to routes for composite backends with sandbox default#2659

Merged
Nick Hollon (nick-hollon-lc) merged 1 commit intomainfrom
nh/scope-permissions-to-route-for-composite
Apr 10, 2026
Merged

feat(sdk): scope permissions to routes for composite backends with sandbox default#2659
Nick Hollon (nick-hollon-lc) merged 1 commit intomainfrom
nh/scope-permissions-to-route-for-composite

Conversation

@nick-hollon-lc
Copy link
Copy Markdown
Contributor

@nick-hollon-lc Nick Hollon (nick-hollon-lc) commented Apr 10, 2026

Summary

Previously, _PermissionMiddleware unconditionally rejected any backend that supported execution (SandboxBackendProtocol), even when permissions only targeted paths under composite backend routes that don't involve execution at all.

This PR adds a check (_all_paths_scoped_to_routes) so that when a CompositeBackend has a sandbox default, permissions are allowed as long as every permission path is scoped under a known route prefix. Permissions that cover paths outside routes (hitting the sandbox default) still raise NotImplementedError.

Examples

from deepagents import create_deep_agent
from deepagents.backends import CompositeBackend
from deepagents.middleware.permissions import FilesystemPermission

sandbox = SandboxBackend(...)  # supports execution
memories = StoreBackend(...)

composite = CompositeBackend(
    default=sandbox,
    routes={"/memories/": memories},
)

# Previously raised NotImplementedError — now works because
# permissions are scoped entirely to the /memories/ route
agent = create_deep_agent(
    model=model,
    backend=composite,
    permissions=[
        FilesystemPermission(operations=["write"], paths=["/memories/**"], mode="deny"),
    ],
)

# Permissions outside any route still raise — they'd hit the sandbox default
agent = create_deep_agent(
    model=model,
    backend=composite,
    permissions=[
        FilesystemPermission(operations=["write"], paths=["/workspace/**"], mode="deny"),
    ],
)
# -> NotImplementedError

# Wildcard paths also raise — /** covers both routes and the default
agent = create_deep_agent(
    model=model,
    backend=composite,
    permissions=[
        FilesystemPermission(operations=["read"], paths=["/**"], mode="deny"),
    ],
)
# -> NotImplementedError

Changes

  • permissions.py: Added _all_paths_scoped_to_routes helper and refined the __init__ guard to allow route-scoped permissions with sandbox defaults
  • test_end_to_end.py: Added TestCompositeBackendPermissionsEndToEnd with 6 tests covering route-scoped allow/deny, wildcard rejection, mixed-path rejection, and multi-route scenarios

@github-actions github-actions bot added deepagents Related to the `deepagents` SDK / agent harness feature New feature/enhancement or request for one internal User is a member of the `langchain-ai` GitHub organization size: M 200-499 LOC labels Apr 10, 2026
assert len(tool_messages) == 1
assert "permission denied" not in tool_messages[0].content

def test_permissions_outside_routes_still_raises_with_sandbox_default(self) -> None:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NICE

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BOOM

@nick-hollon-lc Nick Hollon (nick-hollon-lc) merged commit 6dd6122 into main Apr 10, 2026
42 checks passed
@nick-hollon-lc Nick Hollon (nick-hollon-lc) deleted the nh/scope-permissions-to-route-for-composite branch April 10, 2026 15:05
Mason Daugherty (mdrxy) added a commit that referenced this pull request Apr 10, 2026
> [!CAUTION]
> Merging this PR will automatically publish to **PyPI** and create a
**GitHub release**.

For the full release process, see
[`.github/RELEASING.md`](https://github.com/langchain-ai/deepagents/blob/main/.github/RELEASING.md).

---

_Everything below this line will be the GitHub release body._

---


##
[0.5.2](deepagents==0.5.1...deepagents==0.5.2)
(2026-04-10)

### Features

* Permissions system for filesystem access control
([#2633](#2633))
([41dc759](41dc759))
* Scope permissions to routes for composite backends with sandbox
default
([#2659](#2659))
([6dd6122](6dd6122))
* Raise `ValueError` for permission paths without leading slash and path
traversal
([#2665](#2665))
([723d27d](723d27d))
* Implement `upload_files` for `StateBackend`
([#2661](#2661))
([5798345](5798345))

### Bug Fixes

* Catch `PermissionError` in `FilesystemBackend` ripgrep
([#2571](#2571))
([3d5d673](3d5d673))

---

_Everything above this line will be the GitHub release body._

---

> [!NOTE]
> A **New Contributors** section is appended to the GitHub release notes
automatically at publish time (see [Release
Pipeline](https://github.com/langchain-ai/deepagents/blob/main/.github/RELEASING.md#release-pipeline),
step 2).

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Mason Daugherty <github@mdrxy.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

deepagents Related to the `deepagents` SDK / agent harness feature New feature/enhancement or request for one internal User is a member of the `langchain-ai` GitHub organization size: M 200-499 LOC

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants