Skip to content

fix(server): reject Docker mount paths that clash with server mounts - #2505

Open
acodercat wants to merge 3 commits into
opensandbox-group:mainfrom
acodercat:fix/server-docker-reserved-mount-paths
Open

acodercat wants to merge 3 commits into
opensandbox-group:mainfrom
acodercat:fix/server-docker-reserved-mount-paths

Conversation

@acodercat

@acodercat acodercat commented Oct 31, 2026 •

Copy link
Copy Markdown
Contributor

#2421 made the Docker runtime reject duplicate and root mount paths with a 400 before anything is provisioned. That check only compares the request's volumes with each other. The server also adds mounts of its own: every docker.sandbox_binds destination from the config, a tmpfs at /var/lib/execd/isolation when bootstrap.execd.isolation=enable, and /oem for Windows sandboxes. A volume whose mountPath lands on one of those, for example a request that mounts a volume at the CA path the operator binds through sandbox_binds, still goes to Docker. Docker answers Duplicate mount point, and the client gets 500 DOCKER::SANDBOX_START_FAILED after the image pull and sidecar setup.

One server mount already tried to handle this. A request volume at /opt/opensandbox replaces the egress runtime mount, but that check matched the raw bind string. /opt/opensandbox/ or //opt/opensandbox slipped past it, the server added the runtime bind as well, and Docker refused the duplicate.

A mountPath containing : (for example /data:ro) has the same outcome. The bind string becomes vol:/data:ro:rw, Docker rejects it as an invalid volume specification, and the client sees a 500.

Summary

  • _validate_volume_definitions seeds its duplicate check with the paths the server mounts itself for this request, normalized the same way as request paths. A clash returns 400 VOLUME::INVALID_MOUNT_PATH.
  • A mountPath containing : is rejected with the same code.
  • The runtime mount check compares the cleaned mount paths of the request volumes (_has_volume_at), so any spelling of /opt/opensandbox replaces the runtime mount as intended.
  • The Windows /oem path is now a constant shared by the bind builder and the check.
  • The Docker mount destination note in docs/examples/docker-pvc-volume-mount.md lists the new rules.

Testing

  • Not run (explain why)

  • Unit tests

  • Integration tests

  • e2e / manual verification

  • New test_mount_paths_docker_rejects_are_400 covers a sandbox_binds destination (written differently on each side to exercise normalization), the isolation directory, /oem on Windows, and a path with :. Each case returns 500 on current main, and now returns 400 with no Docker calls. Removing any one of the four checks, or the normalization of sandbox_binds destinations, fails its case.

  • New test_request_volume_at_runtime_path_replaces_runtime_mount covers /opt/opensandbox, /opt/opensandbox/ and //opt/opensandbox. The last two get a second runtime bind on current main, and fail again if the comparison goes back to the raw path.

  • Docker's behavior was checked against a real daemon: a bind plus bind, tmpfs plus bind, and /oem plus /oem at the same destination, and a bind with a : in the container path, are all refused at container creation.

  • The full server suite passes (2704 passed) and ruff is clean. pyright reports one more error of the existing app_config on the mixin kind, the same one already reported a few lines above.

Breaking Changes

  • None
  • Yes (describe impact and migration path)

Requests rejected now were already failing at container creation.

Checklist

  • Linked Issue or clearly described motivation
  • Added/updated docs (if needed)
  • Added/updated tests (if needed)
  • Security impact considered
  • Backward compatibility considered

opensandbox-group#2421 rejects duplicate mount paths within a request, but the server adds
mounts of its own: the docker.sandbox_binds destinations, a tmpfs at the
execd isolation directory when isolation is enabled, and /oem for Windows
sandboxes. A volume at one of those paths, or a mountPath containing ':',
still reached Docker, which refused the container and the client got a
500 after the image pull and sidecar setup. Check these paths up front
and return 400 INVALID_MOUNT_PATH instead.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 31, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-31T03:46:09.748129Z f62cda0 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to 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" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions github-actions Bot added component/server documentation Improvements or additions to documentation size/M Denotes a PR that changes 30-99 lines, ignoring generated files. labels Oct 31, 2026
A request volume at /opt/opensandbox replaces the egress runtime mount,
but the check matched the raw bind string. /opt/opensandbox/ or
//opt/opensandbox slipped past it, so the server added the runtime bind
as well and Docker refused the duplicate mount point. Compare the
cleaned mount paths of the request volumes instead.
It only reads the request, like the module-level _clean_mount_path it
uses.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component/server documentation Improvements or additions to documentation size/M Denotes a PR that changes 30-99 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant