Skip to content

feat(sdk): support explicit HostPath bind mounts - #116

Merged
rcyw merged 2 commits into
inclusionAI:developfrom
rcyw:dev/sdk-hostpath-mounts-20261020
Oct 20, 2026
Merged

rcyw merged 2 commits into
inclusionAI:developfrom
rcyw:dev/sdk-hostpath-mounts-20261020

Conversation

@rcyw

@rcyw rcyw commented Oct 20, 2026 •

Copy link
Copy Markdown
Collaborator

Allow Mount to bind an existing node-visible path into a sandbox:

Mount(target="/apps/logs", host_path="/apps/logs", read_only=False)

HostPath mounts default to read-only and support bind mounts only. Writes require read_only=False. Exactly one mount source is required; Image/S3 behavior and payloads remain unchanged.

The backend adapts HostPath through the pinned native SDK's mount serializer, retaining its constructor, node placement, transport and structured errors. The SDK does not create the source directory or provision node volumes. The guide and runnable example explain Kubernetes volume visibility, filesystem permissions and node-local data. Use trusted management clients and operator-controlled paths; this API does not provide per-tenant source-path isolation.

Validation:

  • make sdk-check: 310 SDK unit tests, 35 benchmark-driver tests, Ruff and mypy passed.
  • Request-level regression verifies HostPath payloads and node affinity through the real native constructor and HTTP encoder, preserving a mocked structured 403 response.
  • Wheel and sdist built and installed into separate fresh environments; dependency checks, isolated public API checks and CLI help passed.
  • Documentation follow-up: executable Python AST unchanged; example lint/help and whitespace checks passed.

A live node HostPath mount has not been tested.

rcyw added 2 commits October 20, 2026 17:11
Add validated host_path and read_only mount fields for prepared node
paths, with read-only defaults and unchanged Image/S3 permissions.
Adapt the pinned native Mount serialization hook while retaining its
constructor, scheduling and structured permission errors.

Cover request encoding, source/mode rejection and mixed mounts, and
document the trusted-management boundary and node visibility setup.
Server-side authorization remains tracked separately in inclusionAI#110.

Signed-off-by: wayne <rcywjo@gmail.com>
Describe prepared node paths, mount permissions and caller requirements
without embedding issue discussions or release history in product guidance.
Keep README, agent instructions, example help and adapter documentation
consistent without changing mount behavior.

Signed-off-by: wayne <rcywjo@gmail.com>
@rcyw
rcyw marked this pull request as ready for review October 20, 2026 09:40
@rcyw
rcyw requested review from WenYuLuo and hky1999 October 20, 2026 09:40

@hky1999 hky1999 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed and independently verified on 6c77083; approving.

The public-surface design is right: HostPath is a third exclusive source on Mount (exactly-one-of image_url/s3_config/host_path enforced), defaults to read-only with writes requiring an explicit read_only=False, allows only type="bind", and Image/S3 remain forcibly read-only. Client-side validation is thorough - absolute path, no ./.. traversal segments, no control characters (including the 0x7F-0x9F C1 range), type check on non-string input - and the wire shape is pinned by tests: host_path plus create_if_missing: False (the SDK never provisions the source), and options flips ro/rw correctly.

The backend adapter is the part I scrutinized most, and the approach is sound: the pinned native SDK checks isinstance(Mount) and only represents Image/S3, so rather than monkey-patching or replacing native classes, a frozen dataclass subclasses the native Mount and overrides to_dict while reusing the native constructor, transport, node-affinity encoding and structured-error parsing. The request-level regression exercises exactly the right seam - a mocked httpx 403 at the transport boundary - verifying the real native serializer produced the mount payload (body mounts == Mount.to_dict()) and the NODE_ID affinity, while preserving the structured PERMISSION_DENIED/retry=never propagation. Node affinity reaching the request for host-path mounts (the path is node-local) is verified in that same test.

Docs are honest about the sharp edges: no per-tenant source-path isolation (trusted management clients and operator-controlled paths), no client-side existence checks or node volume provisioning, and the Kubernetes volume-visibility/permissions caveats in the guide.

Verification on my side (worktree of 6c77083, after installing the pinned adx-environment==0.1.0rc2): the full make sdk-check pipeline passes - 302 unit tests OK, benchmark-driver suite OK, ruff clean, mypy clean (22 files); CI run 39401419785 on this exact head completed successfully.

One non-blocking observation: a live node HostPath mount has not been tested (the PR says so). The request-shape and error paths are covered, but the end-to-end behavior - node runtime honoring create_if_missing: False, read-write bind semantics, and what error surfaces when the path is absent - is only validated once a real node round-trip happens. Worth a follow-up ticket tied to the first deployment that uses this.

@rcyw
rcyw merged commit 343941c into inclusionAI:develop Oct 20, 2026
11 checks passed
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.

2 participants