maf-sandbox-hyperlight 0.1.0__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.
- maf_sandbox_hyperlight-0.1.0/LICENSE +21 -0
- maf_sandbox_hyperlight-0.1.0/PKG-INFO +165 -0
- maf_sandbox_hyperlight-0.1.0/README.md +136 -0
- maf_sandbox_hyperlight-0.1.0/pyproject.toml +92 -0
- maf_sandbox_hyperlight-0.1.0/pyproject.toml.orig +76 -0
- maf_sandbox_hyperlight-0.1.0/src/maf_sandbox_hyperlight/__init__.py +37 -0
- maf_sandbox_hyperlight-0.1.0/src/maf_sandbox_hyperlight/_backend.py +423 -0
- maf_sandbox_hyperlight-0.1.0/src/maf_sandbox_hyperlight/_config.py +50 -0
- maf_sandbox_hyperlight-0.1.0/src/maf_sandbox_hyperlight/_lifetime.py +36 -0
- maf_sandbox_hyperlight-0.1.0/src/maf_sandbox_hyperlight/_linux.py +287 -0
- maf_sandbox_hyperlight-0.1.0/src/maf_sandbox_hyperlight/_linux_entry.py +22 -0
- maf_sandbox_hyperlight-0.1.0/src/maf_sandbox_hyperlight/_linux_watch.py +97 -0
- maf_sandbox_hyperlight-0.1.0/src/maf_sandbox_hyperlight/_process.py +115 -0
- maf_sandbox_hyperlight-0.1.0/src/maf_sandbox_hyperlight/_windows.py +163 -0
- maf_sandbox_hyperlight-0.1.0/src/maf_sandbox_hyperlight/_wire.py +29 -0
- maf_sandbox_hyperlight-0.1.0/src/maf_sandbox_hyperlight/_worker.py +98 -0
- maf_sandbox_hyperlight-0.1.0/src/maf_sandbox_hyperlight/py.typed +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 SOKOLAI BV
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: maf-sandbox-hyperlight
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Hyperlight Python micro-VMs on Windows WHP and Linux KVM with bounded execution and snapshot reset.
|
|
5
|
+
Keywords: hyperlight,microvm,sandbox,agent-framework,microsoft-agent-framework,isolation
|
|
6
|
+
Author: SOKOLAI BV
|
|
7
|
+
Author-email: SOKOLAI BV <info@sokolai.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Typing :: Typed
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
18
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
19
|
+
Classifier: Topic :: Software Development :: Testing
|
|
20
|
+
Requires-Dist: maf-sandbox>=0.40.0,<0.41
|
|
21
|
+
Requires-Dist: hyperlight-sandbox==0.7.0
|
|
22
|
+
Requires-Dist: hyperlight-sandbox-backend-wasm==0.7.0 ; (platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine == 'AMD64' and sys_platform == 'win32')
|
|
23
|
+
Requires-Dist: hyperlight-sandbox-python-guest==0.7.0 ; (platform_machine == 'x86_64' and sys_platform == 'linux') or (platform_machine == 'AMD64' and sys_platform == 'win32')
|
|
24
|
+
Requires-Python: >=3.12, <3.15
|
|
25
|
+
Project-URL: Homepage, https://www.sokol.ai
|
|
26
|
+
Project-URL: Source, https://github.com/sokolaidev/maf-extensions
|
|
27
|
+
Project-URL: Issues, https://github.com/sokolaidev/maf-extensions/issues
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# maf-sandbox-hyperlight
|
|
31
|
+
|
|
32
|
+
[](https://pypi.org/project/maf-sandbox-hyperlight/) [](https://pypi.org/project/maf-sandbox-hyperlight/) [](https://github.com/sokolaidev/maf-extensions/blob/main/packages/maf-sandbox-hyperlight/LICENSE)
|
|
33
|
+
|
|
34
|
+
> **Experimental.** This package warns on import with `MafSandboxHyperlightExperimentalWarning`. Releases before 1.0 may change or remove APIs without notice.
|
|
35
|
+
|
|
36
|
+
Run Python statements in Hyperlight microVMs through the `maf-sandbox` protocol. This backend supports `RUN_CODE` and `SNAPSHOT`, including CodeAct without file channels. It is experimental and has not yet been released.
|
|
37
|
+
|
|
38
|
+
## Requirements
|
|
39
|
+
|
|
40
|
+
Windows x86-64 with Windows Hypervisor Platform, or Linux x86-64 with glibc 2.28 or newer, KVM and a delegated cgroup v2 subtree. Host CPython versions 3.12 through 3.14 are supported by the pinned wheels. The measured configurations are Windows 11 / WHP / host CPython 3.13, Ubuntu 24.04 under WSL2 / KVM / host CPython 3.12, and native Ubuntu 24.04 / KVM / host CPython 3.13, using the exact matched `hyperlight-sandbox`, `hyperlight-sandbox-backend-wasm` and `hyperlight-sandbox-python-guest` 0.7.0 wheels. The guest is CPython 3.14 compiled to WebAssembly. Other operating systems, architectures, hypervisors, custom guests, images and guest working directories are refused. Linux hosts exposing `/dev/mshv` are refused until that family is validated.
|
|
41
|
+
|
|
42
|
+
Each sandbox has a dedicated worker process. The adapter sets `HYPERLIGHT_MAX_SURROGATES=0` inside that process, initializes the platform, warms the packaged guest and takes its initial snapshot during acquire. Windows retains the WHP library handle and uses a job to bound committed memory and terminate the worker tree. Linux verifies KVM VM creation and uses cgroup memory enforcement with an independent lifetime watcher. Linux forwards only the exact environment names `PATH`, `HOME`, `XDG_CACHE_HOME`, `TMPDIR`, `LANG` and `LC_ALL`; Windows matches its system/runtime environment names case-insensitively. The SDK materializes the packaged guest in its ordinary local application cache; no host directory is exposed to guest code.
|
|
43
|
+
|
|
44
|
+
One host process owns this backend within its ownership namespace. Windows uses a machine-wide named event; Linux holds `/run/lock/maf-sandbox-hyperlight.lock` open with an exclusive lock. New lock files are empty, readable by every host user and have no write permissions, regardless of the creating process's umask. The final path is published atomically only after those permissions are ready, without replacing an existing lock. Ordinary Python fork children release their inherited owner descriptor; ownership remains with the original host and its lifetime watchers. Route acquire, execution and purge requests to that process. A second process refuses acquire and returns an unclean disposal result. Ownership lasts until the host exits, including after `aclose()`; Linux watchers retain the lock until old worker trees are gone. Backend objects within the owner share the same key/kind registry. Do not unlink the lock file or use separate mount/PID/cgroup namespaces to route one logical backend across owners. Replicated containers and cross-machine routing require additional deployment work.
|
|
45
|
+
|
|
46
|
+
### Linux and WSL2 setup
|
|
47
|
+
|
|
48
|
+
The host user needs read/write access to `/dev/kvm`. WSL2 needs hardware virtualization exposed by Windows, KVM support enabled in its Linux kernel, and nested virtualization enabled on a supported Windows host; see the [WSL configuration reference](https://learn.microsoft.com/en-us/windows/wsl/wsl-config#configuration-settings-for-wslconfig). Check the device and follow the [Hyperlight KVM prerequisites](https://hyperlight.org/guides/getting-started/#prerequisites). Acquire attempts actual VM creation, so a device node alone does not satisfy admission.
|
|
49
|
+
|
|
50
|
+
The operator supplies a writable cgroup v2 root with the memory controller enabled for children, `memory.swap.max`, `memory.oom.group`, `cgroup.kill` and pidfd support. The default root is `/sys/fs/cgroup/maf-sandbox-hyperlight`; set `HyperlightSandboxConfig(linux_cgroup_root="/sys/fs/cgroup/your-delegated-subtree")` when a service manager delegates another path. Keep the application in a leaf beneath that subtree so the root has no processes. The application needs permission to create worker groups and migrate its workers at their common ancestor. The library never mounts cgroups, enables ancestor controllers or elevates privileges.
|
|
51
|
+
|
|
52
|
+
For local development, on a host whose root cgroup already offers the memory controller, an operator can prepare the subtree and launch a host as the calling user. The calling user must already have KVM device access; replace the interpreter and application arguments with their absolute paths:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
sudo sh -c '
|
|
56
|
+
set -eu
|
|
57
|
+
root=/sys/fs/cgroup/maf-sandbox-hyperlight
|
|
58
|
+
mkdir -p "$root/host"
|
|
59
|
+
printf +memory > "$root/cgroup.subtree_control"
|
|
60
|
+
chown "$SUDO_UID:$SUDO_GID" "$root" "$root/cgroup.procs"
|
|
61
|
+
printf "%s" "$$" > "$root/host/cgroup.procs"
|
|
62
|
+
exec setpriv --reuid "$SUDO_UID" --regid "$SUDO_GID" --init-groups -- "$@"
|
|
63
|
+
' sh /absolute/path/to/.venv/bin/python /absolute/path/to/app.py
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
A supervisor starts in a separate process session and inherits the ownership lock before creating the worker cgroup or process. It configures `memory.max`, zero swap allowance and group OOM enforcement; a trusted bootstrap joins that cgroup before executing the worker command. The supervisor holds pidfds for the host and worker and remains outside the worker's memory group. Host exit, worker exit or an explicit close triggers worker termination and `cgroup.kill`, including descendants that change process session. Cleanup also covers startup before the bootstrap joins the group, waits for the kernel's empty-group indication and removes only that worker's cgroup. The supervisor is trusted host infrastructure and must remain running until cleanup completes. A cleanup timeout or unexpected supervisor exit reports an unclean result; ownership remains held while the supervisor retries cleanup. Service managers should own the delegated subtree's lifetime as well. Missing delegation or enforcement controls refuses acquisition; there is no fallback to an unbounded worker.
|
|
67
|
+
|
|
68
|
+
## Direct execution
|
|
69
|
+
|
|
70
|
+
Install this package when its first release is available; the dependency pins select the compatible SDK and guest automatically. Repository development uses `uv sync`.
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
import asyncio
|
|
74
|
+
|
|
75
|
+
from maf_sandbox import Capability, SandboxKey, SandboxSpec
|
|
76
|
+
from maf_sandbox_hyperlight import HyperlightSandboxBackend
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
async def main() -> None:
|
|
80
|
+
backend = HyperlightSandboxBackend()
|
|
81
|
+
key = SandboxKey(scope="user-1", thread_id="thread-1", agent_id="analyst")
|
|
82
|
+
spec = SandboxSpec(
|
|
83
|
+
kind="python",
|
|
84
|
+
work_dir=None,
|
|
85
|
+
requires=frozenset({Capability.RUN_CODE}),
|
|
86
|
+
)
|
|
87
|
+
try:
|
|
88
|
+
sandbox = await backend.acquire(key, spec)
|
|
89
|
+
result = await sandbox.run_code("answer = 6 * 7\nprint(answer)", timeout=5)
|
|
90
|
+
print(result.stdout) # 42
|
|
91
|
+
await sandbox.reset(timeout=5)
|
|
92
|
+
finally:
|
|
93
|
+
await backend.aclose()
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
asyncio.run(main())
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
`acquire` reuses a live sandbox for the complete `SandboxKey` and kind. A different network policy, execution contract or resource configuration requires disposal first. `reset` restores the initial runtime state and rotates `instance_id`; disposal with an older ID cannot remove its replacement. Ordinary Python exceptions return a nonzero `ExecResult` and leave the runtime usable. Explicit reset is what removes accumulated Python state.
|
|
100
|
+
|
|
101
|
+
## CodeAct
|
|
102
|
+
|
|
103
|
+
Install `maf-sandbox-codeact` alongside this backend and explicitly select `CodeactRuntime(RUNTIME_INSTRUCTIONS)`. Its default exec variant requires capabilities this backend does not provide.
|
|
104
|
+
|
|
105
|
+
```python
|
|
106
|
+
from maf_sandbox import CallerContext, Cleanup, SandboxRouter
|
|
107
|
+
from maf_sandbox_codeact import CodeactRuntime, make_codeact_tools
|
|
108
|
+
from maf_sandbox_hyperlight import RUNTIME_INSTRUCTIONS, HyperlightSandboxBackend
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def tools_for(context: CallerContext):
|
|
112
|
+
backend = HyperlightSandboxBackend()
|
|
113
|
+
router = SandboxRouter([backend], min_cleanup=Cleanup.RESET)
|
|
114
|
+
tools = make_codeact_tools(
|
|
115
|
+
router,
|
|
116
|
+
"analyst",
|
|
117
|
+
context,
|
|
118
|
+
runtime=CodeactRuntime(RUNTIME_INSTRUCTIONS),
|
|
119
|
+
)
|
|
120
|
+
return tools, backend
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
The host supplies `CallerContext` from trusted request state and calls `backend.aclose()` at shutdown. `Cleanup.RESET` permits warm reuse while removing state after each tool call; the router's stronger default disposal policy also works. CodeAct uses exclusive admission so the next call waits for the previous call's cleanup.
|
|
124
|
+
|
|
125
|
+
The guest has a reduced standard library: `json`, `math` and `re` are available; `datetime`, `statistics`, `pickle` and `__future__` are absent. Future imports fail. Programs execute statements and must print results; a final expression is not echoed. `RUNTIME_INSTRUCTIONS` describes this profile for the model. There is no shell, package installation, writable host filesystem, file-transfer channel or host-tool registration.
|
|
126
|
+
|
|
127
|
+
## Network policy
|
|
128
|
+
|
|
129
|
+
`CLOSED` is the default. For HTTP access, request `egress=Egress.ALLOWLIST` and supply exact hosts in `egress_allow`. Each host permits HTTP on port 80 and HTTPS on port 443 at all paths through the guest's `http_get(url)` and `http_post(url, body=..., content_type=...)` helpers. Raw sockets are unavailable. The pinned SDK always refuses CONNECT and TRACE. Wildcards, unrestricted egress, method-scoped rules and attached-identity rules are refused rather than weakened. Named hosts remain allowed after reset.
|
|
130
|
+
|
|
131
|
+
HTTP originates in the worker on the host's network. The host must choose destinations accordingly: allowing loopback or an internal service makes it reachable, and an allowlisted hostname is not an IP-address or DNS-rebinding filter. The worker receives only platform runtime/cache/locale variables, not application credentials or proxy configuration, and the guest does not inherit the worker environment. No platform identity is attached by the adapter.
|
|
132
|
+
|
|
133
|
+
## Budgets and failure behavior
|
|
134
|
+
|
|
135
|
+
`HyperlightSandboxConfig` provides these limits:
|
|
136
|
+
|
|
137
|
+
| Field | Default | Meaning |
|
|
138
|
+
| --- | --- | --- |
|
|
139
|
+
| `startup_timeout` | 30 seconds | Acquisition queue and cold guest preparation |
|
|
140
|
+
| `cleanup_timeout` | 3 seconds | Additional allowance to terminate, reap and close a worker |
|
|
141
|
+
| `max_code_bytes` | 1 MiB | UTF-8 source bytes, at most 10 MiB |
|
|
142
|
+
| `max_output_bytes` | 1 MiB | Combined UTF-8 stdout/stderr, at most 16 MiB |
|
|
143
|
+
| `max_worker_memory_bytes` | Windows: 1.5 GiB; Linux: 3 GiB | Per-worker-tree Windows committed-memory or Linux cgroup-accounted memory ceiling, at most 16 GiB; Linux rounds down to a whole page and disables swap |
|
|
144
|
+
| `linux_cgroup_root` | `None` | Linux uses `/sys/fs/cgroup/maf-sandbox-hyperlight` unless an absolute delegated path is supplied; unused on Windows |
|
|
145
|
+
|
|
146
|
+
The fixed guest heap and stack are 400 MiB and 200 MiB. `run_code(timeout=...)` and `reset(timeout=...)` include their queue time. `SandboxQueuedTimeout` means no operation was submitted and the current guest remains usable. A started operation exceeding its deadline raises `TimeoutError`; cancellation propagates after terminating the worker. Cleanup may add `cleanup_timeout` to the operation budget. Oversized native results raise `HyperlightOutputLimitExceeded`. Protocol errors and worker crashes raise `HyperlightWorkerError`. These failures retire the sandbox; a later acquire prepares a new worker and identity.
|
|
147
|
+
|
|
148
|
+
Native output is buffered before its byte limit can be checked. The worker's kernel memory ceiling bounds that allocation; the deadline bounds endless output. Linux cgroups account charged memory, not virtual-address reservations, and may terminate the group on OOM. The parent separately bounds retained worker diagnostics to 64 KiB while draining the pipe. Lowering the memory limit too far can make cold preparation fail; the measured KVM startup exceeded 1.5 GiB, so Linux has a larger default.
|
|
149
|
+
|
|
150
|
+
Disposal is idempotent and returns `DisposalFailure` when cleanup cannot be confirmed. Failed targets stay registered for retry. Cancellation propagates after the active worker's bounded cleanup attempt finishes, without starting another target; unreported targets remain registered for retry. `dispose_scope` sweeps all agents, kinds and call IDs in the owner's matching scope/conversation. `aclose()` raises on incomplete cleanup and only disposes targets created by that backend object.
|
|
151
|
+
|
|
152
|
+
## Validation and follow-ups
|
|
153
|
+
|
|
154
|
+
The ordinary tests use deterministic workers and real subprocess pipes. Windows tests exercise job memory limits and abrupt owner death without requiring WHP. Linux kernel tests exercise cgroup OOM, process-tree termination and owner-lock retention without requiring KVM. In a repository checkout, run those Linux tests using `sudo python3 scripts/check_hyperlight_linux.py --python "$PWD/.venv/bin/python"`; the helper creates only a temporary test subtree and drops privileges before running pytest.
|
|
155
|
+
|
|
156
|
+
Run the real guest suite separately and serially. On Windows:
|
|
157
|
+
|
|
158
|
+
```powershell
|
|
159
|
+
$env:MAF_HYPERLIGHT_LIVE = "1"
|
|
160
|
+
uv run pytest -q packages/maf-sandbox-hyperlight/tests/test_hyperlight_live.py
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
On Linux, `sudo python3 scripts/check_hyperlight_linux.py --live --python "$PWD/.venv/bin/python"` provisions a temporary test subtree and runs the real guest suite as the calling user. Alternatively, use an already delegated host as described above, set `MAF_HYPERLIGHT_LIVE=1` and `MAF_HYPERLIGHT_CGROUP_ROOT` to the delegated root, and run the same pytest file. The HTTP-policy test needs permission to bind the available loopback port 80. The local WSL2 record ran the other nine guest scenarios unprivileged and the HTTP test with that binding permission.
|
|
164
|
+
|
|
165
|
+
The live suite validates results, errors and reuse, reset, absent host environment and writable file channels, queued/program timeouts, cancellation, output limits, HTTP enforcement, selective disposal, scope purge and CodeAct under both router selection modes. CI runs portable tests and dedicated Linux/Windows worker enforcement jobs. The Linux job also runs the real KVM guest suite as an unprivileged host with KVM access and delegated cgroups, recording its environment and exact dependency versions; unavailable KVM or a failed guest scenario fails the job. The local WSL2 guest measurement used Ubuntu 24.04, kernel `6.18.40.1-microsoft-standard-WSL2`, CPython 3.12.3. [Native Linux CI](https://github.com/sokolaidev/maf-extensions/actions/runs/34791208333/job/103815669959) passed all ten guest scenarios on Ubuntu 24.04.5 LTS, kernel `6.17.0-1022-azure`, x86-64 and CPython 3.13.15 with the exact 0.7.0 trio. MSHV, ARM64, ACA and AKS were not measured. MSHV, ARM64 and custom guests remain refused.
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
# maf-sandbox-hyperlight
|
|
2
|
+
|
|
3
|
+
[](https://pypi.org/project/maf-sandbox-hyperlight/) [](https://pypi.org/project/maf-sandbox-hyperlight/) [](https://github.com/sokolaidev/maf-extensions/blob/main/packages/maf-sandbox-hyperlight/LICENSE)
|
|
4
|
+
|
|
5
|
+
> **Experimental.** This package warns on import with `MafSandboxHyperlightExperimentalWarning`. Releases before 1.0 may change or remove APIs without notice.
|
|
6
|
+
|
|
7
|
+
Run Python statements in Hyperlight microVMs through the `maf-sandbox` protocol. This backend supports `RUN_CODE` and `SNAPSHOT`, including CodeAct without file channels. It is experimental and has not yet been released.
|
|
8
|
+
|
|
9
|
+
## Requirements
|
|
10
|
+
|
|
11
|
+
Windows x86-64 with Windows Hypervisor Platform, or Linux x86-64 with glibc 2.28 or newer, KVM and a delegated cgroup v2 subtree. Host CPython versions 3.12 through 3.14 are supported by the pinned wheels. The measured configurations are Windows 11 / WHP / host CPython 3.13, Ubuntu 24.04 under WSL2 / KVM / host CPython 3.12, and native Ubuntu 24.04 / KVM / host CPython 3.13, using the exact matched `hyperlight-sandbox`, `hyperlight-sandbox-backend-wasm` and `hyperlight-sandbox-python-guest` 0.7.0 wheels. The guest is CPython 3.14 compiled to WebAssembly. Other operating systems, architectures, hypervisors, custom guests, images and guest working directories are refused. Linux hosts exposing `/dev/mshv` are refused until that family is validated.
|
|
12
|
+
|
|
13
|
+
Each sandbox has a dedicated worker process. The adapter sets `HYPERLIGHT_MAX_SURROGATES=0` inside that process, initializes the platform, warms the packaged guest and takes its initial snapshot during acquire. Windows retains the WHP library handle and uses a job to bound committed memory and terminate the worker tree. Linux verifies KVM VM creation and uses cgroup memory enforcement with an independent lifetime watcher. Linux forwards only the exact environment names `PATH`, `HOME`, `XDG_CACHE_HOME`, `TMPDIR`, `LANG` and `LC_ALL`; Windows matches its system/runtime environment names case-insensitively. The SDK materializes the packaged guest in its ordinary local application cache; no host directory is exposed to guest code.
|
|
14
|
+
|
|
15
|
+
One host process owns this backend within its ownership namespace. Windows uses a machine-wide named event; Linux holds `/run/lock/maf-sandbox-hyperlight.lock` open with an exclusive lock. New lock files are empty, readable by every host user and have no write permissions, regardless of the creating process's umask. The final path is published atomically only after those permissions are ready, without replacing an existing lock. Ordinary Python fork children release their inherited owner descriptor; ownership remains with the original host and its lifetime watchers. Route acquire, execution and purge requests to that process. A second process refuses acquire and returns an unclean disposal result. Ownership lasts until the host exits, including after `aclose()`; Linux watchers retain the lock until old worker trees are gone. Backend objects within the owner share the same key/kind registry. Do not unlink the lock file or use separate mount/PID/cgroup namespaces to route one logical backend across owners. Replicated containers and cross-machine routing require additional deployment work.
|
|
16
|
+
|
|
17
|
+
### Linux and WSL2 setup
|
|
18
|
+
|
|
19
|
+
The host user needs read/write access to `/dev/kvm`. WSL2 needs hardware virtualization exposed by Windows, KVM support enabled in its Linux kernel, and nested virtualization enabled on a supported Windows host; see the [WSL configuration reference](https://learn.microsoft.com/en-us/windows/wsl/wsl-config#configuration-settings-for-wslconfig). Check the device and follow the [Hyperlight KVM prerequisites](https://hyperlight.org/guides/getting-started/#prerequisites). Acquire attempts actual VM creation, so a device node alone does not satisfy admission.
|
|
20
|
+
|
|
21
|
+
The operator supplies a writable cgroup v2 root with the memory controller enabled for children, `memory.swap.max`, `memory.oom.group`, `cgroup.kill` and pidfd support. The default root is `/sys/fs/cgroup/maf-sandbox-hyperlight`; set `HyperlightSandboxConfig(linux_cgroup_root="/sys/fs/cgroup/your-delegated-subtree")` when a service manager delegates another path. Keep the application in a leaf beneath that subtree so the root has no processes. The application needs permission to create worker groups and migrate its workers at their common ancestor. The library never mounts cgroups, enables ancestor controllers or elevates privileges.
|
|
22
|
+
|
|
23
|
+
For local development, on a host whose root cgroup already offers the memory controller, an operator can prepare the subtree and launch a host as the calling user. The calling user must already have KVM device access; replace the interpreter and application arguments with their absolute paths:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
sudo sh -c '
|
|
27
|
+
set -eu
|
|
28
|
+
root=/sys/fs/cgroup/maf-sandbox-hyperlight
|
|
29
|
+
mkdir -p "$root/host"
|
|
30
|
+
printf +memory > "$root/cgroup.subtree_control"
|
|
31
|
+
chown "$SUDO_UID:$SUDO_GID" "$root" "$root/cgroup.procs"
|
|
32
|
+
printf "%s" "$$" > "$root/host/cgroup.procs"
|
|
33
|
+
exec setpriv --reuid "$SUDO_UID" --regid "$SUDO_GID" --init-groups -- "$@"
|
|
34
|
+
' sh /absolute/path/to/.venv/bin/python /absolute/path/to/app.py
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
A supervisor starts in a separate process session and inherits the ownership lock before creating the worker cgroup or process. It configures `memory.max`, zero swap allowance and group OOM enforcement; a trusted bootstrap joins that cgroup before executing the worker command. The supervisor holds pidfds for the host and worker and remains outside the worker's memory group. Host exit, worker exit or an explicit close triggers worker termination and `cgroup.kill`, including descendants that change process session. Cleanup also covers startup before the bootstrap joins the group, waits for the kernel's empty-group indication and removes only that worker's cgroup. The supervisor is trusted host infrastructure and must remain running until cleanup completes. A cleanup timeout or unexpected supervisor exit reports an unclean result; ownership remains held while the supervisor retries cleanup. Service managers should own the delegated subtree's lifetime as well. Missing delegation or enforcement controls refuses acquisition; there is no fallback to an unbounded worker.
|
|
38
|
+
|
|
39
|
+
## Direct execution
|
|
40
|
+
|
|
41
|
+
Install this package when its first release is available; the dependency pins select the compatible SDK and guest automatically. Repository development uses `uv sync`.
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
import asyncio
|
|
45
|
+
|
|
46
|
+
from maf_sandbox import Capability, SandboxKey, SandboxSpec
|
|
47
|
+
from maf_sandbox_hyperlight import HyperlightSandboxBackend
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
async def main() -> None:
|
|
51
|
+
backend = HyperlightSandboxBackend()
|
|
52
|
+
key = SandboxKey(scope="user-1", thread_id="thread-1", agent_id="analyst")
|
|
53
|
+
spec = SandboxSpec(
|
|
54
|
+
kind="python",
|
|
55
|
+
work_dir=None,
|
|
56
|
+
requires=frozenset({Capability.RUN_CODE}),
|
|
57
|
+
)
|
|
58
|
+
try:
|
|
59
|
+
sandbox = await backend.acquire(key, spec)
|
|
60
|
+
result = await sandbox.run_code("answer = 6 * 7\nprint(answer)", timeout=5)
|
|
61
|
+
print(result.stdout) # 42
|
|
62
|
+
await sandbox.reset(timeout=5)
|
|
63
|
+
finally:
|
|
64
|
+
await backend.aclose()
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
asyncio.run(main())
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`acquire` reuses a live sandbox for the complete `SandboxKey` and kind. A different network policy, execution contract or resource configuration requires disposal first. `reset` restores the initial runtime state and rotates `instance_id`; disposal with an older ID cannot remove its replacement. Ordinary Python exceptions return a nonzero `ExecResult` and leave the runtime usable. Explicit reset is what removes accumulated Python state.
|
|
71
|
+
|
|
72
|
+
## CodeAct
|
|
73
|
+
|
|
74
|
+
Install `maf-sandbox-codeact` alongside this backend and explicitly select `CodeactRuntime(RUNTIME_INSTRUCTIONS)`. Its default exec variant requires capabilities this backend does not provide.
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
from maf_sandbox import CallerContext, Cleanup, SandboxRouter
|
|
78
|
+
from maf_sandbox_codeact import CodeactRuntime, make_codeact_tools
|
|
79
|
+
from maf_sandbox_hyperlight import RUNTIME_INSTRUCTIONS, HyperlightSandboxBackend
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def tools_for(context: CallerContext):
|
|
83
|
+
backend = HyperlightSandboxBackend()
|
|
84
|
+
router = SandboxRouter([backend], min_cleanup=Cleanup.RESET)
|
|
85
|
+
tools = make_codeact_tools(
|
|
86
|
+
router,
|
|
87
|
+
"analyst",
|
|
88
|
+
context,
|
|
89
|
+
runtime=CodeactRuntime(RUNTIME_INSTRUCTIONS),
|
|
90
|
+
)
|
|
91
|
+
return tools, backend
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The host supplies `CallerContext` from trusted request state and calls `backend.aclose()` at shutdown. `Cleanup.RESET` permits warm reuse while removing state after each tool call; the router's stronger default disposal policy also works. CodeAct uses exclusive admission so the next call waits for the previous call's cleanup.
|
|
95
|
+
|
|
96
|
+
The guest has a reduced standard library: `json`, `math` and `re` are available; `datetime`, `statistics`, `pickle` and `__future__` are absent. Future imports fail. Programs execute statements and must print results; a final expression is not echoed. `RUNTIME_INSTRUCTIONS` describes this profile for the model. There is no shell, package installation, writable host filesystem, file-transfer channel or host-tool registration.
|
|
97
|
+
|
|
98
|
+
## Network policy
|
|
99
|
+
|
|
100
|
+
`CLOSED` is the default. For HTTP access, request `egress=Egress.ALLOWLIST` and supply exact hosts in `egress_allow`. Each host permits HTTP on port 80 and HTTPS on port 443 at all paths through the guest's `http_get(url)` and `http_post(url, body=..., content_type=...)` helpers. Raw sockets are unavailable. The pinned SDK always refuses CONNECT and TRACE. Wildcards, unrestricted egress, method-scoped rules and attached-identity rules are refused rather than weakened. Named hosts remain allowed after reset.
|
|
101
|
+
|
|
102
|
+
HTTP originates in the worker on the host's network. The host must choose destinations accordingly: allowing loopback or an internal service makes it reachable, and an allowlisted hostname is not an IP-address or DNS-rebinding filter. The worker receives only platform runtime/cache/locale variables, not application credentials or proxy configuration, and the guest does not inherit the worker environment. No platform identity is attached by the adapter.
|
|
103
|
+
|
|
104
|
+
## Budgets and failure behavior
|
|
105
|
+
|
|
106
|
+
`HyperlightSandboxConfig` provides these limits:
|
|
107
|
+
|
|
108
|
+
| Field | Default | Meaning |
|
|
109
|
+
| --- | --- | --- |
|
|
110
|
+
| `startup_timeout` | 30 seconds | Acquisition queue and cold guest preparation |
|
|
111
|
+
| `cleanup_timeout` | 3 seconds | Additional allowance to terminate, reap and close a worker |
|
|
112
|
+
| `max_code_bytes` | 1 MiB | UTF-8 source bytes, at most 10 MiB |
|
|
113
|
+
| `max_output_bytes` | 1 MiB | Combined UTF-8 stdout/stderr, at most 16 MiB |
|
|
114
|
+
| `max_worker_memory_bytes` | Windows: 1.5 GiB; Linux: 3 GiB | Per-worker-tree Windows committed-memory or Linux cgroup-accounted memory ceiling, at most 16 GiB; Linux rounds down to a whole page and disables swap |
|
|
115
|
+
| `linux_cgroup_root` | `None` | Linux uses `/sys/fs/cgroup/maf-sandbox-hyperlight` unless an absolute delegated path is supplied; unused on Windows |
|
|
116
|
+
|
|
117
|
+
The fixed guest heap and stack are 400 MiB and 200 MiB. `run_code(timeout=...)` and `reset(timeout=...)` include their queue time. `SandboxQueuedTimeout` means no operation was submitted and the current guest remains usable. A started operation exceeding its deadline raises `TimeoutError`; cancellation propagates after terminating the worker. Cleanup may add `cleanup_timeout` to the operation budget. Oversized native results raise `HyperlightOutputLimitExceeded`. Protocol errors and worker crashes raise `HyperlightWorkerError`. These failures retire the sandbox; a later acquire prepares a new worker and identity.
|
|
118
|
+
|
|
119
|
+
Native output is buffered before its byte limit can be checked. The worker's kernel memory ceiling bounds that allocation; the deadline bounds endless output. Linux cgroups account charged memory, not virtual-address reservations, and may terminate the group on OOM. The parent separately bounds retained worker diagnostics to 64 KiB while draining the pipe. Lowering the memory limit too far can make cold preparation fail; the measured KVM startup exceeded 1.5 GiB, so Linux has a larger default.
|
|
120
|
+
|
|
121
|
+
Disposal is idempotent and returns `DisposalFailure` when cleanup cannot be confirmed. Failed targets stay registered for retry. Cancellation propagates after the active worker's bounded cleanup attempt finishes, without starting another target; unreported targets remain registered for retry. `dispose_scope` sweeps all agents, kinds and call IDs in the owner's matching scope/conversation. `aclose()` raises on incomplete cleanup and only disposes targets created by that backend object.
|
|
122
|
+
|
|
123
|
+
## Validation and follow-ups
|
|
124
|
+
|
|
125
|
+
The ordinary tests use deterministic workers and real subprocess pipes. Windows tests exercise job memory limits and abrupt owner death without requiring WHP. Linux kernel tests exercise cgroup OOM, process-tree termination and owner-lock retention without requiring KVM. In a repository checkout, run those Linux tests using `sudo python3 scripts/check_hyperlight_linux.py --python "$PWD/.venv/bin/python"`; the helper creates only a temporary test subtree and drops privileges before running pytest.
|
|
126
|
+
|
|
127
|
+
Run the real guest suite separately and serially. On Windows:
|
|
128
|
+
|
|
129
|
+
```powershell
|
|
130
|
+
$env:MAF_HYPERLIGHT_LIVE = "1"
|
|
131
|
+
uv run pytest -q packages/maf-sandbox-hyperlight/tests/test_hyperlight_live.py
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
On Linux, `sudo python3 scripts/check_hyperlight_linux.py --live --python "$PWD/.venv/bin/python"` provisions a temporary test subtree and runs the real guest suite as the calling user. Alternatively, use an already delegated host as described above, set `MAF_HYPERLIGHT_LIVE=1` and `MAF_HYPERLIGHT_CGROUP_ROOT` to the delegated root, and run the same pytest file. The HTTP-policy test needs permission to bind the available loopback port 80. The local WSL2 record ran the other nine guest scenarios unprivileged and the HTTP test with that binding permission.
|
|
135
|
+
|
|
136
|
+
The live suite validates results, errors and reuse, reset, absent host environment and writable file channels, queued/program timeouts, cancellation, output limits, HTTP enforcement, selective disposal, scope purge and CodeAct under both router selection modes. CI runs portable tests and dedicated Linux/Windows worker enforcement jobs. The Linux job also runs the real KVM guest suite as an unprivileged host with KVM access and delegated cgroups, recording its environment and exact dependency versions; unavailable KVM or a failed guest scenario fails the job. The local WSL2 guest measurement used Ubuntu 24.04, kernel `6.18.40.1-microsoft-standard-WSL2`, CPython 3.12.3. [Native Linux CI](https://github.com/sokolaidev/maf-extensions/actions/runs/34791208333/job/103815669959) passed all ten guest scenarios on Ubuntu 24.04.5 LTS, kernel `6.17.0-1022-azure`, x86-64 and CPython 3.13.15 with the exact 0.7.0 trio. MSHV, ARM64, ACA and AKS were not measured. MSHV, ARM64 and custom guests remain refused.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "maf-sandbox-hyperlight"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Hyperlight Python micro-VMs on Windows WHP and Linux KVM with bounded execution and snapshot reset."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.12,<3.15"
|
|
7
|
+
license = "MIT"
|
|
8
|
+
license-files = ["LICENSE"]
|
|
9
|
+
keywords = [
|
|
10
|
+
"hyperlight",
|
|
11
|
+
"microvm",
|
|
12
|
+
"sandbox",
|
|
13
|
+
"agent-framework",
|
|
14
|
+
"microsoft-agent-framework",
|
|
15
|
+
"isolation",
|
|
16
|
+
]
|
|
17
|
+
classifiers = [
|
|
18
|
+
"Development Status :: 4 - Beta",
|
|
19
|
+
"Intended Audience :: Developers",
|
|
20
|
+
"Typing :: Typed",
|
|
21
|
+
"Programming Language :: Python :: 3",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Programming Language :: Python :: 3.14",
|
|
25
|
+
"Operating System :: Microsoft :: Windows",
|
|
26
|
+
"Operating System :: POSIX :: Linux",
|
|
27
|
+
"Topic :: Software Development :: Testing",
|
|
28
|
+
]
|
|
29
|
+
dependencies = [
|
|
30
|
+
"maf-sandbox>=0.40.0,<0.41",
|
|
31
|
+
"hyperlight-sandbox==0.7.0",
|
|
32
|
+
"hyperlight-sandbox-backend-wasm==0.7.0; (sys_platform == 'win32' and platform_machine == 'AMD64') or (sys_platform == 'linux' and platform_machine == 'x86_64')",
|
|
33
|
+
"hyperlight-sandbox-python-guest==0.7.0; (sys_platform == 'win32' and platform_machine == 'AMD64') or (sys_platform == 'linux' and platform_machine == 'x86_64')",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[[project.authors]]
|
|
37
|
+
name = "SOKOLAI BV"
|
|
38
|
+
email = "info@sokolai.com"
|
|
39
|
+
|
|
40
|
+
[project.urls]
|
|
41
|
+
Homepage = "https://www.sokol.ai"
|
|
42
|
+
Source = "https://github.com/sokolaidev/maf-extensions"
|
|
43
|
+
Issues = "https://github.com/sokolaidev/maf-extensions/issues"
|
|
44
|
+
|
|
45
|
+
[tool.uv.sources.maf-sandbox]
|
|
46
|
+
workspace = true
|
|
47
|
+
|
|
48
|
+
[tool.uv.build-backend]
|
|
49
|
+
module-name = "maf_sandbox_hyperlight"
|
|
50
|
+
module-root = "src"
|
|
51
|
+
|
|
52
|
+
[tool.ruff]
|
|
53
|
+
line-length = 100
|
|
54
|
+
target-version = "py312"
|
|
55
|
+
|
|
56
|
+
[tool.ruff.lint]
|
|
57
|
+
extend-select = [
|
|
58
|
+
"I",
|
|
59
|
+
"UP",
|
|
60
|
+
"D100",
|
|
61
|
+
"D101",
|
|
62
|
+
"D103",
|
|
63
|
+
"D104",
|
|
64
|
+
"E501",
|
|
65
|
+
"W505",
|
|
66
|
+
"TD",
|
|
67
|
+
"FIX",
|
|
68
|
+
"ERA001",
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
[tool.ruff.lint.per-file-ignores]
|
|
72
|
+
"tests/**" = [
|
|
73
|
+
"D101",
|
|
74
|
+
"D103",
|
|
75
|
+
"E501",
|
|
76
|
+
"W505",
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
[tool.ruff.lint.pycodestyle]
|
|
80
|
+
max-doc-length = 100
|
|
81
|
+
|
|
82
|
+
[tool.pyright]
|
|
83
|
+
include = ["src"]
|
|
84
|
+
typeCheckingMode = "strict"
|
|
85
|
+
pythonPlatform = "All"
|
|
86
|
+
|
|
87
|
+
[tool.pytest.ini_options]
|
|
88
|
+
testpaths = ["tests"]
|
|
89
|
+
|
|
90
|
+
[build-system]
|
|
91
|
+
requires = ["uv_build>=0.11.24,<0.12.0"]
|
|
92
|
+
build-backend = "uv_build"
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "maf-sandbox-hyperlight"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Hyperlight Python micro-VMs on Windows WHP and Linux KVM with bounded execution and snapshot reset."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.12,<3.15"
|
|
7
|
+
authors = [{ name = "SOKOLAI BV", email = "info@sokolai.com" }]
|
|
8
|
+
license = "MIT"
|
|
9
|
+
license-files = ["LICENSE"]
|
|
10
|
+
keywords = [
|
|
11
|
+
"hyperlight",
|
|
12
|
+
"microvm",
|
|
13
|
+
"sandbox",
|
|
14
|
+
"agent-framework",
|
|
15
|
+
"microsoft-agent-framework",
|
|
16
|
+
"isolation",
|
|
17
|
+
]
|
|
18
|
+
classifiers = [
|
|
19
|
+
"Development Status :: 4 - Beta",
|
|
20
|
+
"Intended Audience :: Developers",
|
|
21
|
+
"Typing :: Typed",
|
|
22
|
+
"Programming Language :: Python :: 3",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Programming Language :: Python :: 3.13",
|
|
25
|
+
"Programming Language :: Python :: 3.14",
|
|
26
|
+
"Operating System :: Microsoft :: Windows",
|
|
27
|
+
"Operating System :: POSIX :: Linux",
|
|
28
|
+
"Topic :: Software Development :: Testing",
|
|
29
|
+
]
|
|
30
|
+
dependencies = [
|
|
31
|
+
"maf-sandbox>=0.40.0,<0.41",
|
|
32
|
+
"hyperlight-sandbox==0.7.0",
|
|
33
|
+
"hyperlight-sandbox-backend-wasm==0.7.0; (sys_platform == 'win32' and platform_machine == 'AMD64') or (sys_platform == 'linux' and platform_machine == 'x86_64')",
|
|
34
|
+
"hyperlight-sandbox-python-guest==0.7.0; (sys_platform == 'win32' and platform_machine == 'AMD64') or (sys_platform == 'linux' and platform_machine == 'x86_64')",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[project.urls]
|
|
38
|
+
Homepage = "https://www.sokol.ai"
|
|
39
|
+
Source = "https://github.com/sokolaidev/maf-extensions"
|
|
40
|
+
Issues = "https://github.com/sokolaidev/maf-extensions/issues"
|
|
41
|
+
|
|
42
|
+
[tool.uv.sources]
|
|
43
|
+
maf-sandbox = { workspace = true }
|
|
44
|
+
|
|
45
|
+
[tool.uv.build-backend]
|
|
46
|
+
module-name = "maf_sandbox_hyperlight"
|
|
47
|
+
module-root = "src"
|
|
48
|
+
|
|
49
|
+
[tool.ruff]
|
|
50
|
+
line-length = 100
|
|
51
|
+
target-version = "py312"
|
|
52
|
+
|
|
53
|
+
[tool.ruff.lint]
|
|
54
|
+
extend-select = ["I", "UP", "D100", "D101", "D103", "D104", "E501", "W505", "TD", "FIX", "ERA001"]
|
|
55
|
+
|
|
56
|
+
[tool.ruff.lint.per-file-ignores]
|
|
57
|
+
# ruff resolves [tool.ruff] per file by the NEAREST ancestor pyproject.toml that has one, so
|
|
58
|
+
# this package carries its own copy rather than inheriting one from the workspace root.
|
|
59
|
+
"tests/**" = ["D101", "D103", "E501", "W505"]
|
|
60
|
+
|
|
61
|
+
[tool.ruff.lint.pycodestyle]
|
|
62
|
+
max-doc-length = 100
|
|
63
|
+
|
|
64
|
+
# Self-contained type checking, scoped to this package — strict. `tests/` stays out (fakes
|
|
65
|
+
# for the native worker seam, not signal for a strict checker).
|
|
66
|
+
[tool.pyright]
|
|
67
|
+
include = ["src"]
|
|
68
|
+
typeCheckingMode = "strict"
|
|
69
|
+
pythonPlatform = "All"
|
|
70
|
+
|
|
71
|
+
[tool.pytest.ini_options]
|
|
72
|
+
testpaths = ["tests"]
|
|
73
|
+
|
|
74
|
+
[build-system]
|
|
75
|
+
requires = ["uv_build>=0.11.24,<0.12.0"]
|
|
76
|
+
build-backend = "uv_build"
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""Hyperlight's packaged Python guest as a runtime-only maf-sandbox backend."""
|
|
2
|
+
|
|
3
|
+
import warnings as _warnings
|
|
4
|
+
|
|
5
|
+
from ._backend import BACKEND_NAME, RUNTIME_INSTRUCTIONS, HyperlightSandboxBackend
|
|
6
|
+
from ._config import HyperlightSandboxConfig
|
|
7
|
+
from ._wire import HyperlightOutputLimitExceeded, HyperlightWorkerError
|
|
8
|
+
|
|
9
|
+
__all__ = [
|
|
10
|
+
"BACKEND_NAME",
|
|
11
|
+
"RUNTIME_INSTRUCTIONS",
|
|
12
|
+
"HyperlightSandboxBackend",
|
|
13
|
+
"HyperlightSandboxConfig",
|
|
14
|
+
"HyperlightOutputLimitExceeded",
|
|
15
|
+
"HyperlightWorkerError",
|
|
16
|
+
"MafSandboxHyperlightExperimentalWarning",
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class MafSandboxHyperlightExperimentalWarning(UserWarning):
|
|
21
|
+
"""Warning category for maf-sandbox-hyperlight's experimental-package notice."""
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _warn_experimental() -> None:
|
|
25
|
+
try:
|
|
26
|
+
_warnings.warn(
|
|
27
|
+
"maf_sandbox_hyperlight is experimental and may change or be removed in future "
|
|
28
|
+
"versions without notice.",
|
|
29
|
+
category=MafSandboxHyperlightExperimentalWarning,
|
|
30
|
+
stacklevel=2,
|
|
31
|
+
)
|
|
32
|
+
except MafSandboxHyperlightExperimentalWarning:
|
|
33
|
+
# An informational notice must not prevent importing under -W error.
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
_warn_experimental()
|