code-sandboxes 1.9.7__tar.gz → 1.9.9__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.7 → code_sandboxes-1.9.9}/CHANGELOG.md +26 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/PKG-INFO +1 -1
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/__version__.py +1 -1
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/attest.py +81 -21
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_environment_attest.py +76 -3
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/.github/workflows/build.yml +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/.github/workflows/environments-live.yml +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/.github/workflows/py-code-style.yml +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/.github/workflows/py-tests.yml +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/.github/workflows/py-typing.yml +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/.github/workflows/reusable-python.yml +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/.gitignore +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/.licenserc.yaml +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/.pre-commit-config.yaml +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/.vscode/settings.json +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/Dockerfile +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/LICENSE +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/Makefile +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/README.md +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/build.log +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/__init__.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/base.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/bridge_mount.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/builds.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/cli.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/client.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/cloudflare_sandbox.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/commands.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/console.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/contents.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/coreweave_sandbox.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/datalayer_sandbox.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/daytona_sandbox.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/docker_sandbox.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/e2b_sandbox.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/__init__.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/__main__.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/accounts.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/adapters/__init__.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/adapters/datalayer.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/adapters/daytona.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/adapters/e2b.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/adapters/managed.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/adapters/modal.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/bases.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/breaker.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/build_secrets.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/builders.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/canonical.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/conformance.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/constraints/sandbox-contract-v1.txt +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/constraints/wheelhouse/README.md +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/constraints/wheelhouse/jupyter_server-2.21.0+datalayer.1-py3-none-any.whl +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/contract.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/doctor/__init__.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/doctor/build.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/doctor/datalayer_sandbox.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/doctor/report.schema.json +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/errors.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/files.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/image_import.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/lifecycle.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/policy.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/redact.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/resolve.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/schema.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/spec.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/eval_sandbox.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/exceptions.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/filesystem.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/google_colab.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/google_colab_sandbox.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/interfaces.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/jupyter_ingress.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/jupyter_server_sandbox.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/kaggle.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/kaggle_execute.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/kaggle_live.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/kaggle_sandbox.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/lifecycle.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/manage.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/modal_sandbox.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/models.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/monty_sandbox.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/provider_ingress.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/providers.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docker/Dockerfile +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/.gitignore +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/LICENSE +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/Makefile +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/README.md +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/babel.config.js +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/api-reference/_category_.yml +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/api-reference/index.mdx +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/cli/_category_.yml +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/cli/index.mdx +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/contribute/_category_.yml +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/contribute/index.mdx +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/environments/_category_.yml +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/environments/contract.mdx +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/environments/index.mdx +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/environments/specification.mdx +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/environments/spike-2026-09.mdx +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/examples/_category_.yml +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/examples/index.mdx +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/guide/_category_.yml +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/guide/index.mdx +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/index.mdx +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/install/_category_.yml +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/install/index.mdx +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/provider-ingress.mdx +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/providers/_category_.yml +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/providers/cloudflare.mdx +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/providers/coreweave.mdx +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/providers/datalayer.mdx +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/providers/daytona.mdx +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/providers/docker.mdx +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/providers/e2b.mdx +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/providers/eval.mdx +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/providers/google-colab.mdx +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/providers/index.mdx +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/providers/jupyter-server.mdx +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/providers/kaggle.mdx +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/providers/modal.mdx +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docs/providers/monty.mdx +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/docusaurus.config.js +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/package.json +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/sidebars.js +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/src/components/HomepageRow1.js +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/src/components/HomepageRow1.module.css +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/src/components/HomepageRow2.js +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/src/components/HomepageRow2.module.css +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/src/components/HomepageRow3.js +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/src/components/HomepageRow3.module.css +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/src/css/custom.css +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/src/pages/index.module.css +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/src/pages/markdown-page.md +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/src/theme/CustomDocItem.tsx +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/src/theme/IconsTitle.tsx +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/static/img/bricks.svg +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/static/img/building-construction.svg +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/static/img/cloud-sun.svg +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/static/img/cloud.svg +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/static/img/collaboration.svg +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/static/img/copy-left.svg +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/static/img/datalayer/logo.png +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/static/img/datalayer/logo.svg +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/static/img/datalayer/personas/business.svg +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/static/img/datalayer/personas/data-scientist.svg +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/static/img/datalayer/personas/devops.svg +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/static/img/datalayer/project/project-line.svg +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/static/img/favicon.ico +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/static/img/jupyter.svg +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/static/img/open-source.svg +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/static/img/react-js.svg +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/static/img/react-js2.svg +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/static/img/ringed-planet.svg +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/static/img/robot.svg +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/static/img/rocket.svg +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/static/img/shield.svg +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/static/img/sparkles.svg +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/static/img/streamlit.gif +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/static/img/super-hero.svg +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/static/img/target.svg +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/docs/static/img/thumbs-up.svg +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/examples/README.md +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/examples/exec/Makefile +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/examples/exec/cloudflare_sandbox_example.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/examples/exec/coreweave_sandbox_example.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/examples/exec/datalayer_sandbox_example.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/examples/exec/daytona_sandbox_example.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/examples/exec/docker_sandbox_example.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/examples/exec/e2b_sandbox_example.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/examples/exec/eval_sandbox_example.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/examples/exec/google_colab_sandbox_example.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/examples/exec/jupyter_server_sandbox_example.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/examples/exec/kaggle_sandbox_example.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/examples/exec/modal_sandbox_example.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/examples/exec/monty_sandbox_example.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/examples/repl/Makefile +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/examples/repl/cloudflare_sandbox_example.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/examples/repl/coreweave_sandbox_example.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/examples/repl/datalayer_sandbox_example.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/examples/repl/daytona_sandbox_example.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/examples/repl/docker_sandbox_example.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/examples/repl/e2b_sandbox_example.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/examples/repl/eval_sandbox_example.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/examples/repl/google_colab_sandbox_example.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/examples/repl/jupyter_server_sandbox_example.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/examples/repl/kaggle_sandbox_example.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/examples/repl/modal_sandbox_example.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/examples/repl/monty_sandbox_example.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/pyproject.toml +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/schemas/environment-v1alpha1.json +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/__init__.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/conftest.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_a_datalayer_sandbox_can_be_interrupted.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_bridge_mount.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_builds.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_cli_exec.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_cli_repl.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_client.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_client_contents.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_client_files.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_client_outcome_error_output.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_cloudflare.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_commands_envelope.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_console.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_contents_contract.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_contents_live_matrix.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_coreweave.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_datalayer_sandbox.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_daytona.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_e2b.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_environment_accounts.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_environment_bases.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_environment_breaker.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_environment_build_secrets.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_environment_builders.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_environment_canonical.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_environment_conformance.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_environment_constraints.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_environment_contract.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_environment_cross_variant_report.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_environment_datalayer_builder.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_environment_daytona_builder.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_environment_doctor.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_environment_e2b_builder.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_environment_errors.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_environment_image_import.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_environment_lifecycle.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_environment_live_matrix.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_environment_managed_builders.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_environment_modal_builder.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_environment_redact.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_environment_resolve.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_environment_spec.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_eval.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_every_variant_has_a_real_interrupt.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_factory.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_google_colab.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_integration.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_jupyter_ingress.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_jupyter_server.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_jupyter_server_streaming.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_kaggle.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_kaggle_execute.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_kaggle_live.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_kaggle_session.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_kernel_client_compatibility.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_lifecycle_vocabulary.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_manage.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_manage_datalayer.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_modal_google_colab_sandbox.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_modal_session.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_models.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_output_line_fidelity.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_provider_catalog_names.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_provider_ingress.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_providers.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_sandboxes.py +0 -0
- {code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/tests/test_the_kill_relaunch_drill.py +0 -0
|
@@ -8,6 +8,32 @@
|
|
|
8
8
|
|
|
9
9
|
## Unreleased
|
|
10
10
|
|
|
11
|
+
## 1.9.9
|
|
12
|
+
|
|
13
|
+
- **cosign gets the same registry credential the build pushed with**
|
|
14
|
+
(`environments.attest`; PLAN_ENV.md D-17, E1-09). cosign has no AWS
|
|
15
|
+
credential chain of its own for ECR, unlike the boto3 client the scan is
|
|
16
|
+
read with. Found live on r1, 2026-09-14: `cosign sign` reached the
|
|
17
|
+
repository anonymously and was refused, plain `401 Unauthorized`, on
|
|
18
|
+
every real artifact this pipeline ever tried to sign. `Attestor` takes a
|
|
19
|
+
`registry_auth` — the same `{"DOCKER_CONFIG": <dir>}` shape the resolver
|
|
20
|
+
and the builder already read off a `BuildCredential` — and sets it on
|
|
21
|
+
cosign's own subprocess, added to this process's own environment rather
|
|
22
|
+
than replacing it.
|
|
23
|
+
|
|
24
|
+
## 1.9.8
|
|
25
|
+
|
|
26
|
+
- **Every page of a scan's findings is read before deciding**
|
|
27
|
+
(`environments.attest`; PLAN_ENV.md E1-08, D-11). `describe_image_scan_
|
|
28
|
+
findings` paginates, and the attestor called it exactly once. Found live
|
|
29
|
+
on r1, 2026-09-14: the first real image with more findings than one page
|
|
30
|
+
had 1,547 enhanced findings, 31 of them critical, and the single-page read
|
|
31
|
+
saw a small enough slice that the decision passed — an image with real,
|
|
32
|
+
unreviewed critical vulnerabilities would have been signed and started. A
|
|
33
|
+
hard cap of 50 pages keeps a pathological registry from paginating
|
|
34
|
+
forever; hitting it logs that more findings went unread rather than
|
|
35
|
+
pretending the scan was complete.
|
|
36
|
+
|
|
11
37
|
## 1.9.7
|
|
12
38
|
|
|
13
39
|
- **cosign signs again under `--use-signing-config=false`** (`environments
|
|
@@ -150,6 +150,15 @@ class Attestor:
|
|
|
150
150
|
policy
|
|
151
151
|
What the findings have to say. The owner's default unless an
|
|
152
152
|
organization tightened it (E3-06).
|
|
153
|
+
registry_auth
|
|
154
|
+
What cosign reads the repository with, to sign it (D-17): the same
|
|
155
|
+
`{"DOCKER_CONFIG": <dir>}` shape the resolver and the builder already
|
|
156
|
+
take off a `BuildCredential`, the one attribute name every caller
|
|
157
|
+
reads regardless of what kind of credential it holds. cosign has no
|
|
158
|
+
AWS credential chain of its own for ECR, unlike the boto3 client the
|
|
159
|
+
scan is read with — found live, 2026-09-14: with none, `cosign sign`
|
|
160
|
+
reached the registry anonymously and was refused, `401 Unauthorized`,
|
|
161
|
+
on every real artifact this pipeline ever tried to sign.
|
|
153
162
|
"""
|
|
154
163
|
|
|
155
164
|
def __init__(
|
|
@@ -166,6 +175,7 @@ class Attestor:
|
|
|
166
175
|
scan_timeout_seconds: float = DEFAULT_SCAN_TIMEOUT_SECONDS,
|
|
167
176
|
scan_interval_seconds: float = DEFAULT_SCAN_INTERVAL_SECONDS,
|
|
168
177
|
log: Callable[[str], None] | None = None,
|
|
178
|
+
registry_auth: Mapping[str, str] | None = None,
|
|
169
179
|
) -> None:
|
|
170
180
|
self._ecr = ecr
|
|
171
181
|
self._cosign = (shutil.which("cosign") or "") if cosign is None else cosign
|
|
@@ -178,6 +188,7 @@ class Attestor:
|
|
|
178
188
|
self._timeout = scan_timeout_seconds
|
|
179
189
|
self._interval = scan_interval_seconds
|
|
180
190
|
self._log = log or (lambda _line: None)
|
|
191
|
+
self._registry_auth = dict(registry_auth or {})
|
|
181
192
|
|
|
182
193
|
# -- the scan -------------------------------------------------------------
|
|
183
194
|
|
|
@@ -289,32 +300,70 @@ class Attestor:
|
|
|
289
300
|
detail={"repository": repository, "digest": digest},
|
|
290
301
|
)
|
|
291
302
|
|
|
303
|
+
#: A hard cap on pages read, so a registry that never stops paginating
|
|
304
|
+
#: cannot wedge a build forever — this many pages is already far past any
|
|
305
|
+
#: real image's own finding count (E1-08, found live 2026-09-14: see
|
|
306
|
+
#: `_describe`'s own docstring for why a page limit is not optional).
|
|
307
|
+
_MAX_FINDING_PAGES = 50
|
|
308
|
+
|
|
292
309
|
def _describe(self, *, repository: str, digest: str) -> tuple[str, dict[str, Any]]:
|
|
293
|
-
"""
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
310
|
+
"""Every `DescribeImageScanFindings` page, as one status and one answer.
|
|
311
|
+
|
|
312
|
+
ECR paginates enhanced findings — `nextToken`, not a field this call
|
|
313
|
+
can ask to skip — and a single unpaginated call answers only its first
|
|
314
|
+
page. Found live, 2026-09-14: the first real artifact this pipeline
|
|
315
|
+
scanned had 1,547 enhanced findings across many pages and 31 of them
|
|
316
|
+
critical, and a single-page read passed a decision that should have
|
|
317
|
+
blocked, because none of those 31 were in the one page it happened to
|
|
318
|
+
see. Every page is read and merged before `decide` ever runs.
|
|
319
|
+
"""
|
|
320
|
+
pages = 0
|
|
321
|
+
status = ""
|
|
322
|
+
enhanced: list[Any] = []
|
|
323
|
+
basic: list[Any] = []
|
|
324
|
+
completed_at: Any = None
|
|
325
|
+
token: str | None = None
|
|
326
|
+
while True:
|
|
327
|
+
try:
|
|
328
|
+
kwargs: dict[str, Any] = {
|
|
329
|
+
"repositoryName": repository,
|
|
330
|
+
"imageId": {"imageDigest": digest},
|
|
331
|
+
}
|
|
332
|
+
if token:
|
|
333
|
+
kwargs["nextToken"] = token
|
|
334
|
+
answer = self._client().describe_image_scan_findings(**kwargs)
|
|
335
|
+
except Exception as error:
|
|
336
|
+
if _is_in_progress(error):
|
|
337
|
+
return "IN_PROGRESS", {}
|
|
338
|
+
if _is_missing(error):
|
|
339
|
+
raise EnvironmentsError(
|
|
340
|
+
PROVIDER_ERROR,
|
|
341
|
+
f"The registry has no scan for {digest}: {error}",
|
|
342
|
+
detail={"repository": repository, "digest": digest},
|
|
343
|
+
) from error
|
|
302
344
|
raise EnvironmentsError(
|
|
303
345
|
PROVIDER_ERROR,
|
|
304
|
-
f"The
|
|
346
|
+
f"The scan of {digest} could not be read: {error}",
|
|
305
347
|
detail={"repository": repository, "digest": digest},
|
|
306
348
|
) from error
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
)
|
|
312
|
-
|
|
313
|
-
|
|
349
|
+
status = str(((answer.get("imageScanStatus") or {}).get("status")) or "")
|
|
350
|
+
findings = answer.get("imageScanFindings") or {}
|
|
351
|
+
enhanced.extend(findings.get("enhancedFindings") or [])
|
|
352
|
+
basic.extend(findings.get("findings") or [])
|
|
353
|
+
completed_at = findings.get("imageScanCompletedAt") or completed_at
|
|
354
|
+
pages += 1
|
|
355
|
+
token = answer.get("nextToken")
|
|
356
|
+
if not token or pages >= self._MAX_FINDING_PAGES:
|
|
357
|
+
if token:
|
|
358
|
+
self._log(
|
|
359
|
+
f"Stopped reading {digest}'s scan after {pages} pages, "
|
|
360
|
+
"with more findings still unread"
|
|
361
|
+
)
|
|
362
|
+
break
|
|
314
363
|
return status, {
|
|
315
|
-
"findings": findings,
|
|
316
|
-
"completed_at":
|
|
317
|
-
"scanner": "ECR enhanced" if
|
|
364
|
+
"findings": {"enhancedFindings": enhanced, "findings": basic},
|
|
365
|
+
"completed_at": completed_at,
|
|
366
|
+
"scanner": "ECR enhanced" if enhanced else "ECR basic",
|
|
318
367
|
}
|
|
319
368
|
|
|
320
369
|
@staticmethod
|
|
@@ -421,9 +470,19 @@ class Attestor:
|
|
|
421
470
|
return bool(answer.get("imageDetails"))
|
|
422
471
|
|
|
423
472
|
def _invoke(self, command: Sequence[str]) -> subprocess.CompletedProcess[str]:
|
|
473
|
+
# `registry_auth` — same shape as the resolver's own — puts cosign's
|
|
474
|
+
# `DOCKER_CONFIG` beside the rest of this process's environment,
|
|
475
|
+
# never replacing it: `--key` alone still needs AWS's own chain to
|
|
476
|
+
# reach the KMS key, which this does not touch.
|
|
477
|
+
env = {**os.environ, **self._registry_auth} if self._registry_auth else None
|
|
424
478
|
try:
|
|
425
479
|
finished = self._run(
|
|
426
|
-
list(command),
|
|
480
|
+
list(command),
|
|
481
|
+
capture_output=True,
|
|
482
|
+
text=True,
|
|
483
|
+
check=False,
|
|
484
|
+
timeout=self._timeout,
|
|
485
|
+
env=env,
|
|
427
486
|
)
|
|
428
487
|
except subprocess.TimeoutExpired as expired:
|
|
429
488
|
raise EnvironmentsError(
|
|
@@ -514,6 +573,7 @@ def attest_artifact(
|
|
|
514
573
|
key=str(getattr(credential, "signing_key", "") or ""),
|
|
515
574
|
policy=policy,
|
|
516
575
|
log=log,
|
|
576
|
+
registry_auth=getattr(credential, "registry_auth", None),
|
|
517
577
|
)
|
|
518
578
|
return use.attest(
|
|
519
579
|
registry=registry,
|
|
@@ -90,9 +90,14 @@ class FakeEcr:
|
|
|
90
90
|
enhanced_findings=True,
|
|
91
91
|
signed: set[str] | None = None,
|
|
92
92
|
manifest: dict | None = None,
|
|
93
|
+
pages: list[list[dict]] | None = None,
|
|
93
94
|
) -> None:
|
|
94
95
|
self.statuses = list(statuses)
|
|
95
96
|
self.findings = list(findings)
|
|
97
|
+
#: Each entry is one `describe_image_scan_findings` page's own
|
|
98
|
+
#: findings, read in order and merged by `_describe` — overrides
|
|
99
|
+
#: `findings` when given, to test reading more than one page.
|
|
100
|
+
self.pages = pages
|
|
96
101
|
self.enhanced_findings = enhanced_findings
|
|
97
102
|
self.signed = set(signed or set())
|
|
98
103
|
self.manifest = manifest
|
|
@@ -115,7 +120,7 @@ class FakeEcr:
|
|
|
115
120
|
]
|
|
116
121
|
}
|
|
117
122
|
|
|
118
|
-
def describe_image_scan_findings(self, repositoryName, imageId): # noqa: N803 - boto3's spelling
|
|
123
|
+
def describe_image_scan_findings(self, repositoryName, imageId, nextToken=None): # noqa: N803 - boto3's spelling
|
|
119
124
|
self.asked += 1
|
|
120
125
|
self.scanned.append(imageId["imageDigest"])
|
|
121
126
|
status = self.statuses[min(self.asked, len(self.statuses)) - 1]
|
|
@@ -132,6 +137,18 @@ class FakeEcr:
|
|
|
132
137
|
error.response = {"Error": {"Code": "ImageNotFoundException"}}
|
|
133
138
|
raise error
|
|
134
139
|
key = "enhancedFindings" if self.enhanced_findings else "findings"
|
|
140
|
+
if self.pages is not None:
|
|
141
|
+
index = int(nextToken or "0")
|
|
142
|
+
answer = {
|
|
143
|
+
"imageScanStatus": {"status": status},
|
|
144
|
+
"imageScanFindings": {
|
|
145
|
+
key: list(self.pages[index]),
|
|
146
|
+
"imageScanCompletedAt": "2026-09-12T09:00:00Z",
|
|
147
|
+
},
|
|
148
|
+
}
|
|
149
|
+
if index + 1 < len(self.pages):
|
|
150
|
+
answer["nextToken"] = str(index + 1)
|
|
151
|
+
return answer
|
|
135
152
|
return {
|
|
136
153
|
"imageScanStatus": {"status": status},
|
|
137
154
|
"imageScanFindings": {
|
|
@@ -151,14 +168,16 @@ class FakeEcr:
|
|
|
151
168
|
|
|
152
169
|
|
|
153
170
|
class Cosign:
|
|
154
|
-
"""A cosign whose argv
|
|
171
|
+
"""A cosign whose argv and env are read, and which can refuse."""
|
|
155
172
|
|
|
156
173
|
def __init__(self, returncode: int = 0) -> None:
|
|
157
174
|
self.returncode = returncode
|
|
158
175
|
self.argv: list[str] = []
|
|
176
|
+
self.env: dict[str, str] | None = None
|
|
159
177
|
|
|
160
|
-
def __call__(self, argv, **_kwargs) -> subprocess.CompletedProcess[str]:
|
|
178
|
+
def __call__(self, argv, *, env=None, **_kwargs) -> subprocess.CompletedProcess[str]:
|
|
161
179
|
self.argv = list(argv)
|
|
180
|
+
self.env = env
|
|
162
181
|
return subprocess.CompletedProcess(self.argv, self.returncode, "", "Pushing signature\n")
|
|
163
182
|
|
|
164
183
|
|
|
@@ -327,6 +346,31 @@ class TestTheScan:
|
|
|
327
346
|
assert raised.value.code.code == "DL_ENV_PROVIDER_ERROR"
|
|
328
347
|
assert raised.value.detail["digest"] == DIGEST
|
|
329
348
|
|
|
349
|
+
def test_every_page_of_findings_is_read_before_deciding(self) -> None:
|
|
350
|
+
"""Found live, 2026-09-14: a single unpaginated call answered only its
|
|
351
|
+
first page, and a real image with 1,547 findings across many pages
|
|
352
|
+
passed a decision that should have blocked — none of its 31 critical
|
|
353
|
+
findings were on the one page a single call happened to see. Every
|
|
354
|
+
page is now read and merged before `decide` runs."""
|
|
355
|
+
page_1 = [enhanced("CVE-2026-1111", "LOW")]
|
|
356
|
+
page_2 = [enhanced("CVE-2026-1234", "CRITICAL", fixed="2.9.15")]
|
|
357
|
+
page_3 = [enhanced("CVE-2026-2222", "MEDIUM")]
|
|
358
|
+
ecr = FakeEcr(pages=[page_1, page_2, page_3])
|
|
359
|
+
decision = an_attestor(ecr=ecr).scan(repository=REPOSITORY, digest=DIGEST)
|
|
360
|
+
assert decision.decision == "blocked"
|
|
361
|
+
assert [finding.id for finding in decision.blocking] == ["CVE-2026-1234"]
|
|
362
|
+
assert decision.body()["counts"] == {"LOW": 1, "CRITICAL": 1, "MEDIUM": 1}
|
|
363
|
+
assert ecr.asked == 3
|
|
364
|
+
|
|
365
|
+
def test_reading_pages_stops_at_the_cap_rather_than_paginating_forever(self) -> None:
|
|
366
|
+
pages = [
|
|
367
|
+
[enhanced(f"CVE-2026-{n:04d}", "LOW")] for n in range(Attestor._MAX_FINDING_PAGES + 5)
|
|
368
|
+
]
|
|
369
|
+
ecr = FakeEcr(pages=pages)
|
|
370
|
+
decision = an_attestor(ecr=ecr).scan(repository=REPOSITORY, digest=DIGEST)
|
|
371
|
+
assert decision.decision == "pass"
|
|
372
|
+
assert ecr.asked == Attestor._MAX_FINDING_PAGES
|
|
373
|
+
|
|
330
374
|
IMAGE = "sha256:" + "bb" * 32
|
|
331
375
|
ATTESTATION = "sha256:" + "cc" * 32
|
|
332
376
|
|
|
@@ -429,6 +473,35 @@ class TestTheSignature:
|
|
|
429
473
|
assert reference == f"{REGISTRY}/{REPOSITORY}:{signature_tag(DIGEST)}"
|
|
430
474
|
assert signed_now is True
|
|
431
475
|
|
|
476
|
+
def test_no_registry_auth_leaves_cosigns_own_environment_untouched(self) -> None:
|
|
477
|
+
"""The common case — nothing to add — inherits this process's own
|
|
478
|
+
environment rather than replacing it with an empty one."""
|
|
479
|
+
cosign = Cosign()
|
|
480
|
+
an_attestor(run=cosign).sign(registry=REGISTRY, repository=REPOSITORY, digest=DIGEST)
|
|
481
|
+
assert cosign.env is None
|
|
482
|
+
|
|
483
|
+
def test_registry_auth_reaches_cosign_as_docker_config(self) -> None:
|
|
484
|
+
"""cosign has no AWS credential chain of its own for ECR, unlike the
|
|
485
|
+
boto3 client the scan is read with: found live, 2026-09-14, `cosign
|
|
486
|
+
sign` reached the registry anonymously and was refused with a plain
|
|
487
|
+
`401 Unauthorized` on every real artifact this pipeline tried to
|
|
488
|
+
sign. The same `{"DOCKER_CONFIG": <dir>}` the resolver and the
|
|
489
|
+
builder already take off a `BuildCredential` fixes it here too."""
|
|
490
|
+
docker_config = "/tmp/dl-docker-abc" # noqa: S108 - a build's own dir, never touched by this test
|
|
491
|
+
cosign = Cosign()
|
|
492
|
+
an_attestor(run=cosign, registry_auth={"DOCKER_CONFIG": docker_config}).sign(
|
|
493
|
+
registry=REGISTRY, repository=REPOSITORY, digest=DIGEST
|
|
494
|
+
)
|
|
495
|
+
assert cosign.env is not None
|
|
496
|
+
assert cosign.env["DOCKER_CONFIG"] == docker_config
|
|
497
|
+
# Added to this process's own environment, not instead of it — cosign
|
|
498
|
+
# still needs AWS's own chain to reach the KMS key with `--key`.
|
|
499
|
+
import os
|
|
500
|
+
|
|
501
|
+
for name in ("PATH", "HOME"):
|
|
502
|
+
if name in os.environ:
|
|
503
|
+
assert cosign.env[name] == os.environ[name]
|
|
504
|
+
|
|
432
505
|
def test_a_replay_finds_the_signature_instead_of_pushing_a_second(self) -> None:
|
|
433
506
|
"""Immutable tags would refuse the second, and two signatures are two words."""
|
|
434
507
|
ecr = FakeEcr(signed={signature_tag(DIGEST)})
|
|
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.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/adapters/__init__.py
RENAMED
|
File without changes
|
{code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/adapters/datalayer.py
RENAMED
|
File without changes
|
{code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/adapters/daytona.py
RENAMED
|
File without changes
|
|
File without changes
|
{code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/adapters/managed.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
|
{code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/doctor/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{code_sandboxes-1.9.7 → code_sandboxes-1.9.9}/code_sandboxes/environments/doctor/report.schema.json
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
|
|
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
|