code-sandboxes 1.9.35__tar.gz → 1.9.36__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/PKG-INFO +1 -1
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/__version__.py +1 -1
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/adapters/datalayer.py +11 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/adapters/modal.py +24 -1
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/resolve.py +47 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/resolve_conda.py +6 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/modal_sandbox.py +10 -1
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_datalayer_builder.py +21 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_modal_builder.py +18 -4
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_resolve.py +28 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_resolve_conda.py +24 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_modal_google_colab_sandbox.py +51 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/.github/workflows/build.yml +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/.github/workflows/environments-live.yml +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/.github/workflows/py-code-style.yml +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/.github/workflows/py-tests.yml +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/.github/workflows/py-typing.yml +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/.github/workflows/reusable-python.yml +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/.gitignore +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/.licenserc.yaml +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/.pre-commit-config.yaml +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/.vscode/settings.json +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/CHANGELOG.md +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/Dockerfile +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/LICENSE +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/Makefile +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/README.md +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/__init__.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/base.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/bridge_mount.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/builds.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/cli.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/client.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/cloudflare_sandbox.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/commands.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/console.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/contents.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/coreweave_sandbox.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/datalayer_sandbox.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/daytona_sandbox.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/docker_sandbox.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/e2b_sandbox.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/__init__.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/__main__.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/accounts.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/adapters/__init__.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/adapters/daytona.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/adapters/e2b.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/adapters/managed.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/attest.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/bases.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/breaker.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/build_secrets.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/builders.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/canonical.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/conformance.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/constraints/sandbox-contract-v1.txt +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/constraints/wheelhouse/README.md +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/constraints/wheelhouse/jupyter_server-2.21.0+datalayer.1-py3-none-any.whl +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/contract.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/doctor/__init__.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/doctor/build.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/doctor/datalayer_sandbox.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/doctor/report.schema.json +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/errors.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/files.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/image_import.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/lifecycle.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/policy.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/redact.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/schema.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/spec.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/eval_sandbox.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/exceptions.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/filesystem.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/google_colab.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/google_colab_sandbox.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/interfaces.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/jupyter_ingress.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/jupyter_server_sandbox.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/kaggle.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/kaggle_execute.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/kaggle_live.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/kaggle_sandbox.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/lifecycle.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/manage.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/models.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/monty_sandbox.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/provider_ingress.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/providers.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docker/Dockerfile +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/.gitignore +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/LICENSE +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/Makefile +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/README.md +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/babel.config.js +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/api-reference/_category_.yml +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/api-reference/index.mdx +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/cli/_category_.yml +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/cli/index.mdx +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/contribute/_category_.yml +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/contribute/index.mdx +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/environments/_category_.yml +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/environments/contract.mdx +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/environments/index.mdx +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/environments/specification.mdx +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/environments/spike-2026-09.mdx +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/examples/_category_.yml +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/examples/index.mdx +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/guide/_category_.yml +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/guide/index.mdx +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/index.mdx +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/install/_category_.yml +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/install/index.mdx +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/provider-ingress.mdx +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/providers/_category_.yml +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/providers/cloudflare.mdx +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/providers/coreweave.mdx +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/providers/datalayer.mdx +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/providers/daytona.mdx +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/providers/docker.mdx +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/providers/e2b.mdx +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/providers/eval.mdx +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/providers/google-colab.mdx +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/providers/index.mdx +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/providers/jupyter-server.mdx +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/providers/kaggle.mdx +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/providers/modal.mdx +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docs/providers/monty.mdx +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/docusaurus.config.js +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/package.json +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/sidebars.js +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/src/components/HomepageRow1.js +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/src/components/HomepageRow1.module.css +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/src/components/HomepageRow2.js +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/src/components/HomepageRow2.module.css +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/src/components/HomepageRow3.js +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/src/components/HomepageRow3.module.css +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/src/css/custom.css +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/src/pages/index.module.css +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/src/pages/markdown-page.md +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/src/theme/CustomDocItem.tsx +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/src/theme/IconsTitle.tsx +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/static/img/bricks.svg +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/static/img/building-construction.svg +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/static/img/cloud-sun.svg +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/static/img/cloud.svg +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/static/img/collaboration.svg +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/static/img/copy-left.svg +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/static/img/datalayer/logo.png +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/static/img/datalayer/logo.svg +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/static/img/datalayer/personas/business.svg +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/static/img/datalayer/personas/data-scientist.svg +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/static/img/datalayer/personas/devops.svg +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/static/img/datalayer/project/project-line.svg +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/static/img/favicon.ico +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/static/img/jupyter.svg +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/static/img/open-source.svg +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/static/img/react-js.svg +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/static/img/react-js2.svg +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/static/img/ringed-planet.svg +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/static/img/robot.svg +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/static/img/rocket.svg +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/static/img/shield.svg +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/static/img/sparkles.svg +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/static/img/streamlit.gif +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/static/img/super-hero.svg +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/static/img/target.svg +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/docs/static/img/thumbs-up.svg +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/examples/README.md +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/examples/exec/Makefile +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/examples/exec/cloudflare_sandbox_example.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/examples/exec/coreweave_sandbox_example.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/examples/exec/datalayer_sandbox_example.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/examples/exec/daytona_sandbox_example.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/examples/exec/docker_sandbox_example.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/examples/exec/e2b_sandbox_example.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/examples/exec/eval_sandbox_example.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/examples/exec/google_colab_sandbox_example.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/examples/exec/jupyter_server_sandbox_example.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/examples/exec/kaggle_sandbox_example.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/examples/exec/modal_sandbox_example.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/examples/exec/monty_sandbox_example.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/examples/repl/Makefile +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/examples/repl/cloudflare_sandbox_example.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/examples/repl/coreweave_sandbox_example.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/examples/repl/datalayer_sandbox_example.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/examples/repl/daytona_sandbox_example.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/examples/repl/docker_sandbox_example.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/examples/repl/e2b_sandbox_example.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/examples/repl/eval_sandbox_example.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/examples/repl/google_colab_sandbox_example.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/examples/repl/jupyter_server_sandbox_example.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/examples/repl/kaggle_sandbox_example.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/examples/repl/modal_sandbox_example.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/examples/repl/monty_sandbox_example.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/pyproject.toml +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/schemas/environment-v1alpha1.json +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/__init__.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/conftest.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_a_datalayer_sandbox_can_be_interrupted.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_bridge_mount.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_builds.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_cli_exec.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_cli_repl.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_client.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_client_contents.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_client_files.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_client_outcome_error_output.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_cloudflare.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_commands_envelope.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_console.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_contents_contract.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_contents_live_matrix.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_coreweave.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_datalayer_sandbox.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_daytona.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_e2b.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_accounts.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_attest.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_bases.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_breaker.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_build_secrets.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_builders.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_canonical.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_conformance.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_constraints.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_contract.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_cross_variant_report.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_daytona_builder.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_dockerfile_source.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_doctor.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_e2b_builder.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_errors.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_image_import.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_lifecycle.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_live_matrix.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_managed_builders.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_organization_policy.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_redact.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_spec.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_environment_spec_organization_policy.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_eval.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_every_variant_has_a_real_interrupt.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_factory.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_google_colab.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_integration.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_jupyter_ingress.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_jupyter_server.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_jupyter_server_streaming.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_kaggle.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_kaggle_execute.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_kaggle_live.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_kaggle_session.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_kernel_client_compatibility.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_lifecycle_vocabulary.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_manage.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_manage_datalayer.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_modal_session.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_models.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_output_line_fidelity.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_provider_catalog_names.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_provider_ingress.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_providers.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_sandboxes.py +0 -0
- {code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/tests/test_the_kill_relaunch_drill.py +0 -0
{code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/adapters/datalayer.py
RENAMED
|
@@ -76,6 +76,8 @@ from ..resolve import (
|
|
|
76
76
|
WHEELHOUSE_PATH,
|
|
77
77
|
apt_pins_in,
|
|
78
78
|
apt_snapshot_in,
|
|
79
|
+
buildkit_proxy,
|
|
80
|
+
buildkit_proxy_options,
|
|
79
81
|
locked_versions,
|
|
80
82
|
)
|
|
81
83
|
from ..resolve_conda import (
|
|
@@ -214,6 +216,11 @@ class Builder:
|
|
|
214
216
|
importing this module needs no credentials.
|
|
215
217
|
run
|
|
216
218
|
How a subprocess is run, so a test can watch the argv without a daemon.
|
|
219
|
+
proxy
|
|
220
|
+
The build pool's egress proxy, as ``buildkitd`` reaches it (E1-06):
|
|
221
|
+
every step of the build goes through it. ``DATALAYER_BUILDKIT_PROXY``
|
|
222
|
+
by default; empty is a ``buildkitd`` whose steps reach the network
|
|
223
|
+
directly.
|
|
217
224
|
"""
|
|
218
225
|
|
|
219
226
|
variant = "datalayer"
|
|
@@ -233,6 +240,7 @@ class Builder:
|
|
|
233
240
|
run: Callable[..., subprocess.CompletedProcess[str]] | None = None,
|
|
234
241
|
max_build_seconds: int = DEFAULT_MAX_BUILD_SECONDS,
|
|
235
242
|
resolve_secret: Callable[..., str] = resolve_build_secret,
|
|
243
|
+
proxy: str | None = None,
|
|
236
244
|
) -> None:
|
|
237
245
|
self._log = log or (lambda _line: None)
|
|
238
246
|
self._credential = credential
|
|
@@ -241,6 +249,8 @@ class Builder:
|
|
|
241
249
|
self._tlscert = tlscert or os.environ.get("DATALAYER_BUILDKIT_TLSCERT", "").strip()
|
|
242
250
|
self._tlskey = tlskey or os.environ.get("DATALAYER_BUILDKIT_TLSKEY", "").strip()
|
|
243
251
|
self._tlscacert = tlscacert or os.environ.get("DATALAYER_BUILDKIT_TLSCACERT", "").strip()
|
|
252
|
+
#: The build pool's egress proxy (E1-06), or `DATALAYER_BUILDKIT_PROXY`.
|
|
253
|
+
self._proxy = buildkit_proxy(proxy)
|
|
244
254
|
self._region = region or os.environ.get("AWS_REGION", "us-east-1")
|
|
245
255
|
self._ecr = ecr
|
|
246
256
|
self._run = run or subprocess.run
|
|
@@ -530,6 +540,7 @@ class Builder:
|
|
|
530
540
|
"--metadata-file",
|
|
531
541
|
str(metadata),
|
|
532
542
|
*self._cache_options(request),
|
|
543
|
+
*buildkit_proxy_options(self._proxy),
|
|
533
544
|
*secret_args,
|
|
534
545
|
]
|
|
535
546
|
self._log(f"Building {reference} from {request.resolved_base}")
|
{code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/adapters/modal.py
RENAMED
|
@@ -96,6 +96,15 @@ end and the container exited before that first real exec ever reached it.
|
|
|
96
96
|
The entrypoint now execs `sleep infinity` when it is given no arguments,
|
|
97
97
|
and `"$@"` when it is — correct either way a caller invokes it.
|
|
98
98
|
|
|
99
|
+
**And a sandbox with no command is not given no arguments** (found live on
|
|
100
|
+
2026-09-18): Modal keeps the base's own CMD, `start-jupyter.sh`, under the
|
|
101
|
+
new ENTRYPOINT where Docker would reset it, so the main process was a
|
|
102
|
+
Jupyter server, which exits within a minute and ends the sandbox. A smoke
|
|
103
|
+
test's restarted sandbox, started warm, died between checks 8 and 9. The
|
|
104
|
+
artifact now sets its CMD to `sleep infinity`, and `ModalSandbox` names the
|
|
105
|
+
same command when it launches an artifact, which also covers the ones built
|
|
106
|
+
before.
|
|
107
|
+
|
|
99
108
|
**A GPU is a launch option on Modal, not part of the image** (section 11.4
|
|
100
109
|
item 10, E2-17). A GPU version builds the same image any version does, on the
|
|
101
110
|
CUDA base; the spec's `accelerator` names one of Modal's GPUs, checked at
|
|
@@ -206,6 +215,8 @@ _ENTRYPOINT_PATH = "/opt/datalayer/bin/entrypoint.sh"
|
|
|
206
215
|
#: is given keeps it alive for that; `exec "$@"` still wins when something
|
|
207
216
|
#: is, for a caller that does supply a command directly.
|
|
208
217
|
_ENTRYPOINT_SCRIPT = '#!/bin/sh\nif [ "$#" -eq 0 ]; then exec sleep infinity; fi\nexec "$@"\n'
|
|
218
|
+
#: The artifact's CMD: what a sandbox started with no command of its own runs.
|
|
219
|
+
_KEEP_ALIVE_COMMAND = ("sleep", "infinity")
|
|
209
220
|
|
|
210
221
|
|
|
211
222
|
def _modal_sdk() -> Any:
|
|
@@ -498,7 +509,19 @@ class Builder(ManagedBuilder):
|
|
|
498
509
|
for command in files_step(request.environment, variant=self.variant):
|
|
499
510
|
image = image.run_commands(command)
|
|
500
511
|
image = _post_install(image, spec.commands.post_install, declared, step_secrets)
|
|
501
|
-
|
|
512
|
+
# The base's own CMD is `start-jupyter.sh`, and Modal keeps
|
|
513
|
+
# it under a new ENTRYPOINT where Docker would reset it: a
|
|
514
|
+
# sandbox started with no command ran a Jupyter server as its
|
|
515
|
+
# main process, which exits within a minute and takes the
|
|
516
|
+
# sandbox with it (found live on 2026-09-18, the restarted
|
|
517
|
+
# sandbox of a smoke test dying mid-tier). What holds the
|
|
518
|
+
# container is `sleep`; Jupyter is started by exec, when
|
|
519
|
+
# asked (`ModalSandbox.prepare_jupyter_server`).
|
|
520
|
+
image = (
|
|
521
|
+
image.workdir(_CONTENT_DIR)
|
|
522
|
+
.entrypoint([_ENTRYPOINT_PATH])
|
|
523
|
+
.cmd(list(_KEEP_ALIVE_COMMAND))
|
|
524
|
+
)
|
|
502
525
|
|
|
503
526
|
logged: list[str] = []
|
|
504
527
|
buffer = io.StringIO()
|
|
@@ -83,6 +83,7 @@ if TYPE_CHECKING:
|
|
|
83
83
|
__all__ = [
|
|
84
84
|
"APT_PIN_PREFIX",
|
|
85
85
|
"APT_SNAPSHOT_PREFIX",
|
|
86
|
+
"BUILDKIT_PROXY_ENV",
|
|
86
87
|
"CONSTRAINTS_PATH",
|
|
87
88
|
"COVERAGE_PREFIX",
|
|
88
89
|
"DOCKERFILE_COVERAGE",
|
|
@@ -98,6 +99,8 @@ __all__ = [
|
|
|
98
99
|
"apt_pins",
|
|
99
100
|
"apt_pins_in",
|
|
100
101
|
"apt_snapshot_in",
|
|
102
|
+
"buildkit_proxy",
|
|
103
|
+
"buildkit_proxy_options",
|
|
101
104
|
"lock_document",
|
|
102
105
|
"locked_versions",
|
|
103
106
|
"merge_requirements",
|
|
@@ -145,6 +148,46 @@ DOCKERFILE_COVERAGE = (
|
|
|
145
148
|
APT_SNAPSHOT_PREFIX = "# datalayer-apt-snapshot: "
|
|
146
149
|
_SNAPSHOT_ID = re.compile(r"^\d{8}T\d{6}Z$")
|
|
147
150
|
|
|
151
|
+
#: Where a build's own steps reach the network through, when the build pool
|
|
152
|
+
#: gives them nowhere else to go (E1-06): an HTTP proxy that allows only the
|
|
153
|
+
#: package indexes, the snapshot mirrors and the registries. The address is
|
|
154
|
+
#: the one `buildkitd` itself sees, since a step runs in its network.
|
|
155
|
+
BUILDKIT_PROXY_ENV = "DATALAYER_BUILDKIT_PROXY"
|
|
156
|
+
_PROXY_URL = re.compile(r"^http://[A-Za-z0-9.\-]+:\d{1,5}$")
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def buildkit_proxy(proxy: str | None = None) -> str:
|
|
160
|
+
"""The proxy a build's steps go through: ``proxy``, or the environment's.
|
|
161
|
+
|
|
162
|
+
Empty is no proxy, which is what a `buildkitd` with open egress needs
|
|
163
|
+
(`plane local`'s own). Anything that is not ``http://host:port`` is
|
|
164
|
+
refused rather than handed to every package manager of every build.
|
|
165
|
+
"""
|
|
166
|
+
value = (os.environ.get(BUILDKIT_PROXY_ENV, "") if proxy is None else proxy).strip()
|
|
167
|
+
if value and not _PROXY_URL.match(value):
|
|
168
|
+
raise ValueError(f"{BUILDKIT_PROXY_ENV} must be http://host:port, not {value!r}")
|
|
169
|
+
return value
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def buildkit_proxy_options(proxy: str) -> list[str]:
|
|
173
|
+
"""The ``buildctl`` options that send a build's steps through ``proxy``.
|
|
174
|
+
|
|
175
|
+
The Dockerfile frontend predefines these build args: a ``RUN`` step sees
|
|
176
|
+
them without an ``ARG``, they never reach the image's config or history,
|
|
177
|
+
and they do not change a cache key. Both spellings, since ``apt`` and
|
|
178
|
+
``curl`` read only the lower-case one for plain HTTP and ``uv``, ``pip``
|
|
179
|
+
and ``micromamba`` read either.
|
|
180
|
+
"""
|
|
181
|
+
if not proxy:
|
|
182
|
+
return []
|
|
183
|
+
options: list[str] = []
|
|
184
|
+
for name in ("HTTP_PROXY", "HTTPS_PROXY", "http_proxy", "https_proxy"):
|
|
185
|
+
options += ["--opt", f"build-arg:{name}={proxy}"]
|
|
186
|
+
for name in ("NO_PROXY", "no_proxy"):
|
|
187
|
+
options += ["--opt", f"build-arg:{name}=127.0.0.1,localhost"]
|
|
188
|
+
return options
|
|
189
|
+
|
|
190
|
+
|
|
148
191
|
#: How a protected pin is recorded in the lock.
|
|
149
192
|
PROTECTED_PIN_PREFIX = "# datalayer-protected: "
|
|
150
193
|
|
|
@@ -623,8 +666,11 @@ class BuildkitResolveRunner:
|
|
|
623
666
|
tlscacert: str | None = None,
|
|
624
667
|
apt_snapshot: str = "",
|
|
625
668
|
timeout: float = 900.0,
|
|
669
|
+
proxy: str | None = None,
|
|
626
670
|
) -> None:
|
|
627
671
|
self._buildctl = (shutil.which("buildctl") or "") if buildctl is None else buildctl
|
|
672
|
+
#: The build pool's egress proxy (E1-06), or `DATALAYER_BUILDKIT_PROXY`.
|
|
673
|
+
self._proxy = buildkit_proxy(proxy)
|
|
628
674
|
#: The build pool's `buildkitd` takes mTLS connections only
|
|
629
675
|
#: (PLAN_ENV.md E1-06); a plain-socket one, such as `plane local`'s
|
|
630
676
|
#: own ephemeral daemon, needs none of these three. All or nothing,
|
|
@@ -761,6 +807,7 @@ class BuildkitResolveRunner:
|
|
|
761
807
|
f"dockerfile={root}",
|
|
762
808
|
"--output",
|
|
763
809
|
f"type=local,dest={out}",
|
|
810
|
+
*buildkit_proxy_options(self._proxy),
|
|
764
811
|
]
|
|
765
812
|
say(f"Solving the lock in {request.base_reference}")
|
|
766
813
|
try:
|
{code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/resolve_conda.py
RENAMED
|
@@ -68,6 +68,8 @@ from .resolve import (
|
|
|
68
68
|
WHEELHOUSE_PATH,
|
|
69
69
|
MergedRequirements,
|
|
70
70
|
ProtectedPin,
|
|
71
|
+
buildkit_proxy,
|
|
72
|
+
buildkit_proxy_options,
|
|
71
73
|
merge_requirements,
|
|
72
74
|
)
|
|
73
75
|
|
|
@@ -684,8 +686,11 @@ class BuildkitCondaResolveRunner:
|
|
|
684
686
|
tlskey: str | None = None,
|
|
685
687
|
tlscacert: str | None = None,
|
|
686
688
|
timeout: float = 1200.0,
|
|
689
|
+
proxy: str | None = None,
|
|
687
690
|
) -> None:
|
|
688
691
|
self._buildctl = (shutil.which("buildctl") or "") if buildctl is None else buildctl
|
|
692
|
+
#: The build pool's egress proxy (E1-06), or `DATALAYER_BUILDKIT_PROXY`.
|
|
693
|
+
self._proxy = buildkit_proxy(proxy)
|
|
689
694
|
self._tlscert = tlscert or ""
|
|
690
695
|
self._tlskey = tlskey or ""
|
|
691
696
|
self._tlscacert = tlscacert or ""
|
|
@@ -778,6 +783,7 @@ class BuildkitCondaResolveRunner:
|
|
|
778
783
|
f"dockerfile={root}",
|
|
779
784
|
"--output",
|
|
780
785
|
f"type=local,dest={out}",
|
|
786
|
+
*buildkit_proxy_options(self._proxy),
|
|
781
787
|
]
|
|
782
788
|
say(f"Solving the conda lock in {request.base_reference}")
|
|
783
789
|
try:
|
|
@@ -441,7 +441,16 @@ class ModalSandbox(Sandbox):
|
|
|
441
441
|
for mount_path, volume_id in self._volume_mounts.requested.items()
|
|
442
442
|
}
|
|
443
443
|
|
|
444
|
-
|
|
444
|
+
# An Environments artifact's main process only holds the container:
|
|
445
|
+
# everything this class runs in it is an exec, Jupyter included
|
|
446
|
+
# (`prepare_jupyter_server`). Named here rather than left to the
|
|
447
|
+
# image, since an artifact built before code-sandboxes 1.9.36 carries
|
|
448
|
+
# its base's `start-jupyter.sh` as its CMD, which Modal runs under the
|
|
449
|
+
# entrypoint; that server exits within a minute and ends the sandbox
|
|
450
|
+
# (found live on 2026-09-18: a smoke test's restarted sandbox died
|
|
451
|
+
# between checks 8 and 9).
|
|
452
|
+
command = ("sleep", "infinity") if self._image_id else ()
|
|
453
|
+
self._sandbox = modal.Sandbox.create(*command, **create_kwargs)
|
|
445
454
|
self._volume_mounts.created()
|
|
446
455
|
self._start_driver()
|
|
447
456
|
|
|
@@ -726,6 +726,27 @@ class TestBuildingAndPushing:
|
|
|
726
726
|
a_builder(run=buildctl, tlscert="/certs/client/tls.crt").build(a_request())
|
|
727
727
|
assert not any(arg.startswith("--tls") for arg in buildctl.argv)
|
|
728
728
|
|
|
729
|
+
def test_the_steps_go_through_the_pools_proxy(self, monkeypatch) -> None:
|
|
730
|
+
"""The build pool lets a step reach the network only through its
|
|
731
|
+
proxy (E1-06), so every step is handed it, in both spellings."""
|
|
732
|
+
monkeypatch.setenv("DATALAYER_BUILDKIT_PROXY", "http://127.0.0.1:3128")
|
|
733
|
+
buildctl = Buildctl()
|
|
734
|
+
a_builder(run=buildctl).build(a_request())
|
|
735
|
+
for name in ("HTTP_PROXY", "HTTPS_PROXY", "http_proxy", "https_proxy"):
|
|
736
|
+
assert f"build-arg:{name}=http://127.0.0.1:3128" in buildctl.argv
|
|
737
|
+
assert "build-arg:NO_PROXY=127.0.0.1,localhost" in buildctl.argv
|
|
738
|
+
|
|
739
|
+
def test_no_proxy_when_none_is_set(self, monkeypatch) -> None:
|
|
740
|
+
"""A `buildkitd` whose steps reach the network directly needs none."""
|
|
741
|
+
monkeypatch.delenv("DATALAYER_BUILDKIT_PROXY", raising=False)
|
|
742
|
+
buildctl = Buildctl()
|
|
743
|
+
a_builder(run=buildctl).build(a_request())
|
|
744
|
+
assert not any("proxy" in arg.lower() for arg in buildctl.argv)
|
|
745
|
+
|
|
746
|
+
def test_a_proxy_that_is_not_http_host_port_is_refused(self) -> None:
|
|
747
|
+
with pytest.raises(ValueError, match="DATALAYER_BUILDKIT_PROXY"):
|
|
748
|
+
a_builder(proxy="socks5://127.0.0.1:1080")
|
|
749
|
+
|
|
729
750
|
def test_the_docker_config_does_not_outlive_the_build(self) -> None:
|
|
730
751
|
"""A registry password base64'd into a file the worker keeps forever
|
|
731
752
|
is a credential leak on disk, whichever way the build ends (found on
|
|
@@ -166,6 +166,10 @@ class FakeImage:
|
|
|
166
166
|
self.calls.append(Call("entrypoint", (commands,)))
|
|
167
167
|
return self
|
|
168
168
|
|
|
169
|
+
def cmd(self, command: list[str]) -> FakeImage:
|
|
170
|
+
self.calls.append(Call("cmd", (command,)))
|
|
171
|
+
return self
|
|
172
|
+
|
|
169
173
|
def build(self, app: Any) -> FakeImage:
|
|
170
174
|
self.calls.append(Call("build", (app,)))
|
|
171
175
|
# Simulates Modal's own `enable_output()` printing straight to
|
|
@@ -601,14 +605,24 @@ class TestBuildingAnImage:
|
|
|
601
605
|
[image] = modal.Image.created
|
|
602
606
|
assert not any("doctor" in call.args[0] for call in calls_named(image, "run_commands"))
|
|
603
607
|
|
|
604
|
-
def
|
|
608
|
+
def test_the_chain_ends_with_workdir_entrypoint_and_cmd(self) -> None:
|
|
605
609
|
modal = FakeModalModule()
|
|
606
610
|
a_builder(modal=modal).build(a_request())
|
|
607
611
|
[image] = modal.Image.created
|
|
608
|
-
# `build` is appended by `FakeImage.build` itself; the
|
|
609
|
-
# are the chain's own last words.
|
|
612
|
+
# `build` is appended by `FakeImage.build` itself; the three before
|
|
613
|
+
# it are the chain's own last words.
|
|
610
614
|
names = [call.name for call in image.calls]
|
|
611
|
-
assert names[-
|
|
615
|
+
assert names[-4:] == ["workdir", "entrypoint", "cmd", "build"]
|
|
616
|
+
|
|
617
|
+
def test_the_bases_jupyter_cmd_is_replaced_by_sleep(self) -> None:
|
|
618
|
+
"""Modal keeps the base's `start-jupyter.sh` under a new ENTRYPOINT,
|
|
619
|
+
and a Jupyter server as the main process exits and ends the sandbox
|
|
620
|
+
(found live on 2026-09-18). The artifact says what holds it."""
|
|
621
|
+
modal = FakeModalModule()
|
|
622
|
+
a_builder(modal=modal).build(a_request())
|
|
623
|
+
[image] = modal.Image.created
|
|
624
|
+
[cmd_call] = calls_named(image, "cmd")
|
|
625
|
+
assert cmd_call.args[0] == ["sleep", "infinity"]
|
|
612
626
|
|
|
613
627
|
def test_the_entrypoint_execs_its_arguments(self) -> None:
|
|
614
628
|
"""A bare script path, nothing for `entrypoint()`'s own Dockerfile
|
|
@@ -1315,6 +1315,34 @@ class TestTheBuildkitRunner:
|
|
|
1315
1315
|
)
|
|
1316
1316
|
assert not any(arg.startswith("--tls") for arg in seen["argv"])
|
|
1317
1317
|
|
|
1318
|
+
def test_the_solve_goes_through_the_pools_proxy(self, monkeypatch) -> None:
|
|
1319
|
+
"""The solve reaches the index the way a build does, through the
|
|
1320
|
+
build pool's proxy (E1-06)."""
|
|
1321
|
+
import subprocess as subprocess_module
|
|
1322
|
+
|
|
1323
|
+
from code_sandboxes.environments import resolve as resolve_module
|
|
1324
|
+
from code_sandboxes.environments.resolve import BuildkitResolveRunner
|
|
1325
|
+
|
|
1326
|
+
seen: dict[str, list[str]] = {}
|
|
1327
|
+
|
|
1328
|
+
def fake_run(command, **kwargs):
|
|
1329
|
+
seen["argv"] = list(command)
|
|
1330
|
+
return subprocess_module.CompletedProcess(command, 1, "", "boom")
|
|
1331
|
+
|
|
1332
|
+
monkeypatch.setattr(resolve_module.subprocess, "run", fake_run)
|
|
1333
|
+
with pytest.raises(EnvironmentsError):
|
|
1334
|
+
BuildkitResolveRunner(buildctl="/usr/bin/true", proxy="http://127.0.0.1:3128").solve(
|
|
1335
|
+
ResolveRequest(
|
|
1336
|
+
python_version="3.13",
|
|
1337
|
+
requirements=("ipykernel==7.3.0",),
|
|
1338
|
+
constraints=(),
|
|
1339
|
+
indexes=(),
|
|
1340
|
+
base_reference="environments/base/python-cpu@sha256:" + "11" * 32,
|
|
1341
|
+
)
|
|
1342
|
+
)
|
|
1343
|
+
assert "build-arg:HTTPS_PROXY=http://127.0.0.1:3128" in seen["argv"]
|
|
1344
|
+
assert "build-arg:https_proxy=http://127.0.0.1:3128" in seen["argv"]
|
|
1345
|
+
|
|
1318
1346
|
def test_it_refuses_a_base_that_is_not_pinned_by_digest(self) -> None:
|
|
1319
1347
|
from code_sandboxes.environments.resolve import BuildkitResolveRunner
|
|
1320
1348
|
|
|
@@ -370,6 +370,30 @@ class TestTheRunners:
|
|
|
370
370
|
)
|
|
371
371
|
assert caught.value.code.code == "DL_ENV_CAPABILITY_UNSUPPORTED"
|
|
372
372
|
|
|
373
|
+
def test_the_buildkit_runner_goes_through_the_pools_proxy(
|
|
374
|
+
self, monkeypatch: pytest.MonkeyPatch
|
|
375
|
+
) -> None:
|
|
376
|
+
# The conda solve reaches its channels the way a build does, through
|
|
377
|
+
# the build pool's proxy (E1-06).
|
|
378
|
+
seen: dict[str, list[str]] = {}
|
|
379
|
+
|
|
380
|
+
def fake_run(argv: list[str], **kwargs: object) -> subprocess.CompletedProcess[str]:
|
|
381
|
+
seen["argv"] = list(argv)
|
|
382
|
+
return subprocess.CompletedProcess(argv, 1, stdout="", stderr="boom")
|
|
383
|
+
|
|
384
|
+
monkeypatch.setenv("DATALAYER_BUILDKIT_PROXY", "http://127.0.0.1:3128")
|
|
385
|
+
monkeypatch.setattr("code_sandboxes.environments.resolve_conda.subprocess.run", fake_run)
|
|
386
|
+
runner = BuildkitCondaResolveRunner(buildctl="/usr/bin/buildctl")
|
|
387
|
+
with pytest.raises(EnvironmentsError):
|
|
388
|
+
runner.solve(
|
|
389
|
+
CondaResolveRequest(
|
|
390
|
+
environment_yml=A_YAML,
|
|
391
|
+
python_version="3.13",
|
|
392
|
+
base_reference="base@sha256:" + "11" * 32,
|
|
393
|
+
)
|
|
394
|
+
)
|
|
395
|
+
assert "build-arg:https_proxy=http://127.0.0.1:3128" in seen["argv"]
|
|
396
|
+
|
|
373
397
|
def test_the_buildkit_runner_refuses_an_unpinned_base(self) -> None:
|
|
374
398
|
runner = BuildkitCondaResolveRunner(buildctl="/usr/bin/buildctl")
|
|
375
399
|
with pytest.raises(EnvironmentsError) as caught:
|
|
@@ -493,6 +493,57 @@ def test_modal_start_forwards_gpu_flavor(monkeypatch):
|
|
|
493
493
|
sandbox.stop()
|
|
494
494
|
|
|
495
495
|
|
|
496
|
+
def test_an_environments_artifact_is_held_by_sleep_not_its_cmd(monkeypatch):
|
|
497
|
+
"""An artifact's CMD may be its base's `start-jupyter.sh`, which exits and
|
|
498
|
+
ends the sandbox (found live on 2026-09-18): the launch names the command
|
|
499
|
+
that holds the container, and Jupyter is started by exec when asked."""
|
|
500
|
+
|
|
501
|
+
class _FakeApp:
|
|
502
|
+
pass
|
|
503
|
+
|
|
504
|
+
class _FakeSandboxObj:
|
|
505
|
+
object_id = "modal-object-id"
|
|
506
|
+
|
|
507
|
+
def exec(self, *_args, **_kwargs):
|
|
508
|
+
raise RuntimeError("no driver in this test")
|
|
509
|
+
|
|
510
|
+
def terminate(self):
|
|
511
|
+
return None
|
|
512
|
+
|
|
513
|
+
def detach(self):
|
|
514
|
+
return None
|
|
515
|
+
|
|
516
|
+
captured: dict = {}
|
|
517
|
+
|
|
518
|
+
class _FakeModal:
|
|
519
|
+
class App:
|
|
520
|
+
@staticmethod
|
|
521
|
+
def lookup(_name, create_if_missing=False):
|
|
522
|
+
return _FakeApp()
|
|
523
|
+
|
|
524
|
+
class Image:
|
|
525
|
+
@staticmethod
|
|
526
|
+
def from_id(image_id):
|
|
527
|
+
captured["image_id"] = image_id
|
|
528
|
+
return object()
|
|
529
|
+
|
|
530
|
+
class Sandbox:
|
|
531
|
+
@staticmethod
|
|
532
|
+
def create(*args, **kwargs):
|
|
533
|
+
captured["args"] = args
|
|
534
|
+
return _FakeSandboxObj()
|
|
535
|
+
|
|
536
|
+
monkeypatch.setitem(sys.modules, "modal", _FakeModal)
|
|
537
|
+
|
|
538
|
+
sandbox = ModalSandbox(config=SandboxConfig(timeout=10.0), image_id="im-artifact")
|
|
539
|
+
sandbox.start()
|
|
540
|
+
|
|
541
|
+
assert captured["image_id"] == "im-artifact"
|
|
542
|
+
assert captured["args"] == ("sleep", "infinity")
|
|
543
|
+
|
|
544
|
+
sandbox.stop()
|
|
545
|
+
|
|
546
|
+
|
|
496
547
|
class _FakeExecSandbox:
|
|
497
548
|
"""Records what `_start_driver` asks `sandbox.exec` for, nothing more."""
|
|
498
549
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/adapters/__init__.py
RENAMED
|
File without changes
|
{code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/adapters/daytona.py
RENAMED
|
File without changes
|
|
File without changes
|
{code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/adapters/managed.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/build_secrets.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{code_sandboxes-1.9.35 → code_sandboxes-1.9.36}/code_sandboxes/environments/doctor/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|