Skip to content

Fix Docker Runtime bootstrap on Docker before 28 (copyUIDGID with uid:gid user) - #21

Merged
sunyalou merged 1 commit into
mainfrom
fix/docker-bootstrap-copyuidgid
Oct 4, 2026
Merged

sunyalou merged 1 commit into
mainfrom
fix/docker-bootstrap-copyuidgid

Conversation

@sunyalou

@sunyalou sunyalou commented Oct 4, 2026

Copy link
Copy Markdown
Owner

Goal

Docker-backed openai_hosted sandboxes never start on Docker Engine < 28: the Runtime container stays in created, the environment stays pending, and the console marks the node "Needs attention".

Root cause

services/core/internal/sandbox/docker/container_options.go creates the Runtime container with Config.User = "1000:1000", and bootstrap.go copied the bootstrap archive with copyUIDGID. Docker before 28 resolves Config.User with a passwd lookup and passes a "uid:gid" pair through as a single user name, so PUT /containers/<id>/archive fails:

Handler for PUT /v1.45/containers/<id>/archive returned error: getent unable to find entry "1000:1000" in passwd database

The Runtime then starts without /home/runtime/runtime-bootstrap.json (oac-daemon: connect: Runtime bootstrap file unavailable, exit 1) and the allocation never settles. Upstream added a uid:gid-aware lookup in 28.0.0; 26.x/27.x are affected.

Change

  • services/core/internal/sandbox/docker/bootstrap.go: stop requesting copyUIDGID and rely on the archive's numeric owner. The tar entries already carry uid/gid 1000, which the daemon preserves on extraction, so ownership is unchanged on every Docker version.
  • bootstrap_test.go: add a regression test whose fake daemon rejects a copyUIDGID request the way Docker 26/27 does; it fails before the fix and passes after.

Verification

  • go test ./services/core/internal/sandbox/docker/... -count=1 -> ok
  • New TestBootstrapDoesNotRequireContainerUserLookup fails on the parent commit with the exact dockerd error and passes after.
  • go build ./services/core/cmd/sandbox-node -> ok
  • make check-names -> pass
  • make check-core-packages -> every package passes except services/core/internal/nativeinstaller (two curl-dependent tests), which fail identically on unmodified origin/main in this environment (host curl rejects --max-time / certificate type) -- pre-existing, unrelated.
  • python3 scripts/ci_plan.py plan --base origin/main --head HEAD -> hygiene, compose, backend, api

Notes

  • The node binary embeds this provider, so a node built before this change still needs a rebuild to pick up the fix.
  • No contracts, generated artifacts, migrations or SQL are touched.

Boundaries

No secrets, tokens or connection strings in the diff or this description.

The Docker provider launches the Runtime container with Config.User
"1000:1000" and copied the bootstrap archive with copyUIDGID. Docker
before 28 resolves Config.User with a passwd lookup and passes a
"uid:gid" pair through as a single user name, so the archive request
fails ("getent unable to find entry \"1000:1000\"") and the Runtime starts
without runtime-bootstrap.json. Rely on the archive's own numeric owner
instead; the tar entries already carry uid/gid 1000, which the daemon
preserves on extraction.

Add a regression test that rejects a copyUIDGID request the way Docker
26/27 does.

Co-authored-by: multica-agent <github@multica.ai>
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@sunyalou
sunyalou merged commit c954dfc into main Oct 4, 2026
18 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.

1 participant