Repository navigation
Environments: layer sandbox-contract/v1 on a foreign image at build - #40
Conversation
…; a Dockerfile on a foreign base, held to the registries an image is
There was a problem hiding this comment.
🟡 Changes recommended
Critical validation gaps allow external image references to bypass registry restrictions and continued FROM instructions to retain mutable tags, undermining dependency controls and reproducible builds.
6 open issues
Unvalidated external images in COPY and RUN mounts bypass registry restrictions · New Multiline FROM instructions retain mutable image tags · New WORKDIR ancestor chown makes the reserved install tree writable · New Lock metadata uses the spec Python version instead of the detected version · New Pip fallback may target a different Python interpreter · New Unset PLANE_DOCKERFILES incorrectly enables Docker tests · New
What changed in this PR
This PR extends the environment pipeline to layer sandbox-contract/v1 onto foreign images, enabling them to run as Datalayer sandboxes while preserving packages outside the lock.
Changes:
- Adds the Datalayer-only
foreignDockerfilesource with single-base and registry validation. - Pins the contract source in lock metadata and adds Python bootstrap, runtime files, tini, and the contract user during builds.
- Updates the schema, documentation, and tests, including opt-in Docker integration coverage.
| File | Description |
|---|---|
tests/test_environment_resolve.py |
Updates the uv bootstrap assertion. |
tests/test_environment_foreign_contract_layer.py |
Adds validation, rendering, and Docker integration tests. |
tests/test_environment_datalayer_builder.py |
Updates contract-layer and capability expectations. |
schemas/environment-v1alpha1.json |
Adds foreignDockerfile to allowed sources. |
docs/docs/environments/specification.mdx |
Documents foreign sources and contract layering. |
code_sandboxes/environments/spec.py |
Defines and validates foreign build sources. |
code_sandboxes/environments/resolve.py |
Bootstraps foreign Python and records the contract base. |
code_sandboxes/environments/contract.py |
Adds foreign Dockerfile validation and base pinning. |
code_sandboxes/environments/adapters/datalayer.py |
Layers the sandbox runtime and preserves unlocked packages. |
Review effort: Balanced
| findings += [ | ||
| finding | ||
| for finding in dockerfile_findings_for_build(text) | ||
| if finding.instruction in ("COPY", "ADD", "escape") | ||
| ] |
There was a problem hiding this comment.
Fixed in bba02df. COPY --from= and RUN --mount=from= must now name an earlier stage of the Dockerfile, so neither can bring in an image past the base's registry check. Tests cover both forms.
| if in_directives and _DIRECTIVE.match(raw.strip()): | ||
| continue | ||
| in_directives = False | ||
| rewritten.append(raw.replace(image, reference, 1) if number == line else raw) |
There was a problem hiding this comment.
Fixed in bba02df. The base is pinned as a token across the whole logical FROM instruction, so a continued FROM gets the resolved reference. Covered by a test.
| user, uid, gid, home = contract.user, contract.uid, contract.gid, contract.home | ||
| return [ | ||
| f"RUN pwd > {TASK_WORKDIR_FILE} && chmod 0644 {TASK_WORKDIR_FILE} " | ||
| f'&& if [ "$(pwd)" != / ]; then chown -R {uid}:{gid} "$(pwd)"; fi', |
There was a problem hiding this comment.
Fixed in bba02df. The ownership change now leaves /opt and /opt/datalayer with root, and a real build with WORKDIR /opt passes the doctor.
| find_links = "/solve/wheelhouse" | ||
| # Solved for the interpreter the image has, not the one the spec | ||
| # names: the layer installs into that one. | ||
| python_version = '"$(python3 -c \'import sys; print("%d.%d" % sys.version_info[:2])\')"' |
There was a problem hiding this comment.
Fixed in bba02df. The solve exports the interpreter version it saw, and the lock's # python: header and python_version use that version.
| "RUN (command -v python3 >/dev/null && python3 -m pip --version >/dev/null 2>&1) || " | ||
| "(apt-get update -qq && apt-get install -y --no-install-recommends " | ||
| "python3 python3-pip ca-certificates && rm -rf /var/lib/apt/lists/*)", |
There was a problem hiding this comment.
Fixed in bba02df. pip is bootstrapped for the selected interpreter with ensurepip --default-pip, and only a distribution's Python goes through apt.
| subprocess.run(["docker", "rm", "-f", name], capture_output=True) | ||
|
|
||
|
|
||
| @pytest.mark.skipif(not (REAL and PLANE.is_dir()), reason="needs Docker, the network and the plane") |
There was a problem hiding this comment.
Fixed in bba02df. The skip now needs PLANE_DOCKERFILES to be set and to name an existing directory.
…es past the one base, the base pinned across continuations, the reserved tree left to root, the lock says the Python it was solved for, pip for the Python the image kept; pytest-asyncio's loop scope set


An
imagesource never became a sandbox: the build ended in a doctor it had not installed, anduv pip syncremoved what the image held. This layers the contract on at build.# datalayer-contract-base:), then PID 1 (static tini, by checksum), the kernel stack over what the image holds (install, notsync), the contract user and home, the entrypoint.foreignDockerfile: one base, held to the same registries asimage. Datalayer builder only. It is a new source rather than a field so existing spec digests do not change.DEFAULT_ALLOWED_REGISTRIESis unchanged, and the test pins it.Tested:
tests/test_environment_foreign_contract_layer.py, 22 passed withDATALAYER_ENVIRONMENT_DOCKER_TESTS=1andPLANE_DOCKERFILESset: real solve and build onpython:3.12-slimandubuntu:24.04, all 15 doctor rows, the image's entrypoint serving Jupyter, a kernel answering, andalpinerefused. A local image stood in for the approved base. The real one, and a BuildKit daemon, have not been used.