Skip to content

Add an OpenSandbox Sandbox Provider - #913

Merged
SaladDay merged 7 commits into
mainfrom
feat/opensandbox-provider
Nov 3, 2026
Merged

SaladDay merged 7 commits into
mainfrom
feat/opensandbox-provider

Conversation

@SaladDay

@SaladDay SaladDay commented Nov 3, 2026 •

Copy link
Copy Markdown
Collaborator

Adds opensandbox, a direct Sandbox Provider over the official OpenSandbox Go SDK (sdks/sandbox/go v1.2.0). It maps the native lifecycle, execd and egress APIs and links OpenSandbox's own documentation instead of restating it.

Adapter

  • Required operations and Observe map to the native lifecycle API, execd (through the server proxy) and /metrics. The adapter stores nothing: it finds sandboxes by four ownership metadata keys, and settlement is any non-Pending owned sandbox.

  • Create waits for the egress sidecar inside the SDK readiness check and requires dns+nft enforcement. It then uploads the bootstrap file (mode 0600), runs oac-daemon connect and marks completion in metadata.

  • Network: every sandbox denies the private, shared and link-local ranges. OpenSandbox's deny rules win over any allow, and its domain rules open every port of an answer's addresses. So the private denies keep allowed names off private answers, and Core must resolve to global addresses: Create rejects a non-global Core before dispatch (invalid). public allows the rest by default. Non-public denies by default and allows Core, model endpoints and domains. PrivateDomains is unsupported.

  • Settlement:

    • Any observed owned sandbox settles the creation, including a Pending one. Every step after the create response reports the created sandbox.
    • A create request that never reaches the server (dial, lookup or certificate failure) settles as absent, and so does a 401 from the server's key check.
    • When a create fails with the server's own namespaced error (such as DOCKER::SANDBOX_IMAGE_PULL_FAILED), the adapter lists the allocation. An empty listing settles it as absent; a leftover sandbox settles it for cleanup.
    • A gateway's answer stays unconfirmed.
  • Key replacement needs each unreleased allocation to list its sandboxes with the candidate key, because an empty listing does not prove access.

  • Server requirements include [docker] publish_host = "127.0.0.1": on the Docker runtime, execd answers on published sandbox ports without authentication, and Core uses only the server proxy.

  • The adapter guide also requires:

    • pre-pulling the Runtime image, because Core gives a Create 30 s;
    • disable_ipv6 left at its default;
    • on Kubernetes, deny.always covering cluster ranges outside the private ranges.

    It also states that only Core may reach the server, because the sandbox proxy route accepts requests without the API key.

  • The shared sandbox_configuration_error copy no longer says HTTPS. Core only refuses a loopback public URL.

  • The checkpoint group and preparation are declared unsupported. Pause/resume is runtime-specific in OpenSandbox, and there is no preparation cache.

  • deploy/opensandbox/Dockerfile derives the Runtime image. OpenSandbox runs the image's user, so the layout is prepared at build time and the sandbox needs no root.

  • Setup wizard, registry entry, generated contracts and documentation (English and Chinese) are included.

Verification

All runs used real Sessions on a temporary Core selecting opensandbox, against an OpenSandbox 1.2.0 server (Docker runtime, dns+nft egress):

  • codex and claude_sdk hosted acceptance: 9/9 each. These runs predate the global-Core requirement: the test Core is on a private IP, so the previous Core carve-out was in place. Bootstrap, commands, files and Kill have not changed since.
  • Network:
    • disabled: blocks DNS and TCP.
    • restricted ["example.com"]: allows example.com and blocks www.example.com and example.org.
    • A Session with Core on a private IP fails before any sandbox is created, under both public: true and public: false.
    • The restricted policy, run in a real sidecar, blocks allowed names with private answers, the metadata address, unlisted names and the Core host's other ports. Allowed public names stay reachable.
    • With publish_host = "127.0.0.1", the server proxy reaches execd, and the host address refuses the published port.
  • Observe returns provider_type: opensandbox with memory usage and limit.
  • Kill: deleting a Session removed its sandbox within 9 s.
  • PUT with the same provider and no credential inherits the key and passes ownership verification.
  • Unit tests: go test ./services/core/internal/sandbox/opensandbox/ ./services/core/internal/sandbox/providers/, go vet ./..., translation check.

Run Core-managed sandboxes on an operator's OpenSandbox server through its official Go SDK: a direct adapter with no helper or local state, ownership in sandbox metadata, the Runtime bootstrap through execd, and Core's egress mapped to the sidecar's dns+nft policy. Checkpoint and the preparation cache stay unmapped.
@SaladDay
SaladDay merged commit 7ae768b into main Nov 3, 2026
25 checks passed
@SaladDay
SaladDay deleted the feat/opensandbox-provider branch November 3, 2026 11:08
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