Skip to content

add sandbox mounts#17

Merged
steven-passynkov merged 2 commits into
mainfrom
sandbox-object-storage-mounts
Apr 22, 2026
Merged

add sandbox mounts#17
steven-passynkov merged 2 commits into
mainfrom
sandbox-object-storage-mounts

Conversation

@steven-passynkov

@steven-passynkov steven-passynkov commented Apr 21, 2026

Copy link
Copy Markdown
Contributor

Summary

  • add object storage mount validation and response models to sandbox data structures
  • support mount creation, update, and deletion in both sync and async sandbox clients
  • cover mount serialization and helper methods with sync, async, and model tests

Summary by CodeRabbit

New Features

  • Object Storage Mounts: Attach and manage object storage mounts on sandboxes. Create mounts during sandbox initialization or add, update, and delete mounts on running sandboxes.
  • Mount management APIs are available in both synchronous and asynchronous client implementations.

@coderabbitai

coderabbitai Bot commented Apr 21, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@steven-passynkov has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 17 minutes and 0 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 17 minutes and 0 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f028e5b2-995c-48df-8a1b-3019beef5bab

📥 Commits

Reviewing files that changed from the base of the PR and between 401fe40 and 0dd1dd8.

📒 Files selected for processing (2)
  • leap0/models/sandbox.py
  • tests/models/test_sandbox.py
📝 Walkthrough

Walkthrough

This change introduces comprehensive object storage mount support to the SDK by adding new schemas, models, validators, and CRUD operations (add, update, delete) to both synchronous and asynchronous sandbox clients, alongside updated model definitions and full test coverage.

Changes

Cohort / File(s) Summary
Package Exports
leap0/__init__.py
Added ObjectStorageMount to TYPE_CHECKING imports, __all__ exports, and _DYNAMIC_IMPORTS for lazy loading from .models.sandbox.
Schemas
leap0/_schemas/sandbox.py
Introduced three new TypedDict schemas: ObjectStorageMountRequestDict (create), ObjectStorageMountUpdateDict (update), ObjectStorageMountDict (response). Updated SandboxCreateResponseDict and SandboxStatusResponseDict to include mounts field and made id explicitly Required.
Models & Validators
leap0/models/sandbox.py
Added ObjectStorageMount dataclass with from_dict() classmethod. Introduced validators: _validate_object_storage_mounts() (enforces max 8 mounts, validates fields, ensures unique/absolute mount paths) and _validate_object_storage_mount_update() (validates partial update payloads). Extended CreateSandboxParams, Sandbox, and SandboxStatus with optional mounts field.
Async Client
leap0/_async/sandbox.py
Extended AsyncSandboxesClient.create() with mounts parameter. Added three mount operation methods to AsyncSandboxesClient: add_mount() (POST, 201), update_mount() (PATCH), delete_mount() (DELETE, 204). Mirrored these methods on AsyncSandbox instance as convenience wrappers.
Sync Client
leap0/_sync/sandbox.py
Extended SandboxesClient.create() with mounts parameter. Added three mount operation methods to SandboxesClient: add_mount() (POST, 201), update_mount() (PATCH), delete_mount() (DELETE, 204). Mirrored these methods on Sandbox instance as convenience wrappers.
Model Tests
tests/models/test_sandbox.py
Extended Sandbox.from_dict() and SandboxStatus.from_dict() tests to verify mounts parsing. Added tests for CreateSandboxParams mount validation (valid mounts accepted, invalid type/prefix/duplicate paths rejected). Added test for _validate_object_storage_mount_update() rejecting empty payloads.
Sync Client Tests
tests/_sync/test_sandboxes.py
Added test for SandboxesClient.create() serializing mounts in request. Added CRUD operation tests: add_mount (POST endpoint, 201), update_mount (PATCH with JSON patch fields), delete_mount (DELETE, 204). Added delegation test verifying Sandbox mount methods forward to client.
Async Client Tests
tests/_async/test_sandboxes.py
Added test for AsyncSandboxesClient.create() serializing mounts in request. Added CRUD operation tests: add_mount (POST endpoint, 201), update_mount (PATCH with JSON patch fields), delete_mount (DELETE, 204). Added delegation test verifying AsyncSandbox mount methods forward to client.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • tighten sandbox handles and template creds #10: Modifies leap0/models/sandbox.py (Sandbox/SandboxStatus/CreateSandboxParams definitions) and leap0/__init__.py (package exports), directly overlapping with this PR's model and export changes.
  • refactor async #7: Introduces/refactors AsyncSandboxesClient and AsyncSandbox classes that this PR extends with new mount operation methods.
  • Clarify OTel config #8: Modifies CreateSandboxParams in leap0/models/sandbox.py with structural changes to the same model this PR augments with mount support.

Poem

🐰 A warren of mounts, both swift and secure,
Buckets and storage, our sandbox so pure! 📦
Add, patch, and delete—what a dance they perform,
Sync and async together, adhering to form! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'add sandbox mounts' directly and specifically describes the main change—adding object storage mount support to sandbox APIs.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch sandbox-object-storage-mounts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@steven-passynkov

Copy link
Copy Markdown
Contributor Author

@CodeRabbit review

@coderabbitai

coderabbitai Bot commented Apr 22, 2026

Copy link
Copy Markdown
✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (1)
leap0/_sync/sandbox.py (1)

488-490: Use _validate_object_storage_mounts directly instead of constructing CreateSandboxParams.

Going through CreateSandboxParams(mounts=[mount]).mounts instantiates the full sandbox-creation pydantic model (re-validating defaults for template_name, vcpu, memory, etc.) just to normalize a single mount. Importing and calling _validate_object_storage_mounts([mount]) directly is clearer and cheaper, and avoids coupling add_mount to unrelated field validation. Same applies to the async client at leap0/_async/sandbox.py:489.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@leap0/_sync/sandbox.py` around lines 488 - 490, The code currently normalizes
a single mount by instantiating CreateSandboxParams
(CreateSandboxParams(mounts=[mount]).mounts) which triggers full pydantic
validation of unrelated fields; replace that with a direct call to
_validate_object_storage_mounts([mount]) to normalize/validate mounts only.
Update the synchronous add_mount implementation (and the async counterpart in
_async/sandbox.py) to import and call _validate_object_storage_mounts with a
single-item list, use its return value instead of
CreateSandboxParams(...).mounts, and remove the unnecessary dependency on
CreateSandboxParams so add_mount no longer revalidates
template_name/vcpu/memory.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@leap0/models/sandbox.py`:
- Around line 144-150: The validator _validate_object_storage_mounts currently
treats an empty-string prefix as valid (passes the `if prefix and (...)` check)
then later drops it from the normalized payload, causing inconsistent behavior
versus _validate_object_storage_mount_update; make the behavior explicit by
rejecting empty-string prefixes: after the type check for prefix in
_validate_object_storage_mounts add a guard that raises ValueError when prefix
== "" with the same error message as other invalid forms, and mirror this change
in _validate_object_storage_mount_update so both code paths consistently reject
empty prefixes rather than silently eliding them.
- Line 338: Sandbox.mounts and SandboxStatus.mounts default to None but their
from_dict implementations unconditionally use data.get("mounts", []) which
converts absent fields to an empty list; change the parsing to preserve None
when the key is absent (e.g. if "mounts" in data: mounts =
[ObjectStorageMount.from_dict(m) for m in data["mounts"]] else: mounts = None).
Update Sandbox.from_dict and SandboxStatus.from_dict (and any other similar
fields noted around the same area) to use the presence-check pattern so
programmatically constructed instances (None) and parsed instances (absent ->
None) behave the same.

---

Nitpick comments:
In `@leap0/_sync/sandbox.py`:
- Around line 488-490: The code currently normalizes a single mount by
instantiating CreateSandboxParams (CreateSandboxParams(mounts=[mount]).mounts)
which triggers full pydantic validation of unrelated fields; replace that with a
direct call to _validate_object_storage_mounts([mount]) to normalize/validate
mounts only. Update the synchronous add_mount implementation (and the async
counterpart in _async/sandbox.py) to import and call
_validate_object_storage_mounts with a single-item list, use its return value
instead of CreateSandboxParams(...).mounts, and remove the unnecessary
dependency on CreateSandboxParams so add_mount no longer revalidates
template_name/vcpu/memory.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: a632188e-e3e1-4be3-92b2-fb15b1a1cebf

📥 Commits

Reviewing files that changed from the base of the PR and between 418ff3f and 401fe40.

📒 Files selected for processing (8)
  • leap0/__init__.py
  • leap0/_async/sandbox.py
  • leap0/_schemas/sandbox.py
  • leap0/_sync/sandbox.py
  • leap0/models/sandbox.py
  • tests/_async/test_sandboxes.py
  • tests/_sync/test_sandboxes.py
  • tests/models/test_sandbox.py

Comment thread leap0/models/sandbox.py
Comment thread leap0/models/sandbox.py
@steven-passynkov steven-passynkov merged commit b0024e5 into main Apr 22, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant