code-sandboxes 1.9.20__tar.gz → 1.9.22__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.20 → code_sandboxes-1.9.22}/PKG-INFO +1 -1
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/__version__.py +1 -1
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/adapters/daytona.py +85 -1
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/adapters/managed.py +18 -1
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/attest.py +30 -1
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/conformance.py +31 -3
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_environment_attest.py +54 -15
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_environment_daytona_builder.py +96 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_environment_managed_builders.py +5 -4
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/.github/workflows/build.yml +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/.github/workflows/environments-live.yml +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/.github/workflows/py-code-style.yml +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/.github/workflows/py-tests.yml +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/.github/workflows/py-typing.yml +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/.github/workflows/reusable-python.yml +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/.gitignore +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/.licenserc.yaml +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/.pre-commit-config.yaml +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/.vscode/settings.json +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/CHANGELOG.md +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/Dockerfile +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/LICENSE +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/Makefile +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/README.md +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/__init__.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/base.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/bridge_mount.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/builds.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/cli.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/client.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/cloudflare_sandbox.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/commands.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/console.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/contents.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/coreweave_sandbox.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/datalayer_sandbox.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/daytona_sandbox.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/docker_sandbox.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/e2b_sandbox.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/__init__.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/__main__.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/accounts.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/adapters/__init__.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/adapters/datalayer.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/adapters/e2b.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/adapters/modal.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/bases.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/breaker.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/build_secrets.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/builders.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/canonical.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/constraints/sandbox-contract-v1.txt +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/constraints/wheelhouse/README.md +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/constraints/wheelhouse/jupyter_server-2.21.0+datalayer.1-py3-none-any.whl +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/contract.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/doctor/__init__.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/doctor/build.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/doctor/datalayer_sandbox.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/doctor/report.schema.json +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/errors.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/files.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/image_import.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/lifecycle.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/policy.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/redact.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/resolve.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/resolve_conda.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/schema.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/spec.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/eval_sandbox.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/exceptions.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/filesystem.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/google_colab.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/google_colab_sandbox.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/interfaces.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/jupyter_ingress.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/jupyter_server_sandbox.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/kaggle.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/kaggle_execute.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/kaggle_live.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/kaggle_sandbox.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/lifecycle.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/manage.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/modal_sandbox.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/models.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/monty_sandbox.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/provider_ingress.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/providers.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docker/Dockerfile +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/.gitignore +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/LICENSE +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/Makefile +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/README.md +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/babel.config.js +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/api-reference/_category_.yml +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/api-reference/index.mdx +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/cli/_category_.yml +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/cli/index.mdx +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/contribute/_category_.yml +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/contribute/index.mdx +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/environments/_category_.yml +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/environments/contract.mdx +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/environments/index.mdx +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/environments/specification.mdx +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/environments/spike-2026-09.mdx +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/examples/_category_.yml +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/examples/index.mdx +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/guide/_category_.yml +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/guide/index.mdx +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/index.mdx +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/install/_category_.yml +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/install/index.mdx +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/provider-ingress.mdx +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/providers/_category_.yml +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/providers/cloudflare.mdx +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/providers/coreweave.mdx +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/providers/datalayer.mdx +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/providers/daytona.mdx +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/providers/docker.mdx +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/providers/e2b.mdx +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/providers/eval.mdx +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/providers/google-colab.mdx +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/providers/index.mdx +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/providers/jupyter-server.mdx +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/providers/kaggle.mdx +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/providers/modal.mdx +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docs/providers/monty.mdx +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/docusaurus.config.js +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/package.json +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/sidebars.js +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/src/components/HomepageRow1.js +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/src/components/HomepageRow1.module.css +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/src/components/HomepageRow2.js +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/src/components/HomepageRow2.module.css +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/src/components/HomepageRow3.js +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/src/components/HomepageRow3.module.css +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/src/css/custom.css +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/src/pages/index.module.css +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/src/pages/markdown-page.md +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/src/theme/CustomDocItem.tsx +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/src/theme/IconsTitle.tsx +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/static/img/bricks.svg +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/static/img/building-construction.svg +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/static/img/cloud-sun.svg +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/static/img/cloud.svg +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/static/img/collaboration.svg +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/static/img/copy-left.svg +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/static/img/datalayer/logo.png +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/static/img/datalayer/logo.svg +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/static/img/datalayer/personas/business.svg +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/static/img/datalayer/personas/data-scientist.svg +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/static/img/datalayer/personas/devops.svg +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/static/img/datalayer/project/project-line.svg +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/static/img/favicon.ico +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/static/img/jupyter.svg +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/static/img/open-source.svg +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/static/img/react-js.svg +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/static/img/react-js2.svg +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/static/img/ringed-planet.svg +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/static/img/robot.svg +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/static/img/rocket.svg +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/static/img/shield.svg +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/static/img/sparkles.svg +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/static/img/streamlit.gif +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/static/img/super-hero.svg +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/static/img/target.svg +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/docs/static/img/thumbs-up.svg +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/examples/README.md +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/examples/exec/Makefile +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/examples/exec/cloudflare_sandbox_example.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/examples/exec/coreweave_sandbox_example.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/examples/exec/datalayer_sandbox_example.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/examples/exec/daytona_sandbox_example.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/examples/exec/docker_sandbox_example.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/examples/exec/e2b_sandbox_example.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/examples/exec/eval_sandbox_example.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/examples/exec/google_colab_sandbox_example.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/examples/exec/jupyter_server_sandbox_example.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/examples/exec/kaggle_sandbox_example.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/examples/exec/modal_sandbox_example.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/examples/exec/monty_sandbox_example.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/examples/repl/Makefile +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/examples/repl/cloudflare_sandbox_example.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/examples/repl/coreweave_sandbox_example.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/examples/repl/datalayer_sandbox_example.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/examples/repl/daytona_sandbox_example.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/examples/repl/docker_sandbox_example.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/examples/repl/e2b_sandbox_example.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/examples/repl/eval_sandbox_example.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/examples/repl/google_colab_sandbox_example.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/examples/repl/jupyter_server_sandbox_example.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/examples/repl/kaggle_sandbox_example.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/examples/repl/modal_sandbox_example.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/examples/repl/monty_sandbox_example.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/pyproject.toml +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/schemas/environment-v1alpha1.json +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/__init__.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/conftest.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_a_datalayer_sandbox_can_be_interrupted.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_bridge_mount.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_builds.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_cli_exec.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_cli_repl.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_client.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_client_contents.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_client_files.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_client_outcome_error_output.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_cloudflare.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_commands_envelope.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_console.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_contents_contract.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_contents_live_matrix.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_coreweave.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_datalayer_sandbox.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_daytona.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_e2b.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_environment_accounts.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_environment_bases.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_environment_breaker.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_environment_build_secrets.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_environment_builders.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_environment_canonical.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_environment_conformance.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_environment_constraints.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_environment_contract.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_environment_cross_variant_report.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_environment_datalayer_builder.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_environment_doctor.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_environment_e2b_builder.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_environment_errors.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_environment_image_import.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_environment_lifecycle.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_environment_live_matrix.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_environment_modal_builder.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_environment_redact.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_environment_resolve.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_environment_resolve_conda.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_environment_spec.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_eval.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_every_variant_has_a_real_interrupt.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_factory.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_google_colab.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_integration.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_jupyter_ingress.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_jupyter_server.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_jupyter_server_streaming.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_kaggle.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_kaggle_execute.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_kaggle_live.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_kaggle_session.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_kernel_client_compatibility.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_lifecycle_vocabulary.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_manage.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_manage_datalayer.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_modal_google_colab_sandbox.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_modal_session.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_models.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_output_line_fidelity.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_provider_catalog_names.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_provider_ingress.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_providers.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_sandboxes.py +0 -0
- {code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/tests/test_the_kill_relaunch_drill.py +0 -0
{code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/adapters/daytona.py
RENAMED
|
@@ -90,7 +90,7 @@ from __future__ import annotations
|
|
|
90
90
|
import shlex
|
|
91
91
|
import tempfile
|
|
92
92
|
import uuid
|
|
93
|
-
from collections.abc import Callable
|
|
93
|
+
from collections.abc import Callable, Sequence
|
|
94
94
|
from pathlib import Path
|
|
95
95
|
from typing import Any
|
|
96
96
|
|
|
@@ -100,6 +100,7 @@ from ..builders import (
|
|
|
100
100
|
ArtifactReference,
|
|
101
101
|
BuildRequest,
|
|
102
102
|
CapabilityFinding,
|
|
103
|
+
ValidationResult,
|
|
103
104
|
)
|
|
104
105
|
from ..contract import SANDBOX_CONTRACT_V1
|
|
105
106
|
from ..errors import (
|
|
@@ -567,6 +568,89 @@ class Builder(ManagedBuilder):
|
|
|
567
568
|
raise self._provider_error("ask whether the snapshot exists", error) from error
|
|
568
569
|
return True
|
|
569
570
|
|
|
571
|
+
def smoke_test(
|
|
572
|
+
self,
|
|
573
|
+
artifact: ArtifactReference,
|
|
574
|
+
*,
|
|
575
|
+
environment: Any = None,
|
|
576
|
+
lock_text: str | None = None,
|
|
577
|
+
secret_values: Sequence[str] = (),
|
|
578
|
+
) -> ValidationResult:
|
|
579
|
+
"""Launch the snapshot and run Appendix B's core tier in it (E2-04).
|
|
580
|
+
|
|
581
|
+
This box's own `Done when` asks for exactly this — "a sandbox launched
|
|
582
|
+
from its id passes the core tier" — and until 2026-09-17 it refused
|
|
583
|
+
through `ManagedBuilder`, so **no Daytona build could reach
|
|
584
|
+
`succeeded`**: the workflow calls this step, the snapshot was built and
|
|
585
|
+
live at the provider, and the build was recorded failed.
|
|
586
|
+
|
|
587
|
+
**Launched by id, never by name** (E0-04): a Daytona sandbox record
|
|
588
|
+
keeps the snapshot's *name*, and a name is republished, so only the id
|
|
589
|
+
says which artifact actually ran.
|
|
590
|
+
|
|
591
|
+
**Restarted by stopping and starting the sandbox**, not the kernel
|
|
592
|
+
(E0-04 again): Daytona's own daemon is PID 1 here, so there is no
|
|
593
|
+
kernel to restart, and check 8 means the thing that survives a real
|
|
594
|
+
restart.
|
|
595
|
+
|
|
596
|
+
The sandbox is deleted whether the tier passed or not — a smoke test
|
|
597
|
+
that leaves a sandbox running bills the owner for a check.
|
|
598
|
+
"""
|
|
599
|
+
if environment is None:
|
|
600
|
+
raise EnvironmentsError(
|
|
601
|
+
CAPABILITY_UNSUPPORTED,
|
|
602
|
+
"A Daytona smoke test needs the version's spec: the core tier "
|
|
603
|
+
"asks for the Python version it declared and the packages its "
|
|
604
|
+
"lock pinned, and an artifact carries neither",
|
|
605
|
+
detail={"variant": self.variant},
|
|
606
|
+
)
|
|
607
|
+
from ..conformance import expected_packages, run_core_tier
|
|
608
|
+
|
|
609
|
+
snapshot = artifact.provider_artifact_id or artifact.immutable_reference
|
|
610
|
+
sandbox = self._smoke_test_sandbox(snapshot)
|
|
611
|
+
self._log(f"Launching {snapshot} to smoke-test it")
|
|
612
|
+
try:
|
|
613
|
+
sandbox.start()
|
|
614
|
+
return run_core_tier(
|
|
615
|
+
sandbox,
|
|
616
|
+
python_version=environment.spec.language.version,
|
|
617
|
+
expected_packages=expected_packages(environment, lock_text or ""),
|
|
618
|
+
secret_values=tuple(secret_values),
|
|
619
|
+
restart=lambda: self._restart(sandbox),
|
|
620
|
+
)
|
|
621
|
+
except EnvironmentsError:
|
|
622
|
+
raise
|
|
623
|
+
except Exception as error:
|
|
624
|
+
raise self._provider_error("smoke-test the snapshot", error) from error
|
|
625
|
+
finally:
|
|
626
|
+
try:
|
|
627
|
+
sandbox.stop()
|
|
628
|
+
except Exception as error:
|
|
629
|
+
self._log(f"The smoke-test sandbox could not be stopped: {error}")
|
|
630
|
+
|
|
631
|
+
def _smoke_test_sandbox(self, snapshot: str) -> Any:
|
|
632
|
+
"""A sandbox of this build's own snapshot, deleted when it stops."""
|
|
633
|
+
from ...daytona_sandbox import DaytonaSandbox
|
|
634
|
+
|
|
635
|
+
secrets = self._provider_secrets()
|
|
636
|
+
return DaytonaSandbox(
|
|
637
|
+
api_key=secrets.get("DAYTONA_API_KEY"),
|
|
638
|
+
organization_id=secrets.get("DAYTONA_ORGANIZATION_ID"),
|
|
639
|
+
snapshot=snapshot,
|
|
640
|
+
delete_on_stop=True,
|
|
641
|
+
)
|
|
642
|
+
|
|
643
|
+
@staticmethod
|
|
644
|
+
def _restart(sandbox: Any) -> None:
|
|
645
|
+
"""Check 8's restart, as Daytona can do it.
|
|
646
|
+
|
|
647
|
+
Its daemon is PID 1, so there is no kernel to restart: the sandbox
|
|
648
|
+
itself is stopped and started, which is the stronger version of the
|
|
649
|
+
same question.
|
|
650
|
+
"""
|
|
651
|
+
sandbox.stop()
|
|
652
|
+
sandbox.start()
|
|
653
|
+
|
|
570
654
|
def _provider_error(self, what: str, error: BaseException) -> EnvironmentsError:
|
|
571
655
|
return EnvironmentsError(
|
|
572
656
|
PROVIDER_ERROR,
|
{code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/adapters/managed.py
RENAMED
|
@@ -24,6 +24,7 @@ An SDK imported at module scope would turn `validate` into a 500.
|
|
|
24
24
|
|
|
25
25
|
from __future__ import annotations
|
|
26
26
|
|
|
27
|
+
from collections.abc import Sequence
|
|
27
28
|
from typing import Any, Callable
|
|
28
29
|
|
|
29
30
|
from ..builders import (
|
|
@@ -261,7 +262,23 @@ class ManagedBuilder:
|
|
|
261
262
|
def inspect(self, artifact: ArtifactReference) -> ArtifactMetadata:
|
|
262
263
|
raise self._not_built("inspect an artifact")
|
|
263
264
|
|
|
264
|
-
def smoke_test(
|
|
265
|
+
def smoke_test(
|
|
266
|
+
self,
|
|
267
|
+
artifact: ArtifactReference,
|
|
268
|
+
*,
|
|
269
|
+
environment: Any = None,
|
|
270
|
+
lock_text: str | None = None,
|
|
271
|
+
secret_values: Sequence[str] = (),
|
|
272
|
+
) -> ValidationResult:
|
|
273
|
+
"""Launch the artifact and run Appendix B's core tier in it (E2-03/04/05).
|
|
274
|
+
|
|
275
|
+
`environment` and `lock_text` are what the core tier needs and an
|
|
276
|
+
artifact does not carry: the Python version the spec asks for and the
|
|
277
|
+
packages its lock pins. The caller has both — it read them to build —
|
|
278
|
+
and passes them rather than making every adapter fetch them again.
|
|
279
|
+
They are keyword-only and optional so a caller that has neither still
|
|
280
|
+
type-checks, and an adapter that needs them says so itself.
|
|
281
|
+
"""
|
|
265
282
|
raise self._not_built("smoke-test an artifact")
|
|
266
283
|
|
|
267
284
|
def resolve(self, version_ref: str) -> ArtifactReference:
|
|
@@ -675,14 +675,43 @@ def attest_artifact(
|
|
|
675
675
|
answers the mapping the workflow stores: the scan's decision, the
|
|
676
676
|
signature, the SBOM and provenance references, and the size.
|
|
677
677
|
"""
|
|
678
|
+
variant = str(getattr(artifact, "variant", "") or "")
|
|
678
679
|
reference = str(getattr(artifact, "immutable_reference", "") or "")
|
|
680
|
+
if variant and variant != "datalayer":
|
|
681
|
+
# D-11 is about the Datalayer artifact: it lives in this platform's
|
|
682
|
+
# registry, the scanner reads it there, cosign signs that digest, and
|
|
683
|
+
# the Operator refuses to start what is unsigned. A managed artifact
|
|
684
|
+
# is none of those things — it lives in the owner's own provider
|
|
685
|
+
# account (D-8) and is referenced the way that provider names it: a
|
|
686
|
+
# Daytona snapshot uuid, an E2B build id, a Modal `im-…`. There is no
|
|
687
|
+
# digest in a repository to scan or sign, and no Operator starting it.
|
|
688
|
+
#
|
|
689
|
+
# Attesting one anyway is what the first real Daytona build did, and
|
|
690
|
+
# it failed *after* the snapshot was built — the work done, the
|
|
691
|
+
# artifact live at the provider, and the build recorded as failed
|
|
692
|
+
# (2026-09-17).
|
|
693
|
+
#
|
|
694
|
+
# Publishing is not weakened by this: E2-15's gate requires the
|
|
695
|
+
# **Datalayer** artifact to have passed its scan, and that one is
|
|
696
|
+
# still attested here.
|
|
697
|
+
if log:
|
|
698
|
+
log(f"{variant} artifacts are not attested: {reference} is not a digest in a registry")
|
|
699
|
+
return {
|
|
700
|
+
"scan_summary": {},
|
|
701
|
+
"sbom_ref": "",
|
|
702
|
+
"provenance_ref": "",
|
|
703
|
+
"signature_ref": "",
|
|
704
|
+
"size_bytes": size_bytes,
|
|
705
|
+
"signed_now": False,
|
|
706
|
+
"licenses": [],
|
|
707
|
+
}
|
|
679
708
|
registry, _, rest = reference.partition("/")
|
|
680
709
|
repository, _, digest = rest.partition("@")
|
|
681
710
|
if not (registry and repository and _DIGEST.match(digest)):
|
|
682
711
|
raise EnvironmentsError(
|
|
683
712
|
PROVIDER_ERROR,
|
|
684
713
|
f"`{reference}` is not a digest in a repository, so it cannot be attested",
|
|
685
|
-
detail={"reference": reference},
|
|
714
|
+
detail={"reference": reference, "variant": variant},
|
|
686
715
|
)
|
|
687
716
|
use = attestor or Attestor(
|
|
688
717
|
key=str(getattr(credential, "signing_key", "") or ""),
|
|
@@ -457,6 +457,36 @@ def _secrets(
|
|
|
457
457
|
)
|
|
458
458
|
|
|
459
459
|
|
|
460
|
+
def expected_packages(environment: Any, lock_text: str) -> dict[str, str]:
|
|
461
|
+
"""Each top-level distribution the spec names, pinned to what its lock resolved.
|
|
462
|
+
|
|
463
|
+
What Appendix B check 5 is given. Never every package the lock pins — most
|
|
464
|
+
of a real lock is transitive, and check 5 tries to *import* each name it is
|
|
465
|
+
handed; a build tool or a C-library-only wheel that was never meant to be
|
|
466
|
+
imported directly would fail a check with nothing wrong to report. The
|
|
467
|
+
spec's own `packages.python.dependencies` is what a person declared
|
|
468
|
+
wanting, so it is what disagreeing across variants (E2-08) means something
|
|
469
|
+
about.
|
|
470
|
+
|
|
471
|
+
Here rather than in the durable worker, which had the only copy, so that a
|
|
472
|
+
builder running its own smoke test asks the same question of its own
|
|
473
|
+
artifact (E2-03/04/05).
|
|
474
|
+
"""
|
|
475
|
+
from packaging.requirements import InvalidRequirement, Requirement
|
|
476
|
+
from packaging.utils import canonicalize_name
|
|
477
|
+
|
|
478
|
+
from .resolve import locked_versions
|
|
479
|
+
|
|
480
|
+
pinned = locked_versions(lock_text) if lock_text else {}
|
|
481
|
+
names: list[str] = []
|
|
482
|
+
for text in environment.spec.packages.python.dependencies:
|
|
483
|
+
try:
|
|
484
|
+
names.append(canonicalize_name(Requirement(text).name))
|
|
485
|
+
except InvalidRequirement:
|
|
486
|
+
continue
|
|
487
|
+
return {name: pinned[name] for name in names if name in pinned}
|
|
488
|
+
|
|
489
|
+
|
|
460
490
|
def run_core_tier(
|
|
461
491
|
sandbox: Sandbox,
|
|
462
492
|
*,
|
|
@@ -551,9 +581,7 @@ def _gpu(sandbox: Sandbox, requested: bool, cuda: str | None, timeout: float | N
|
|
|
551
581
|
# version its spec describes. A version that asked for none never
|
|
552
582
|
# reaches here (the trivial pass above), so the extended tier still
|
|
553
583
|
# gates nothing for a CPU version.
|
|
554
|
-
return _result(
|
|
555
|
-
11, not problems, gating=True, detail="; ".join(problems) or None, actual=answer
|
|
556
|
-
)
|
|
584
|
+
return _result(11, not problems, gating=True, detail="; ".join(problems) or None, actual=answer)
|
|
557
585
|
|
|
558
586
|
|
|
559
587
|
def _throughput(
|
|
@@ -19,12 +19,13 @@ from __future__ import annotations
|
|
|
19
19
|
|
|
20
20
|
import json
|
|
21
21
|
import subprocess
|
|
22
|
+
from types import SimpleNamespace
|
|
22
23
|
|
|
23
24
|
import pytest
|
|
24
25
|
|
|
25
26
|
from code_sandboxes.environments.attest import Attestor, attest_artifact, licenses_of, signature_tag
|
|
26
27
|
from code_sandboxes.environments.builders import ArtifactReference
|
|
27
|
-
from code_sandboxes.environments.errors import EnvironmentsError
|
|
28
|
+
from code_sandboxes.environments.errors import PROVIDER_ERROR, EnvironmentsError
|
|
28
29
|
from code_sandboxes.environments.policy import (
|
|
29
30
|
DEFAULT_POLICY,
|
|
30
31
|
Finding,
|
|
@@ -613,27 +614,25 @@ class TestAttestingAnArtifact:
|
|
|
613
614
|
assert cosign.argv == [], "a blocked artifact must not be signed"
|
|
614
615
|
|
|
615
616
|
def test_a_reference_that_is_not_a_digest_cannot_be_attested(self) -> None:
|
|
616
|
-
artifact
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
)
|
|
617
|
+
"""A `datalayer` artifact must be a digest in this platform's registry.
|
|
618
|
+
|
|
619
|
+
`attest_artifact` takes `artifact: Any`, so nothing guarantees every
|
|
620
|
+
caller went through the model validator that would have refused this.
|
|
621
|
+
"""
|
|
622
|
+
artifact = SimpleNamespace(variant="datalayer", immutable_reference="im-1234567890")
|
|
622
623
|
with pytest.raises(EnvironmentsError) as raised:
|
|
623
624
|
attest_artifact(artifact=artifact, attestor=an_attestor())
|
|
624
625
|
assert raised.value.code.code == "DL_ENV_PROVIDER_ERROR"
|
|
625
626
|
|
|
626
627
|
def test_a_malformed_digest_cannot_be_attested_either(self) -> None:
|
|
627
628
|
"""`sha256:bad` starts with `sha256:` too: only a whole one is
|
|
628
|
-
accepted (found on PR #27's Copilot review).
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
artifact =
|
|
633
|
-
variant="
|
|
629
|
+
accepted (found on PR #27's Copilot review). Asked of `datalayer`,
|
|
630
|
+
since that is the variant this check is for — `attest_artifact` takes
|
|
631
|
+
`artifact: Any`, so nothing guarantees every caller went through the
|
|
632
|
+
model validator that would have refused it."""
|
|
633
|
+
artifact = SimpleNamespace(
|
|
634
|
+
variant="datalayer",
|
|
634
635
|
immutable_reference=f"{REGISTRY}/{REPOSITORY}@sha256:bad",
|
|
635
|
-
provider_artifact_id="sha256:bad",
|
|
636
|
-
contract_version="sandbox-contract/v1",
|
|
637
636
|
)
|
|
638
637
|
with pytest.raises(EnvironmentsError) as raised:
|
|
639
638
|
attest_artifact(artifact=artifact, attestor=an_attestor())
|
|
@@ -749,3 +748,43 @@ class TestLicencesFromTheSbom:
|
|
|
749
748
|
"""Never a reason to fail a build: a licence list is worth having, not dying for."""
|
|
750
749
|
for document in (None, {}, {"packages": None}, {"components": [1, 2]}, "spdx"):
|
|
751
750
|
assert licenses_of(document) == []
|
|
751
|
+
|
|
752
|
+
|
|
753
|
+
class TestWhatIsAttestedAndWhatIsNot:
|
|
754
|
+
"""D-11 is about the Datalayer artifact, not every artifact.
|
|
755
|
+
|
|
756
|
+
It lives in this platform's registry: the scanner reads it there, cosign
|
|
757
|
+
signs that digest, and the Operator refuses to start what is unsigned. A
|
|
758
|
+
managed artifact is none of those things — it lives in the owner's own
|
|
759
|
+
provider account (D-8), named the way that provider names it.
|
|
760
|
+
"""
|
|
761
|
+
|
|
762
|
+
def _artifact(self, variant: str, reference: str):
|
|
763
|
+
return SimpleNamespace(variant=variant, immutable_reference=reference)
|
|
764
|
+
|
|
765
|
+
def test_a_daytona_snapshot_is_not_attested(self) -> None:
|
|
766
|
+
"""Its reference is a uuid, and attesting it anyway failed the first
|
|
767
|
+
real Daytona build *after* the snapshot was already built
|
|
768
|
+
(2026-09-17)."""
|
|
769
|
+
answer = attest_artifact(
|
|
770
|
+
artifact=self._artifact("daytona", "51d10ab0-d98d-4117-bdb5-918e98646c92"),
|
|
771
|
+
size_bytes=1234,
|
|
772
|
+
)
|
|
773
|
+
assert answer["scan_summary"] == {}
|
|
774
|
+
assert answer["signature_ref"] == ""
|
|
775
|
+
assert answer["signed_now"] is False
|
|
776
|
+
# What the provider told us is still recorded.
|
|
777
|
+
assert answer["size_bytes"] == 1234
|
|
778
|
+
|
|
779
|
+
def test_an_e2b_build_id_and_a_modal_image_id_are_not_either(self) -> None:
|
|
780
|
+
for variant, reference in (("e2b", "bld-123"), ("modal", "im-abc123")):
|
|
781
|
+
answer = attest_artifact(artifact=self._artifact(variant, reference))
|
|
782
|
+
assert answer["signed_now"] is False, variant
|
|
783
|
+
assert answer["scan_summary"] == {}, variant
|
|
784
|
+
|
|
785
|
+
def test_a_datalayer_artifact_that_is_not_a_digest_still_fails(self) -> None:
|
|
786
|
+
"""The check that matters is kept where it means something."""
|
|
787
|
+
with pytest.raises(EnvironmentsError) as raised:
|
|
788
|
+
attest_artifact(artifact=self._artifact("datalayer", "not-a-digest"))
|
|
789
|
+
assert raised.value.code is PROVIDER_ERROR
|
|
790
|
+
assert "cannot be attested" in str(raised.value)
|
|
@@ -833,3 +833,99 @@ class TestReadingTheRegistry:
|
|
|
833
833
|
builder.build(a_request())
|
|
834
834
|
builder.exists(an_artifact(provider_artifact_id="snp-999"))
|
|
835
835
|
assert len(daytona.daytona_calls) == 1
|
|
836
|
+
|
|
837
|
+
|
|
838
|
+
class TestSmokeTestingASnapshot:
|
|
839
|
+
"""E2-04's own `Done when`: a sandbox launched from its id passes the core tier.
|
|
840
|
+
|
|
841
|
+
It refused through `ManagedBuilder` until 2026-09-17, and the build
|
|
842
|
+
workflow calls this step — so no Daytona build could reach `succeeded`:
|
|
843
|
+
the snapshot was built and live at the provider, and the build was
|
|
844
|
+
recorded failed.
|
|
845
|
+
"""
|
|
846
|
+
|
|
847
|
+
def _environment(self):
|
|
848
|
+
return parse_environment(a_request().environment.model_dump(by_alias=True))
|
|
849
|
+
|
|
850
|
+
def test_it_launches_by_id_and_runs_the_core_tier(self, monkeypatch) -> None:
|
|
851
|
+
"""A Daytona sandbox record keeps the snapshot's *name*, and a name is
|
|
852
|
+
republished, so only the id says which artifact ran (E0-04)."""
|
|
853
|
+
made: dict = {}
|
|
854
|
+
ran: dict = {}
|
|
855
|
+
|
|
856
|
+
class FakeSandbox:
|
|
857
|
+
def __init__(self, **kwargs):
|
|
858
|
+
made.update(kwargs)
|
|
859
|
+
self.events: list[str] = []
|
|
860
|
+
|
|
861
|
+
def start(self):
|
|
862
|
+
self.events.append("start")
|
|
863
|
+
|
|
864
|
+
def stop(self):
|
|
865
|
+
self.events.append("stop")
|
|
866
|
+
|
|
867
|
+
builder = a_builder()
|
|
868
|
+
monkeypatch.setattr(
|
|
869
|
+
"code_sandboxes.daytona_sandbox.DaytonaSandbox", FakeSandbox, raising=False
|
|
870
|
+
)
|
|
871
|
+
monkeypatch.setattr(
|
|
872
|
+
"code_sandboxes.environments.conformance.run_core_tier",
|
|
873
|
+
lambda sandbox, **kwargs: ran.update(kwargs) or "the-result",
|
|
874
|
+
)
|
|
875
|
+
|
|
876
|
+
answer = builder.smoke_test(
|
|
877
|
+
an_artifact(
|
|
878
|
+
variant="daytona",
|
|
879
|
+
immutable_reference="snap-1",
|
|
880
|
+
provider_artifact_id="snap-1",
|
|
881
|
+
),
|
|
882
|
+
environment=self._environment(),
|
|
883
|
+
lock_text="",
|
|
884
|
+
)
|
|
885
|
+
assert answer == "the-result"
|
|
886
|
+
assert made["snapshot"] == "snap-1"
|
|
887
|
+
# A smoke test that leaves a sandbox running bills the owner for a check.
|
|
888
|
+
assert made["delete_on_stop"] is True
|
|
889
|
+
assert "restart" in ran and ran["python_version"]
|
|
890
|
+
|
|
891
|
+
def test_the_sandbox_is_deleted_even_when_the_tier_raises(self, monkeypatch) -> None:
|
|
892
|
+
events: list[str] = []
|
|
893
|
+
|
|
894
|
+
class FakeSandbox:
|
|
895
|
+
def __init__(self, **_kwargs):
|
|
896
|
+
pass
|
|
897
|
+
|
|
898
|
+
def start(self):
|
|
899
|
+
events.append("start")
|
|
900
|
+
|
|
901
|
+
def stop(self):
|
|
902
|
+
events.append("stop")
|
|
903
|
+
|
|
904
|
+
monkeypatch.setattr(
|
|
905
|
+
"code_sandboxes.daytona_sandbox.DaytonaSandbox", FakeSandbox, raising=False
|
|
906
|
+
)
|
|
907
|
+
monkeypatch.setattr(
|
|
908
|
+
"code_sandboxes.environments.conformance.run_core_tier",
|
|
909
|
+
lambda *_a, **_k: (_ for _ in ()).throw(RuntimeError("the tier blew up")),
|
|
910
|
+
)
|
|
911
|
+
with pytest.raises(EnvironmentsError):
|
|
912
|
+
a_builder().smoke_test(
|
|
913
|
+
an_artifact(
|
|
914
|
+
variant="daytona", immutable_reference="snap-1", provider_artifact_id="snap-1"
|
|
915
|
+
),
|
|
916
|
+
environment=self._environment(),
|
|
917
|
+
lock_text="",
|
|
918
|
+
)
|
|
919
|
+
assert events == ["start", "stop"]
|
|
920
|
+
|
|
921
|
+
def test_without_a_spec_it_says_what_it_needs(self) -> None:
|
|
922
|
+
"""The core tier asks for the Python version and the pinned packages,
|
|
923
|
+
and an artifact carries neither."""
|
|
924
|
+
with pytest.raises(EnvironmentsError) as raised:
|
|
925
|
+
a_builder().smoke_test(
|
|
926
|
+
an_artifact(
|
|
927
|
+
variant="daytona", immutable_reference="snap-1", provider_artifact_id="snap-1"
|
|
928
|
+
)
|
|
929
|
+
)
|
|
930
|
+
assert raised.value.code is CAPABILITY_UNSUPPORTED
|
|
931
|
+
assert "needs the version's spec" in str(raised.value)
|
|
@@ -379,12 +379,13 @@ class TestTheHalfThatIsNotBuiltYet:
|
|
|
379
379
|
assert raised.value.detail["operation"], f"e2b.{operation}"
|
|
380
380
|
|
|
381
381
|
def test_daytona_still_refuses_what_e2_04_did_not_build(self) -> None:
|
|
382
|
-
"""`build
|
|
383
|
-
|
|
384
|
-
|
|
382
|
+
"""`build`, `inspect`, `exists` and now `smoke_test` are E2-04's —
|
|
383
|
+
the last of them because this box's own `Done when` asks for "a
|
|
384
|
+
sandbox launched from its id passes the core tier", and until it was
|
|
385
|
+
built no Daytona build could reach `succeeded`. `resolve` and `delete`
|
|
386
|
+
are still not built — see test_environment_daytona_builder.py."""
|
|
385
387
|
builder = get_builder("daytona")
|
|
386
388
|
calls = {
|
|
387
|
-
"smoke_test": lambda: builder.smoke_test(None), # type: ignore[arg-type]
|
|
388
389
|
"resolve": lambda: builder.resolve("geo@1"),
|
|
389
390
|
"delete": lambda: builder.delete(None), # type: ignore[arg-type]
|
|
390
391
|
}
|
|
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.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/adapters/__init__.py
RENAMED
|
File without changes
|
{code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/adapters/datalayer.py
RENAMED
|
File without changes
|
|
File without changes
|
{code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/adapters/modal.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/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
|
{code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/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
|
{code_sandboxes-1.9.20 → code_sandboxes-1.9.22}/code_sandboxes/environments/resolve_conda.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
|