OSEP-0015: Declarative Sandbox Features#1302
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds OSEP-0015 as a new enhancement proposal defining a public API and lifecycle for declarative, administrator-approved sandbox “features” (digest-pinned OCI artifacts provisioned pre-start across Docker and Kubernetes), and updates OSEP indexes to include OSEP-0013 through OSEP-0015.
Changes:
- Added OSEP-0015 proposal document defining the contract, registry model, OCI artifact requirements, and Docker/Kubernetes provisioning semantics.
- Updated the OSEP index lists under
oseps/anddocs/community/to include OSEP-0013, OSEP-0014, and OSEP-0015. - Linked OSEP-0015 from the docs community OSEP index.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
oseps/README.md |
Adds OSEP-0013/0014/0015 entries to the OSEP list. |
oseps/0015-declarative-sandbox-features.md |
New OSEP describing declarative sandbox features: API shape, registry allowlist, artifact contract, provisioning flows, and phased implementation/testing plan. |
docs/community/oseps.md |
Adds OSEP-0015 to the docs-site OSEP index. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| | [OSEP-0014](https://github.com/opensandbox-group/OpenSandbox/blob/main/oseps/0014-multi-tenancy.md) | Multi-Tenancy Support for Kubernetes Runtime | draft | 2026-04-29 | | ||
| | [OSEP-0015](https://github.com/opensandbox-group/OpenSandbox/blob/main/oseps/0015-declarative-sandbox-features.md) | Declarative Sandbox Features | draft | 2026-07-14 | |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: de7e5b60bf
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| and end-to-end coverage. New SDKs send `features` only when a caller requests | ||
| them. They must not downgrade the request into `extensions` when connected to an | ||
| older server; the older server's unsupported-field response is safer than | ||
| silently creating a sandbox without requested tools. |
There was a problem hiding this comment.
Guard feature requests against older servers
With a new SDK talking to any current/pre-feature server, this migration plan assumes the unknown top-level features field will be rejected, but the existing CreateSandboxRequest model only sets populate_by_name and does not forbid extra fields (server/opensandbox_server/api/schema.py:534-535), so Pydantic will ignore the field and create a sandbox without the requested tools. The rollout needs an explicit compatibility guard/version check, or a prior server change to reject unknown fields, before relying on this failure mode.
Useful? React with 👍 / 👎.
| 4. Add a final activation-compiler init container from the pinned execd image. | ||
| It validates all activation documents against the request environment and | ||
| writes one ordered, shell-escaped activation file into the shared volume. |
There was a problem hiding this comment.
Persist activation documents before compiling them
In the Kubernetes flow, the preceding feature init step only places payload/ under features/<name>/<version>, but activation.json is defined outside payload/; this final compiler therefore has no activation documents to read for any feature that declares env or PATH changes. The contract should require the installer/provisioning step to copy validated activation metadata into the shared volume before this compiler runs, otherwise Kubernetes creates will either fail here or silently miss activation.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: eef0444437
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| it. SDKs MUST call this endpoint, or use a result cached for the same resolved | ||
| server base URL and authentication context, before the first create with a | ||
| non-empty `features` list. |
There was a problem hiding this comment.
Bind capability negotiation to the create target
In a rolling or mixed-version deployment, this separate cacheable GET can reach a feature-aware instance while the subsequent create reaches an older instance; a rollback behind the same URL can also leave the cached result valid. Because lines 296-299 establish that those older instances silently ignore features, the sandbox can still start without its requested tools despite this new guard. Require a fleet-wide compatibility gate/prior server change or another mechanism that guarantees the create is handled by the negotiated server version.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cae6b733c3
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| 1. Keep the existing `execd-installer` init container. | ||
| 2. Add one feature init container per requested feature, in request order. Each | ||
| uses the registry's digest-pinned OCI image and invokes its self-contained | ||
| installer. |
There was a problem hiding this comment.
Supply pull credentials to feature init containers
When an allowlisted feature image is private and the sandbox ServiceAccount has no preconfigured registry secret, this flow adds only the image reference, so kubelet cannot use the operator credentials with which the server validated the artifact. The existing BatchSandbox path injects imagePullSecrets only from caller image.auth (batchsandbox_provider.py:231-233), while other providers require credentials to already exist on the ServiceAccount or template (kubernetes_service.py:340-357). Specify how operator-controlled feature credentials are propagated to generated Pods for both providers; otherwise supported private feature images fail with ImagePullBackOff.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7748857bc1
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| Kubernetes init containers are sequential, so request order is preserved. The | ||
| Pod retains `automountServiceAccountToken: false`; feature init containers do | ||
| not receive API credentials and do not need network access after kubelet pulls | ||
| their OCI image. Implementations SHOULD apply the existing restricted | ||
| init-container security defaults and grant no additional Linux capabilities. |
There was a problem hiding this comment.
Enforce egress policy before feature installers run
For Kubernetes sandboxes with a restrictive networkPolicy, these feature init containers run before the egress sidecar and can therefore make unrestricted outbound connections while executing an explicitly untrusted installer. The current wiring appends egress as a normal container (server/opensandbox_server/services/k8s/egress_helper.py:104-131), and that process installs the network rules only when it starts (components/egress/main.go:111-116), after all init containers have completed. This both bypasses the caller's policy and leaves the stated no-download requirement unenforced; the design needs enforcement active during feature initialization rather than merely noting that installers do not need network access.
Useful? React with 👍 / 👎.
|
For stable, large-scale sandbox fleets, I'd argue that pre-baked OCI images and VM templates are still the optimal path — resolving and provisioning features at create time introduces non-trivial overhead on the hot path (image pulls, ordered init containers, activation before execd), which is hard to justify when the toolchain rarely changes. This design looks great for newcomers and interactive/exploratory use cases where the toolchain is fluid and per-request. But for hyperscale scheduling, where cold-start latency, cache locality, and deterministic startup dominate, I'd expect most operators to still consolidate features into a curated base image rather than composing them dynamically. Not opposing the proposal — just wondering if it's worth calling out in Non-Goals or Alternatives that declarative features are not intended to replace pre-baked images for high-throughput workloads, and that the two approaches are complementary. |
|
Thanks @Pangjiping, agreed. The intent is for declarative features to complement, not replace, pre-baked images or VM templates. I updated the proposal in 395eeb5 to make that boundary explicit:
Thanks for calling out the large-scale fleet perspective. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 395eeb5b1d
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| When `platform` is explicit, all selected features must contain that platform. | ||
| When it is omitted, the resolver computes the intersection of platforms across | ||
| the selected feature versions and constrains Pod scheduling to that | ||
| intersection. The init-container `image` uses the pinned OCI index digest, so |
There was a problem hiding this comment.
Include sandbox image platforms in Kubernetes resolution
For Kubernetes creates where platform is omitted, this computes scheduling constraints only from the selected feature versions. In a mixed-architecture cluster, a linux/amd64-only sandbox image plus features that also allow arm64 can still be scheduled onto an arm64 node; current provider helpers only add kubernetes.io/os/arch selectors from an explicit PlatformSpec (server/opensandbox_server/services/k8s/workload_provider.py:306-336), so kubelet fails later with ImagePullBackOff/readiness timeout instead of the documented pre-create FEATURE_PLATFORM_UNSUPPORTED. The resolver should intersect the sandbox image's supported platforms, or require an explicit platform, before creating the workload.
Useful? React with 👍 / 👎.
Summary
Key decisions
featuresentries, while SDKs may providename@versionconveniencesresolvedFeatureswith exact version, OCI digest, OS, and architecturedeny_toolsis excluded because command-name andPATHfiltering are bypassable and do not form an enforceable security boundaryRelated to #1289. This proposal does not close the issue; it should remain open until the OSEP is approved and the end-to-end implementation is complete.
Validation
cd docs && pnpm docs:buildgit diff --check