opencomputer-sdk 0.6.3__tar.gz → 0.6.5__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/.gitignore +3 -0
  2. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/PKG-INFO +1 -1
  3. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/opencomputer/mounts.py +79 -15
  4. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/opencomputer/sandbox.py +25 -2
  5. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/pyproject.toml +1 -1
  6. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/README.md +0 -0
  7. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/examples/run_all_tests.py +0 -0
  8. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/examples/stream_demo.py +0 -0
  9. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/examples/test_commands.py +0 -0
  10. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/examples/test_concurrent.py +0 -0
  11. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/examples/test_declarative_images.py +0 -0
  12. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/examples/test_default_template.py +0 -0
  13. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/examples/test_disk_size.py +0 -0
  14. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/examples/test_domain_tls.py +0 -0
  15. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/examples/test_environment.py +0 -0
  16. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/examples/test_exec.py +0 -0
  17. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/examples/test_file_ops.py +0 -0
  18. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/examples/test_large_files.py +0 -0
  19. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/examples/test_multi_template.py +0 -0
  20. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/examples/test_python_sdk.py +0 -0
  21. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/examples/test_reconnect.py +0 -0
  22. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/examples/test_secret_store_fork.py +0 -0
  23. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/examples/test_secretstore.py +0 -0
  24. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/examples/test_shell.py +0 -0
  25. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/examples/test_timeout.py +0 -0
  26. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/opencomputer/__init__.py +0 -0
  27. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/opencomputer/agent.py +0 -0
  28. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/opencomputer/commands.py +0 -0
  29. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/opencomputer/exec.py +0 -0
  30. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/opencomputer/filesystem.py +0 -0
  31. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/opencomputer/image.py +0 -0
  32. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/opencomputer/project.py +0 -0
  33. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/opencomputer/pty.py +0 -0
  34. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/opencomputer/shell.py +0 -0
  35. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/opencomputer/snapshot.py +0 -0
  36. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/opencomputer/sse.py +0 -0
  37. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/opencomputer/template.py +0 -0
  38. {opencomputer_sdk-0.6.3 → opencomputer_sdk-0.6.5}/opencomputer/usage.py +0 -0
@@ -18,6 +18,9 @@ Thumbs.db
18
18
  .env
19
19
  .env.*
20
20
  !.env.example
21
+ # Cloudflare Worker local secrets (wrangler dev)
22
+ .dev.vars
23
+ .dev.vars.*
21
24
 
22
25
  # Per-developer dev-box lifecycle state (written by deploy/*/deploy-qemu-dev.sh)
23
26
  deploy/**/.qemu-dev-state-*
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opencomputer-sdk
3
- Version: 0.6.3
3
+ Version: 0.6.5
4
4
  Summary: Python SDK for OpenComputer - cloud sandbox platform
5
5
  Project-URL: Homepage, https://github.com/diggerhq/opensandbox
6
6
  Project-URL: Repository, https://github.com/diggerhq/opensandbox
@@ -1,15 +1,20 @@
1
- """FUSE-backed remote filesystem mounts inside a sandbox.
2
-
3
- Mounts use ``rclone mount`` under the hood — one driver covering ~40 backends
4
- (S3, GCS, Azure Blob, SFTP, WebDAV, Dropbox, etc.). Credentials are passed
5
- inline, written to a tmpfs file inside the VM (mode 0600), and never persisted
6
- on the worker. v1 does NOT auto-restore mounts on hibernate/wake callers
7
- re-issue ``add(...)`` after a wake if they need the mount back.
1
+ """FUSE-backed filesystem mounts inside a sandbox.
2
+
3
+ Two drivers:
4
+
5
+ - ``rclone`` (default, via :meth:`Mounts.add`): wrap any of rclone's ~40
6
+ backends (S3, GCS, Azure Blob, SFTP, WebDAV, Dropbox, …) behind a simple
7
+ remote+creds shape. Creds are written to a tmpfs file (mode 0600), never
8
+ persisted on the worker.
9
+ - ``command`` (via :meth:`Mounts.add_command`): run your own FUSE daemon /
10
+ mount command. Use this when you already have a FUSE-ready filesystem and
11
+ don't want rclone as a middle layer. Secrets are injected into the daemon's
12
+ process env (never the command line) and never persisted.
8
13
  """
9
14
 
10
15
  from __future__ import annotations
11
16
 
12
- from dataclasses import dataclass
17
+ from dataclasses import dataclass, field
13
18
  from typing import Literal
14
19
 
15
20
  import httpx
@@ -21,17 +26,22 @@ MountBackend = Literal["s3", "gcs", "azureblob", "sftp", "webdav", "dropbox"]
21
26
  class MountInfo:
22
27
  """An active mount as tracked by the worker.
23
28
 
24
- ``rclone_version`` is the rclone version inside the sandbox captured at
25
- mount-add time (e.g. ``"v1.65.2"``). rclone is baked into the rootfs, so
26
- different sandboxes may carry different versions; this lets ops triage
27
- backend-specific bug reports quickly.
29
+ ``rclone_version`` (rclone driver) is the rclone version inside the sandbox
30
+ captured at mount-add time (e.g. ``"v1.65.2"``). rclone is baked into the
31
+ rootfs, so different sandboxes may carry different versions; this lets ops
32
+ triage backend-specific bug reports quickly.
28
33
  """
29
34
 
30
35
  path: str
31
- remote: str
32
36
  read_only: bool
37
+ driver: str = "rclone"
38
+ # rclone driver
39
+ remote: str = ""
33
40
  backend: str = ""
34
41
  rclone_version: str = ""
42
+ # command driver
43
+ command: list[str] = field(default_factory=list)
44
+ env: dict[str, str] = field(default_factory=dict)
35
45
 
36
46
 
37
47
  @dataclass
@@ -90,6 +100,57 @@ class Mounts:
90
100
  data = resp.json()
91
101
  return _mount_from_dict(data)
92
102
 
103
+ async def add_command(
104
+ self,
105
+ path: str,
106
+ command: list[str],
107
+ env: dict[str, str] | None = None,
108
+ secrets: dict[str, str] | None = None,
109
+ read_only: bool = True,
110
+ ) -> MountInfo:
111
+ """Mount a filesystem by running your own FUSE daemon / mount command.
112
+
113
+ Use this when you already have a FUSE-ready filesystem (your own VFS,
114
+ gcsfuse, s3fs, …) and don't want rclone as a middle layer. The platform
115
+ manages the mountpoint, env/secret injection, and teardown; ``command``
116
+ establishes the mount.
117
+
118
+ Args:
119
+ path: Absolute mountpoint inside the VM.
120
+ command: argv for the FUSE daemon. Any ``"{mountpoint}"`` token is
121
+ replaced with ``path``.
122
+ env: Env vars for the command (returned by :meth:`list`).
123
+ secrets: Secret env vars — injected into the daemon's process env
124
+ (never the command line, so they don't leak via ``ps``), and
125
+ never recorded or returned by :meth:`list`.
126
+ read_only: Advisory for this driver — your command must honor it.
127
+ Also exported to the daemon as ``OC_MOUNT_READONLY=1``. Default
128
+ ``True``.
129
+
130
+ Example:
131
+ >>> await sandbox.mounts.add_command(
132
+ ... path="/mnt/data",
133
+ ... command=["gcsfuse", "my-bucket", "{mountpoint}"],
134
+ ... secrets={"GOOGLE_APPLICATION_CREDENTIALS_JSON": sa_json},
135
+ ... )
136
+ """
137
+ body: dict[str, object] = {
138
+ "path": path,
139
+ "driver": "command",
140
+ "command": command,
141
+ "readOnly": read_only,
142
+ }
143
+ if env is not None:
144
+ body["env"] = env
145
+ if secrets is not None:
146
+ body["secrets"] = secrets
147
+
148
+ resp = await self._client.post(
149
+ f"/sandboxes/{self._sandbox_id}/mounts", json=body
150
+ )
151
+ resp.raise_for_status()
152
+ return _mount_from_dict(resp.json())
153
+
93
154
  async def list(self) -> list[MountInfo]:
94
155
  """List the mounts this worker is tracking for the sandbox.
95
156
 
@@ -117,8 +178,11 @@ class Mounts:
117
178
  def _mount_from_dict(data: dict) -> MountInfo:
118
179
  return MountInfo(
119
180
  path=data["path"],
120
- remote=data["remote"],
121
- backend=data.get("backend", ""),
181
+ driver=data.get("driver", "rclone"),
122
182
  read_only=data.get("readOnly", True),
183
+ remote=data.get("remote", ""),
184
+ backend=data.get("backend", ""),
123
185
  rclone_version=data.get("rcloneVersion", ""),
186
+ command=data.get("command", []) or [],
187
+ env=data.get("env", {}) or {},
124
188
  )
@@ -602,18 +602,41 @@ class Sandbox:
602
602
  pty_key = self._token or self._api_key
603
603
  return Pty(self._ops_client, self.sandbox_id, pty_url, pty_key)
604
604
 
605
- async def create_checkpoint(self, name: str) -> dict:
605
+ async def create_checkpoint(
606
+ self,
607
+ name: str,
608
+ kind: str | None = None,
609
+ promote_to_full: bool | None = None,
610
+ retention_policy: dict | None = None,
611
+ ) -> dict:
606
612
  """Create a named checkpoint of the running sandbox.
607
613
 
608
614
  Args:
609
615
  name: A unique name for this checkpoint.
616
+ kind: Optional checkpoint kind. Use "full" for disk, memory, and
617
+ device state, or "disk_only" for a disk-only checkpoint that
618
+ automatically prepares a full artifact for faster future forks.
619
+ promote_to_full: Advanced override for disk-only checkpoints.
620
+ Defaults to server behavior.
621
+ retention_policy: Optional policy such as
622
+ {"mode": "delete_oldest", "maxCount": 10}. When set, the
623
+ server may delete older eligible checkpoints before creating
624
+ this one.
610
625
 
611
626
  Returns:
612
627
  Checkpoint info dict with id, sandboxId, name, status, etc.
613
628
  """
629
+ body = {"name": name}
630
+ if kind is not None:
631
+ body["kind"] = kind
632
+ if promote_to_full is not None:
633
+ body["promoteToFull"] = promote_to_full
634
+ if retention_policy is not None:
635
+ body["retentionPolicy"] = retention_policy
636
+
614
637
  resp = await self._client.post(
615
638
  f"/sandboxes/{self.sandbox_id}/checkpoints",
616
- json={"name": name},
639
+ json=body,
617
640
  )
618
641
  resp.raise_for_status()
619
642
  return resp.json()
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "opencomputer-sdk"
7
- version = "0.6.3"
7
+ version = "0.6.5"
8
8
  description = "Python SDK for OpenComputer - cloud sandbox platform"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"