Repository navigation
feat(sandbox): add a Tenki Sandbox VM sandbox provider - #187
Conversation
Adds `tenki` as a built-in VM sandbox provider behind a `tenki` extra. Each sandbox is one Tenki VM running agent-env's docker-in-VM flows: commands run as root via privileged exec, objects go over exec stdin, and exposed ports get public HTTPS URLs. Allowlist egress is enforced outside the VM and set at create, so bytes the policy doesn't cover go over stdin. Config: api_key (required), base_url, snapshot_id or image, min_disk_gb.
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
| except asyncio.CancelledError: | ||
| task.add_done_callback(terminate_orphan) | ||
| raise |
There was a problem hiding this comment.
Cancelled deploy leaves VM running
Cancelling a CLI deploy during client.create makes _create_or_reclaim attach a callback and immediately raise cancellation. When asyncio.run shuts down, it cancels the unfinished create. The callback then starts cleanup that shutdown does not wait for. The loop can close while client.list is still waiting, leaving the VM running until its maximum lifetime.
Wait for creation and cleanup during cancellation, with a bounded wait, rather than relying only on the callback.
Knowledge Base Used: Stop Container Leaks During Cancelled Modal Deploys
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agent_env/providers/sandbox_providers/tenki/provider.py
Line: 368-370
Comment:
**Cancelled deploy leaves VM running**
Cancelling a CLI deploy during `client.create` makes `_create_or_reclaim` attach a callback and immediately raise cancellation. When `asyncio.run` shuts down, it cancels the unfinished create. The callback then starts cleanup that shutdown does not wait for. The loop can close while `client.list` is still waiting, leaving the VM running until its maximum lifetime.
Wait for creation and cleanup during cancellation, with a bounded wait, rather than relying only on the callback.
**Knowledge Base Used:** [Stop Container Leaks During Cancelled Modal Deploys](https://app.greptile.com/scale-ai/-/custom-context/knowledge-base/scaleapi/agentenv-framework/-/reverts/incident-mitigation_171-20261013-cancelled-container-leaks-9ee55f4.md)
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| becomes a /32. A policy with IPv6 or malformed entries is refused with `NetworkPolicyUnsupportedError` before | ||
| anything is created, and a fallback chain skips to its next provider. Tenki applies the policy outside the VM, so |
There was a problem hiding this comment.
Docs overstate hostname checks
The README promises that all malformed entries raise NetworkPolicyUnsupportedError before creation. But supports_network_policy only checks CIDRs and entry counts. A malformed hostname passes those checks and reaches client.create, so users can receive an SDK or API error instead of the promised early rejection.
Narrow the wording to malformed CIDRs, or add hostname checks and tests.
| becomes a /32. A policy with IPv6 or malformed entries is refused with `NetworkPolicyUnsupportedError` before | |
| anything is created, and a fallback chain skips to its next provider. Tenki applies the policy outside the VM, so | |
| becomes a /32. A policy with IPv6 or malformed CIDRs is refused with `NetworkPolicyUnsupportedError` before | |
| anything is created, and a fallback chain skips to its next provider. Tenki applies the policy outside the VM, so |
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agent_env/providers/sandbox_providers/tenki/README.md
Line: 111-112
Comment:
**Docs overstate hostname checks**
The README promises that all malformed entries raise `NetworkPolicyUnsupportedError` before creation. But `supports_network_policy` only checks CIDRs and entry counts. A malformed hostname passes those checks and reaches `client.create`, so users can receive an SDK or API error instead of the promised early rejection.
Narrow the wording to malformed CIDRs, or add hostname checks and tests.
```suggestion
becomes a /32. A policy with IPv6 or malformed CIDRs is refused with `NetworkPolicyUnsupportedError` before
anything is created, and a fallback chain skips to its next provider. Tenki applies the policy outside the VM, so
```
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.| if not isinstance(queue, asyncio.Queue) or not isinstance(done, asyncio.Event): | ||
| return False | ||
| while not done.is_set() and queue.qsize() > _STDIN_QUEUE_LIMIT: | ||
| await asyncio.sleep(0.005) |
There was a problem hiding this comment.
The new queue-drain loop uses an inline 0.005 delay. The repository requires magic numbers to be stored as class or instance variables with descriptive names. Move this delay to a named class variable so its unit and purpose are clear. This repository requirement must be satisfied before merging.
Rule Used: Store magic numbers as class or instance variables with descriptive names rather than using them inline in the code. (source)
Learned From
scaleapi/scaleapi#126388
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agent_env/providers/sandbox_providers/tenki/sandbox.py
Line: 274
Comment:
**Upload delay has no name**
The new queue-drain loop uses an inline `0.005` delay. The repository requires magic numbers to be stored as class or instance variables with descriptive names. Move this delay to a named class variable so its unit and purpose are clear. This repository requirement must be satisfied before merging.
**Rule Used:** Store magic numbers as class or instance variables with descriptive names rather than using them inline in the code. ([source](https://app.greptile.com/scale-ai/-/custom-context?memory=002e0051-41ad-46c1-9098-47433c580150))
**Learned From**
[scaleapi/scaleapi#126388](https://github.com/scaleapi/scaleapi/pull/126388)
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
What and why
Closes #186.
Adds
tenkias a built-in sandbox provider behind atenkiextra, so environments and agents can run on Tenki Sandbox VMs. Each sandbox is one VM with Docker inside, so agent-env's docker-in-VM flows run unchanged: the gateway's docker-compose, an agent'sdocker run, image loading and artifact collection.[sandbox.providers.tenki.config]takesapi_key(required,env:/secret:),base_url,snapshot_idorimage, andmin_disk_gb. No new environment variables.timeoutis the VM's hard max lifetime.push_object_over_stdin. A dropped stream is exit -1, whichexec_scriptretries.EGRESS_HOSTSis*.sb.tenki.shand*.us.sb.tenki.sh.get_sandboxrestores ports and the applied policy. A VM whose setup fails, whose create is cancelled, or whose create response is lost is terminated.Core changes are the registry entry and the
--sandboxhelp text, plus the shared test and doc touchpoints a built-in provider gets.How it was tested
make unit-test: all pass, including the newtenki_*tests (offline, against SDK stand-ins).check_plugin_api.py --base origin/main: no break to the plugin surface.tenki_sandbox_smoke_test.py: 2 passed (nested Docker, public port, upload over stdin, reconnect, allowlisted VM).agent-env run hello --sandbox tenki: passed, about 8 s from a snapshot.deploy_env(gateway and service DB),load_artifact,deploy_agent,prompt_agentandrubrics_verifier, using a Claude agent with the env's MCP tools: 5 parallel runs passed in about 70 s, judge score 1.0.agent-env up): the same agent task started from the Tasks hub, 5 runs at once, all passed in about 70 s; their rollouts show each step and the judge's scores.Fix cancelled-create cleanup and satisfy the named-variable requirement before merging.
Fix with agent prompt
Summary
Adds the optional
tenkibackend for Docker-capable VMs, public ports, restricted outbound access, file uploads, and reconnects.Diagram
%%{init: {'theme': 'neutral'}}%% flowchart TD A[Configured Tenki provider] --> B[Size VM and check policy] B --> C[Create Tenki VM] C --> D[Wait for readiness] D --> E[Expose public ports] E --> F[Prepare Docker] F --> G[Run gateway or agent containers] C --> H[Create cancelled] H --> I[Register late cleanup callback] I --> J[CLI loop may close before cleanup finishes] D --> K[Setup failure] E --> K F --> K K --> L[Await VM termination]Reviews (1) · Last reviewed commit: "feat(sandbox): add a Tenki Sandbox VM sa..." · Reviewed by Greptile