code-sandboxes 1.9.35__tar.gz → 1.9.37__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.
Files changed (272) hide show
  1. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/PKG-INFO +1 -1
  2. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/__version__.py +1 -1
  3. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/adapters/datalayer.py +32 -0
  4. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/adapters/modal.py +24 -1
  5. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/resolve.py +129 -0
  6. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/resolve_conda.py +21 -0
  7. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/modal_sandbox.py +10 -1
  8. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/environments/specification.mdx +1 -1
  9. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/providers/modal.mdx +24 -8
  10. code_sandboxes-1.9.37/tests/egress_logs/buildctl-base.log +16 -0
  11. code_sandboxes-1.9.37/tests/egress_logs/buildctl-curl.log +41 -0
  12. code_sandboxes-1.9.37/tests/egress_logs/buildctl-pip.log +43 -0
  13. code_sandboxes-1.9.37/tests/egress_logs/buildctl-uv.log +54 -0
  14. code_sandboxes-1.9.37/tests/egress_logs/micromamba.log +30 -0
  15. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_datalayer_builder.py +26 -2
  16. code_sandboxes-1.9.37/tests/test_environment_egress_refusals.py +146 -0
  17. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_modal_builder.py +18 -4
  18. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_resolve.py +28 -0
  19. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_resolve_conda.py +24 -0
  20. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_modal_google_colab_sandbox.py +51 -0
  21. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/.github/workflows/build.yml +0 -0
  22. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/.github/workflows/environments-live.yml +0 -0
  23. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/.github/workflows/py-code-style.yml +0 -0
  24. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/.github/workflows/py-tests.yml +0 -0
  25. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/.github/workflows/py-typing.yml +0 -0
  26. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/.github/workflows/reusable-python.yml +0 -0
  27. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/.gitignore +0 -0
  28. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/.licenserc.yaml +0 -0
  29. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/.pre-commit-config.yaml +0 -0
  30. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/.vscode/settings.json +0 -0
  31. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/CHANGELOG.md +0 -0
  32. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/Dockerfile +0 -0
  33. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/LICENSE +0 -0
  34. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/Makefile +0 -0
  35. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/README.md +0 -0
  36. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/__init__.py +0 -0
  37. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/base.py +0 -0
  38. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/bridge_mount.py +0 -0
  39. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/builds.py +0 -0
  40. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/cli.py +0 -0
  41. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/client.py +0 -0
  42. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/cloudflare_sandbox.py +0 -0
  43. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/commands.py +0 -0
  44. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/console.py +0 -0
  45. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/contents.py +0 -0
  46. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/coreweave_sandbox.py +0 -0
  47. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/datalayer_sandbox.py +0 -0
  48. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/daytona_sandbox.py +0 -0
  49. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/docker_sandbox.py +0 -0
  50. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/e2b_sandbox.py +0 -0
  51. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/__init__.py +0 -0
  52. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/__main__.py +0 -0
  53. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/accounts.py +0 -0
  54. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/adapters/__init__.py +0 -0
  55. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/adapters/daytona.py +0 -0
  56. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/adapters/e2b.py +0 -0
  57. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/adapters/managed.py +0 -0
  58. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/attest.py +0 -0
  59. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/bases.py +0 -0
  60. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/breaker.py +0 -0
  61. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/build_secrets.py +0 -0
  62. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/builders.py +0 -0
  63. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/canonical.py +0 -0
  64. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/conformance.py +0 -0
  65. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/constraints/sandbox-contract-v1.txt +0 -0
  66. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/constraints/wheelhouse/README.md +0 -0
  67. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/constraints/wheelhouse/jupyter_server-2.21.0+datalayer.1-py3-none-any.whl +0 -0
  68. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/contract.py +0 -0
  69. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/doctor/__init__.py +0 -0
  70. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/doctor/build.py +0 -0
  71. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/doctor/datalayer_sandbox.py +0 -0
  72. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/doctor/report.schema.json +0 -0
  73. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/errors.py +0 -0
  74. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/files.py +0 -0
  75. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/image_import.py +0 -0
  76. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/lifecycle.py +0 -0
  77. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/policy.py +0 -0
  78. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/redact.py +0 -0
  79. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/schema.py +0 -0
  80. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/environments/spec.py +0 -0
  81. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/eval_sandbox.py +0 -0
  82. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/exceptions.py +0 -0
  83. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/filesystem.py +0 -0
  84. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/google_colab.py +0 -0
  85. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/google_colab_sandbox.py +0 -0
  86. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/interfaces.py +0 -0
  87. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/jupyter_ingress.py +0 -0
  88. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/jupyter_server_sandbox.py +0 -0
  89. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/kaggle.py +0 -0
  90. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/kaggle_execute.py +0 -0
  91. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/kaggle_live.py +0 -0
  92. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/kaggle_sandbox.py +0 -0
  93. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/lifecycle.py +0 -0
  94. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/manage.py +0 -0
  95. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/models.py +0 -0
  96. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/monty_sandbox.py +0 -0
  97. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/provider_ingress.py +0 -0
  98. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/code_sandboxes/providers.py +0 -0
  99. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docker/Dockerfile +0 -0
  100. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/.gitignore +0 -0
  101. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/LICENSE +0 -0
  102. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/Makefile +0 -0
  103. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/README.md +0 -0
  104. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/babel.config.js +0 -0
  105. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/api-reference/_category_.yml +0 -0
  106. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/api-reference/index.mdx +0 -0
  107. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/cli/_category_.yml +0 -0
  108. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/cli/index.mdx +0 -0
  109. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/contribute/_category_.yml +0 -0
  110. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/contribute/index.mdx +0 -0
  111. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/environments/_category_.yml +0 -0
  112. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/environments/contract.mdx +0 -0
  113. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/environments/index.mdx +0 -0
  114. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/environments/spike-2026-09.mdx +0 -0
  115. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/examples/_category_.yml +0 -0
  116. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/examples/index.mdx +0 -0
  117. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/guide/_category_.yml +0 -0
  118. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/guide/index.mdx +0 -0
  119. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/index.mdx +0 -0
  120. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/install/_category_.yml +0 -0
  121. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/install/index.mdx +0 -0
  122. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/provider-ingress.mdx +0 -0
  123. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/providers/_category_.yml +0 -0
  124. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/providers/cloudflare.mdx +0 -0
  125. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/providers/coreweave.mdx +0 -0
  126. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/providers/datalayer.mdx +0 -0
  127. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/providers/daytona.mdx +0 -0
  128. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/providers/docker.mdx +0 -0
  129. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/providers/e2b.mdx +0 -0
  130. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/providers/eval.mdx +0 -0
  131. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/providers/google-colab.mdx +0 -0
  132. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/providers/index.mdx +0 -0
  133. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/providers/jupyter-server.mdx +0 -0
  134. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/providers/kaggle.mdx +0 -0
  135. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docs/providers/monty.mdx +0 -0
  136. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/docusaurus.config.js +0 -0
  137. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/package.json +0 -0
  138. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/sidebars.js +0 -0
  139. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/src/components/HomepageRow1.js +0 -0
  140. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/src/components/HomepageRow1.module.css +0 -0
  141. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/src/components/HomepageRow2.js +0 -0
  142. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/src/components/HomepageRow2.module.css +0 -0
  143. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/src/components/HomepageRow3.js +0 -0
  144. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/src/components/HomepageRow3.module.css +0 -0
  145. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/src/css/custom.css +0 -0
  146. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/src/pages/index.module.css +0 -0
  147. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/src/pages/markdown-page.md +0 -0
  148. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/src/theme/CustomDocItem.tsx +0 -0
  149. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/src/theme/IconsTitle.tsx +0 -0
  150. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/static/img/bricks.svg +0 -0
  151. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/static/img/building-construction.svg +0 -0
  152. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/static/img/cloud-sun.svg +0 -0
  153. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/static/img/cloud.svg +0 -0
  154. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/static/img/collaboration.svg +0 -0
  155. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/static/img/copy-left.svg +0 -0
  156. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/static/img/datalayer/logo.png +0 -0
  157. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/static/img/datalayer/logo.svg +0 -0
  158. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/static/img/datalayer/personas/business.svg +0 -0
  159. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/static/img/datalayer/personas/data-scientist.svg +0 -0
  160. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/static/img/datalayer/personas/devops.svg +0 -0
  161. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/static/img/datalayer/project/project-line.svg +0 -0
  162. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/static/img/favicon.ico +0 -0
  163. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/static/img/jupyter.svg +0 -0
  164. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/static/img/open-source.svg +0 -0
  165. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/static/img/react-js.svg +0 -0
  166. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/static/img/react-js2.svg +0 -0
  167. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/static/img/ringed-planet.svg +0 -0
  168. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/static/img/robot.svg +0 -0
  169. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/static/img/rocket.svg +0 -0
  170. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/static/img/shield.svg +0 -0
  171. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/static/img/sparkles.svg +0 -0
  172. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/static/img/streamlit.gif +0 -0
  173. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/static/img/super-hero.svg +0 -0
  174. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/static/img/target.svg +0 -0
  175. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/docs/static/img/thumbs-up.svg +0 -0
  176. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/examples/README.md +0 -0
  177. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/examples/exec/Makefile +0 -0
  178. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/examples/exec/cloudflare_sandbox_example.py +0 -0
  179. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/examples/exec/coreweave_sandbox_example.py +0 -0
  180. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/examples/exec/datalayer_sandbox_example.py +0 -0
  181. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/examples/exec/daytona_sandbox_example.py +0 -0
  182. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/examples/exec/docker_sandbox_example.py +0 -0
  183. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/examples/exec/e2b_sandbox_example.py +0 -0
  184. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/examples/exec/eval_sandbox_example.py +0 -0
  185. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/examples/exec/google_colab_sandbox_example.py +0 -0
  186. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/examples/exec/jupyter_server_sandbox_example.py +0 -0
  187. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/examples/exec/kaggle_sandbox_example.py +0 -0
  188. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/examples/exec/modal_sandbox_example.py +0 -0
  189. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/examples/exec/monty_sandbox_example.py +0 -0
  190. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/examples/repl/Makefile +0 -0
  191. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/examples/repl/cloudflare_sandbox_example.py +0 -0
  192. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/examples/repl/coreweave_sandbox_example.py +0 -0
  193. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/examples/repl/datalayer_sandbox_example.py +0 -0
  194. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/examples/repl/daytona_sandbox_example.py +0 -0
  195. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/examples/repl/docker_sandbox_example.py +0 -0
  196. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/examples/repl/e2b_sandbox_example.py +0 -0
  197. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/examples/repl/eval_sandbox_example.py +0 -0
  198. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/examples/repl/google_colab_sandbox_example.py +0 -0
  199. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/examples/repl/jupyter_server_sandbox_example.py +0 -0
  200. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/examples/repl/kaggle_sandbox_example.py +0 -0
  201. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/examples/repl/modal_sandbox_example.py +0 -0
  202. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/examples/repl/monty_sandbox_example.py +0 -0
  203. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/pyproject.toml +0 -0
  204. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/schemas/environment-v1alpha1.json +0 -0
  205. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/__init__.py +0 -0
  206. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/conftest.py +0 -0
  207. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_a_datalayer_sandbox_can_be_interrupted.py +0 -0
  208. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_bridge_mount.py +0 -0
  209. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_builds.py +0 -0
  210. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_cli_exec.py +0 -0
  211. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_cli_repl.py +0 -0
  212. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_client.py +0 -0
  213. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_client_contents.py +0 -0
  214. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_client_files.py +0 -0
  215. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_client_outcome_error_output.py +0 -0
  216. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_cloudflare.py +0 -0
  217. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_commands_envelope.py +0 -0
  218. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_console.py +0 -0
  219. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_contents_contract.py +0 -0
  220. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_contents_live_matrix.py +0 -0
  221. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_coreweave.py +0 -0
  222. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_datalayer_sandbox.py +0 -0
  223. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_daytona.py +0 -0
  224. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_e2b.py +0 -0
  225. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_accounts.py +0 -0
  226. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_attest.py +0 -0
  227. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_bases.py +0 -0
  228. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_breaker.py +0 -0
  229. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_build_secrets.py +0 -0
  230. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_builders.py +0 -0
  231. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_canonical.py +0 -0
  232. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_conformance.py +0 -0
  233. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_constraints.py +0 -0
  234. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_contract.py +0 -0
  235. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_cross_variant_report.py +0 -0
  236. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_daytona_builder.py +0 -0
  237. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_dockerfile_source.py +0 -0
  238. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_doctor.py +0 -0
  239. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_e2b_builder.py +0 -0
  240. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_errors.py +0 -0
  241. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_image_import.py +0 -0
  242. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_lifecycle.py +0 -0
  243. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_live_matrix.py +0 -0
  244. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_managed_builders.py +0 -0
  245. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_organization_policy.py +0 -0
  246. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_redact.py +0 -0
  247. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_spec.py +0 -0
  248. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_environment_spec_organization_policy.py +0 -0
  249. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_eval.py +0 -0
  250. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_every_variant_has_a_real_interrupt.py +0 -0
  251. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_factory.py +0 -0
  252. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_google_colab.py +0 -0
  253. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_integration.py +0 -0
  254. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_jupyter_ingress.py +0 -0
  255. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_jupyter_server.py +0 -0
  256. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_jupyter_server_streaming.py +0 -0
  257. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_kaggle.py +0 -0
  258. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_kaggle_execute.py +0 -0
  259. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_kaggle_live.py +0 -0
  260. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_kaggle_session.py +0 -0
  261. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_kernel_client_compatibility.py +0 -0
  262. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_lifecycle_vocabulary.py +0 -0
  263. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_manage.py +0 -0
  264. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_manage_datalayer.py +0 -0
  265. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_modal_session.py +0 -0
  266. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_models.py +0 -0
  267. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_output_line_fidelity.py +0 -0
  268. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_provider_catalog_names.py +0 -0
  269. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_provider_ingress.py +0 -0
  270. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_providers.py +0 -0
  271. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_sandboxes.py +0 -0
  272. {code_sandboxes-1.9.35 → code_sandboxes-1.9.37}/tests/test_the_kill_relaunch_drill.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: code_sandboxes
3
- Version: 1.9.35
3
+ Version: 1.9.37
4
4
  Project-URL: Home, https://github.com/datalayer/code-sandboxes
5
5
  Author-email: Datalayer <info@datalayer.io>
6
6
  License: BSD 3-Clause License
@@ -3,4 +3,4 @@
3
3
 
4
4
  """Code Sandboxes."""
5
5
 
6
- __version__ = "1.9.35"
6
+ __version__ = "1.9.37"
@@ -76,6 +76,11 @@ from ..resolve import (
76
76
  WHEELHOUSE_PATH,
77
77
  apt_pins_in,
78
78
  apt_snapshot_in,
79
+ buildkit_proxy,
80
+ buildkit_proxy_options,
81
+ egress_findings,
82
+ egress_hosts_text,
83
+ egress_refused_hosts,
79
84
  locked_versions,
80
85
  )
81
86
  from ..resolve_conda import (
@@ -214,6 +219,11 @@ class Builder:
214
219
  importing this module needs no credentials.
215
220
  run
216
221
  How a subprocess is run, so a test can watch the argv without a daemon.
222
+ proxy
223
+ The build pool's egress proxy, as ``buildkitd`` reaches it (E1-06):
224
+ every step of the build goes through it. ``DATALAYER_BUILDKIT_PROXY``
225
+ by default; empty is a ``buildkitd`` whose steps reach the network
226
+ directly.
217
227
  """
218
228
 
219
229
  variant = "datalayer"
@@ -233,6 +243,7 @@ class Builder:
233
243
  run: Callable[..., subprocess.CompletedProcess[str]] | None = None,
234
244
  max_build_seconds: int = DEFAULT_MAX_BUILD_SECONDS,
235
245
  resolve_secret: Callable[..., str] = resolve_build_secret,
246
+ proxy: str | None = None,
236
247
  ) -> None:
237
248
  self._log = log or (lambda _line: None)
238
249
  self._credential = credential
@@ -241,6 +252,8 @@ class Builder:
241
252
  self._tlscert = tlscert or os.environ.get("DATALAYER_BUILDKIT_TLSCERT", "").strip()
242
253
  self._tlskey = tlskey or os.environ.get("DATALAYER_BUILDKIT_TLSKEY", "").strip()
243
254
  self._tlscacert = tlscacert or os.environ.get("DATALAYER_BUILDKIT_TLSCACERT", "").strip()
255
+ #: The build pool's egress proxy (E1-06), or `DATALAYER_BUILDKIT_PROXY`.
256
+ self._proxy = buildkit_proxy(proxy)
244
257
  self._region = region or os.environ.get("AWS_REGION", "us-east-1")
245
258
  self._ecr = ecr
246
259
  self._run = run or subprocess.run
@@ -530,11 +543,30 @@ class Builder:
530
543
  "--metadata-file",
531
544
  str(metadata),
532
545
  *self._cache_options(request),
546
+ *buildkit_proxy_options(self._proxy),
533
547
  *secret_args,
534
548
  ]
535
549
  self._log(f"Building {reference} from {request.resolved_base}")
536
550
  finished = self._invoke(command, timeout=self._max_build_seconds)
537
551
  if finished.returncode != 0:
552
+ refused = egress_refused_hosts(finished.stderr or "", proxy=self._proxy)
553
+ if refused:
554
+ # The one failure a log line hid best: a host the build
555
+ # pool may not reach, named as a finding (E2-19).
556
+ raise EnvironmentsError(
557
+ BUILD_FAILED,
558
+ f"The build pool's egress proxy refused {egress_hosts_text(refused)}: "
559
+ "a build reaches only the package indexes, mirrors and registries "
560
+ "the build pool allows. Put what it fetches in the build, or ask "
561
+ "for the host to be allowed",
562
+ detail={
563
+ "variant": self.variant,
564
+ "reference": reference,
565
+ "exit": finished.returncode,
566
+ "refused_hosts": refused,
567
+ "findings": egress_findings(refused),
568
+ },
569
+ )
538
570
  raise EnvironmentsError(
539
571
  BUILD_FAILED,
540
572
  "The build failed; its log says where",
@@ -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
- image = image.workdir(_CONTENT_DIR).entrypoint([_ENTRYPOINT_PATH])
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,9 @@ __all__ = [
98
99
  "apt_pins",
99
100
  "apt_pins_in",
100
101
  "apt_snapshot_in",
102
+ "buildkit_proxy",
103
+ "buildkit_proxy_options",
104
+ "egress_refused_hosts",
101
105
  "lock_document",
102
106
  "locked_versions",
103
107
  "merge_requirements",
@@ -145,6 +149,114 @@ DOCKERFILE_COVERAGE = (
145
149
  APT_SNAPSHOT_PREFIX = "# datalayer-apt-snapshot: "
146
150
  _SNAPSHOT_ID = re.compile(r"^\d{8}T\d{6}Z$")
147
151
 
152
+ #: Where a build's own steps reach the network through, when the build pool
153
+ #: gives them nowhere else to go (E1-06): an HTTP proxy that allows only the
154
+ #: package indexes, the snapshot mirrors and the registries. The address is
155
+ #: the one `buildkitd` itself sees, since a step runs in its network.
156
+ BUILDKIT_PROXY_ENV = "DATALAYER_BUILDKIT_PROXY"
157
+ _PROXY_URL = re.compile(r"^http://[A-Za-z0-9.\-]+:\d{1,5}$")
158
+
159
+
160
+ def buildkit_proxy(proxy: str | None = None) -> str:
161
+ """The proxy a build's steps go through: ``proxy``, or the environment's.
162
+
163
+ Empty is no proxy, which is what a `buildkitd` with open egress needs
164
+ (`plane local`'s own). Anything that is not ``http://host:port`` is
165
+ refused rather than handed to every package manager of every build.
166
+ """
167
+ value = (os.environ.get(BUILDKIT_PROXY_ENV, "") if proxy is None else proxy).strip()
168
+ if value and not _PROXY_URL.match(value):
169
+ raise ValueError(f"{BUILDKIT_PROXY_ENV} must be http://host:port, not {value!r}")
170
+ return value
171
+
172
+
173
+ def buildkit_proxy_options(proxy: str) -> list[str]:
174
+ """The ``buildctl`` options that send a build's steps through ``proxy``.
175
+
176
+ The Dockerfile frontend predefines these build args: a ``RUN`` step sees
177
+ them without an ``ARG``, they never reach the image's config or history,
178
+ and they do not change a cache key. Both spellings, since ``apt`` and
179
+ ``curl`` read only the lower-case one for plain HTTP and ``uv``, ``pip``
180
+ and ``micromamba`` read either.
181
+ """
182
+ if not proxy:
183
+ return []
184
+ options: list[str] = []
185
+ for name in ("HTTP_PROXY", "HTTPS_PROXY", "http_proxy", "https_proxy"):
186
+ options += ["--opt", f"build-arg:{name}={proxy}"]
187
+ for name in ("NO_PROXY", "no_proxy"):
188
+ options += ["--opt", f"build-arg:{name}=127.0.0.1,localhost"]
189
+ return options
190
+
191
+
192
+ #: What each tool writes when the build pool's egress proxy refuses it a
193
+ #: tunnel (E2-19). Read from the tools themselves, through the chart's own
194
+ #: Squid refusing every host, on 2026-09-19: pip, uv 0.12, micromamba 2.3,
195
+ #: git, curl 8 without `-f`, wget, and a Go client — `buildkitd`'s own pulls.
196
+ #: Each is a refused CONNECT and nothing else: a host that answered 403 over
197
+ #: its own TLS says so differently. `curl -f` ("The requested URL returned
198
+ #: error: 403"), `wget -q` (nothing) and `apt` over plain HTTP ("403
199
+ #: Forbidden [IP: proxy]") cannot be told from the host's own 403, and are
200
+ #: left to the log.
201
+ _EGRESS_REFUSED = re.compile(
202
+ r"Tunnel connection failed: 403" # pip, requests, urllib3
203
+ r"|tunnel error: unsuccessful" # uv
204
+ r"|CONNECT tunnel failed, response 403" # curl, git, micromamba
205
+ r"|Proxy tunneling failed: Forbidden" # wget
206
+ r'|"https?://[^"\s]+": Forbidden' # Go: buildkitd, containerd
207
+ )
208
+ #: A host a line names: urllib3's `host='…'`, or the host of a URL.
209
+ _NAMED_HOST = re.compile(r"host='(?P<pool>[A-Za-z0-9.\-]+)'|https?://(?P<url>[A-Za-z0-9.\-]+)")
210
+ #: `buildctl`'s plain progress: `#12 0.874 <what the step wrote>`. Steps run
211
+ #: side by side, so a line is read against the lines of its own step.
212
+ _BUILDKIT_LINE = re.compile(r"^#(?P<step>\d+) (?:\d+\.\d+ )?(?P<text>.*)$")
213
+
214
+
215
+ def egress_refused_hosts(log: str, *, proxy: str = "", limit: int = 10) -> list[str]:
216
+ """The hosts the build pool's egress proxy refused, as a build's log shows them (E2-19).
217
+
218
+ A refusal is found by what the tool writes (`_EGRESS_REFUSED`), and its
219
+ host is the one the same line names — pip's `host='files.pythonhosted.org'`,
220
+ git's URL — or else the last one its step named before it: uv and
221
+ micromamba write the URL a line or four above the refusal, wget and a
222
+ silent `curl` only in the `RUN` line. The proxy's own address is never a
223
+ host it refused. In the order they were first refused, at most ``limit``.
224
+ """
225
+ own = {"127.0.0.1", "localhost"}
226
+ if proxy:
227
+ own.add(proxy.split("://", 1)[-1].rsplit(":", 1)[0])
228
+ hosts: list[str] = []
229
+ last: dict[str, str] = {}
230
+ for raw in log.splitlines():
231
+ line = _BUILDKIT_LINE.match(raw)
232
+ step, text = (line.group("step"), line.group("text")) if line else ("", raw)
233
+ named = [
234
+ host.lower().rstrip(".")
235
+ for match in _NAMED_HOST.finditer(text)
236
+ for host in (match.group("pool") or match.group("url"),)
237
+ if host and host.lower().rstrip(".") not in own
238
+ ]
239
+ if _EGRESS_REFUSED.search(text):
240
+ host = named[0] if named else last.get(step, "")
241
+ if host and host not in hosts:
242
+ hosts.append(host)
243
+ if len(hosts) >= limit:
244
+ break
245
+ if named:
246
+ last[step] = named[-1]
247
+ return hosts
248
+
249
+
250
+ def egress_findings(hosts: Sequence[str]) -> list[dict[str, str]]:
251
+ """The refused hosts as a failure's findings: what a page lists, not the log."""
252
+ return [{"kind": "egress_refused", "subject": host} for host in hosts]
253
+
254
+
255
+ def egress_hosts_text(hosts: Sequence[str]) -> str:
256
+ quoted = [f"`{host}`" for host in hosts]
257
+ return quoted[0] if len(quoted) == 1 else ", ".join(quoted[:-1]) + " and " + quoted[-1]
258
+
259
+
148
260
  #: How a protected pin is recorded in the lock.
149
261
  PROTECTED_PIN_PREFIX = "# datalayer-protected: "
150
262
 
@@ -478,6 +590,19 @@ def parse_resolver_failure(
478
590
  },
479
591
  )
480
592
 
593
+ # An index the build pool may not reach is not an outage: resolving again
594
+ # is refused again, so it is said with the host rather than retried.
595
+ refused = egress_refused_hosts(output)
596
+ if refused and "No solution found" not in text:
597
+ return EnvironmentsError(
598
+ PACKAGE_NOT_FOUND,
599
+ f"The build pool's egress proxy refused {egress_hosts_text(refused)}: a version "
600
+ "resolves only against the indexes the build pool allows. Use one of them, or "
601
+ "ask for the host to be allowed",
602
+ detail={**detail, "refused_hosts": refused, "findings": egress_findings(refused)},
603
+ retryable=False,
604
+ )
605
+
481
606
  pair = _conflicting_pair(mentions) if "No solution found" in text else None
482
607
  if pair:
483
608
  return EnvironmentsError(
@@ -623,8 +748,11 @@ class BuildkitResolveRunner:
623
748
  tlscacert: str | None = None,
624
749
  apt_snapshot: str = "",
625
750
  timeout: float = 900.0,
751
+ proxy: str | None = None,
626
752
  ) -> None:
627
753
  self._buildctl = (shutil.which("buildctl") or "") if buildctl is None else buildctl
754
+ #: The build pool's egress proxy (E1-06), or `DATALAYER_BUILDKIT_PROXY`.
755
+ self._proxy = buildkit_proxy(proxy)
628
756
  #: The build pool's `buildkitd` takes mTLS connections only
629
757
  #: (PLAN_ENV.md E1-06); a plain-socket one, such as `plane local`'s
630
758
  #: own ephemeral daemon, needs none of these three. All or nothing,
@@ -761,6 +889,7 @@ class BuildkitResolveRunner:
761
889
  f"dockerfile={root}",
762
890
  "--output",
763
891
  f"type=local,dest={out}",
892
+ *buildkit_proxy_options(self._proxy),
764
893
  ]
765
894
  say(f"Solving the lock in {request.base_reference}")
766
895
  try:
@@ -68,6 +68,11 @@ from .resolve import (
68
68
  WHEELHOUSE_PATH,
69
69
  MergedRequirements,
70
70
  ProtectedPin,
71
+ buildkit_proxy,
72
+ buildkit_proxy_options,
73
+ egress_findings,
74
+ egress_hosts_text,
75
+ egress_refused_hosts,
71
76
  merge_requirements,
72
77
  )
73
78
 
@@ -527,6 +532,18 @@ def parse_conda_failure(output: str) -> EnvironmentsError:
527
532
  f"`{name}` is not in any channel this environment may read",
528
533
  detail={**detail, "package": name},
529
534
  )
535
+ # A channel the build pool may not reach: solving again is refused again,
536
+ # so it is said with the host rather than retried (E2-19).
537
+ refused = egress_refused_hosts(output)
538
+ if refused:
539
+ return EnvironmentsError(
540
+ PACKAGE_NOT_FOUND,
541
+ f"The build pool's egress proxy refused {egress_hosts_text(refused)}: a version "
542
+ "solves only against the channels the build pool allows. Use one of them, or "
543
+ "ask for the host to be allowed",
544
+ detail={**detail, "refused_hosts": refused, "findings": egress_findings(refused)},
545
+ retryable=False,
546
+ )
530
547
  lowered = text.lower()
531
548
  if (
532
549
  "could not solve" in lowered
@@ -684,8 +701,11 @@ class BuildkitCondaResolveRunner:
684
701
  tlskey: str | None = None,
685
702
  tlscacert: str | None = None,
686
703
  timeout: float = 1200.0,
704
+ proxy: str | None = None,
687
705
  ) -> None:
688
706
  self._buildctl = (shutil.which("buildctl") or "") if buildctl is None else buildctl
707
+ #: The build pool's egress proxy (E1-06), or `DATALAYER_BUILDKIT_PROXY`.
708
+ self._proxy = buildkit_proxy(proxy)
689
709
  self._tlscert = tlscert or ""
690
710
  self._tlskey = tlskey or ""
691
711
  self._tlscacert = tlscacert or ""
@@ -778,6 +798,7 @@ class BuildkitCondaResolveRunner:
778
798
  f"dockerfile={root}",
779
799
  "--output",
780
800
  f"type=local,dest={out}",
801
+ *buildkit_proxy_options(self._proxy),
781
802
  ]
782
803
  say(f"Solving the conda lock in {request.base_reference}")
783
804
  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
- self._sandbox = modal.Sandbox.create(**create_kwargs)
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
 
@@ -37,7 +37,7 @@ A document is refused with `DL_ENV_SPEC_INVALID` when a field is wrong, and with
37
37
  | `commands.postInstall` | none | At most 32 non-empty commands, run after the packages are installed. |
38
38
  | `buildSecrets` | none | `id` is a Datalayer secret id, `dlsec_...`; `mountAs` is `env` or `file`; `name` is the variable or file name. Ids and names are unique. Secrets are injected into the build step that needs them and never written into the artifact. |
39
39
  | `resources.sizeClass` | `small` | `small`, `medium`, `large`, `gpu-small` or `gpu-large`. A GPU class needs an accelerator and a CUDA base; an accelerator needs a GPU class. Datalayer runs no GPU nodes yet, so a GPU class is built for Modal and Daytona, which bring their own GPUs; E2B has none. |
40
- | `resources.accelerator` | `none` | `none`, or `type`, `count` and `cuda`. `type` is the provider's own name for the GPU (Daytona: `H100`, `H200`, `RTX-PRO-6000`, `RTX-4090`, `RTX-5090`), and a GPU a variant does not offer is refused for it at `validate`. `cuda` is the base's toolkit: `datalayer/python-cuda:2026.09` carries 12.8, and another version is refused. |
40
+ | `resources.accelerator` | `none` | `none`, or `type`, `count` and `cuda`. `type` is the provider's own name for the GPU (Modal: `T4`, `L4`, `A10G`, `L40S`, `A100`, `A100-40GB`, `A100-80GB`, `H100`, `H200`, `B200`; Daytona: `H100`, `H200`, `RTX-PRO-6000`, `RTX-4090`, `RTX-5090`), and a GPU a variant does not offer is refused for it at `validate`. `cuda` is the base's toolkit: `datalayer/python-cuda:2026.09` carries 12.8, and another version is refused. |
41
41
  | `resources.hints` | none | `cpu`, `memoryGi`, `diskGi`: positive numbers, within the size class. |
42
42
  | `compatibility.variants.required` | `[datalayer]` | At least one of `datalayer`, `e2b`, `daytona`, `modal`. |
43
43
  | `compatibility.variants.optional` | none | The same variants, none of them also required. |
@@ -77,9 +77,11 @@ with Sandbox.create(
77
77
  An [Environment](/environments) built for Modal is an **image id**,
78
78
  `im-…` — pulled `from_aws_ecr` off the approved Datalayer base, with your
79
79
  lock installed by `uv pip sync --require-hashes` on top. A published name
80
- is worth having for operability, but a launch always pins the id: each
81
- build gets a fresh credential, so no layer cache survives between builds,
82
- and the id is the only reference that names one build and not another.
80
+ is worth having for operability, but a launch always pins the id: a name
81
+ moves when the same build is published again, and the id is the only
82
+ reference that names one build's image. Modal answers an identical image
83
+ definition with the image it already has, so two builds of the same lock
84
+ can share one id.
83
85
 
84
86
  **Bring your own account:** a build runs in the environment owner's own
85
87
  Modal workspace, from the same `MODAL_TOKEN_ID`/`MODAL_TOKEN_SECRET` pair
@@ -96,8 +98,22 @@ with no image id — general Modal sandbox usage here is unaffected).
96
98
  Confirmed live: a launched sandbox's identity check now passes, where it
97
99
  used to report `uid: 0`.
98
100
 
99
- **A known, open gap:** two of the core tier's checks — imports and
100
- filesystem — still fail on a launched Environment sandbox, for a reason
101
- not yet root-caused: reproduced on a real, contract-built image, not on a
102
- plain `ModalSandbox`, so it is specific to something about that image
103
- under repeated `exec`, not the identity fix above.
101
+ **The sandbox is held by `sleep infinity`, not the base's Jupyter.**
102
+ Modal keeps the base image's CMD, `start-jupyter.sh`, under the builder's
103
+ `ENTRYPOINT`, where Docker would reset it, so a sandbox started with no
104
+ command ran a Jupyter server as its main process. That server exits
105
+ within a minute and the sandbox ends with it: "Modal Sandbox is shutting
106
+ down", a few commands in. Since 1.9.36 the artifact's CMD is
107
+ `sleep infinity`, and `ModalSandbox` names `sleep infinity` when it
108
+ launches an artifact, which covers images built by earlier releases too.
109
+ Jupyter is started by exec when it is asked for
110
+ (`prepare_jupyter_server`).
111
+
112
+ **GPU versions.** On Modal a GPU is a launch option, not part of the
113
+ image: a GPU version's image builds like any other on the CUDA base, and
114
+ its sandboxes start on the GPU the version names. The build's smoke test
115
+ does that (`gpu="L4"`, or `"H100:2"` for two) and adds the contract's
116
+ check 11: the GPUs asked for are visible, and the image's CUDA is the
117
+ version's. A GPU Modal does not offer — it offers `T4`, `L4`, `A10G`,
118
+ `L40S`, `A100`, `A100-40GB`, `A100-80GB`, `H100`, `H200`, `B200` — is
119
+ refused at `validate`, before anything is built.
@@ -0,0 +1,16 @@
1
+ #1 [internal] load build definition from Dockerfile
2
+ #1 transferring dockerfile: 80B done
3
+ #1 DONE 0.0s
4
+
5
+ #2 [internal] load metadata for ghcr.io/astral-sh/uv:0.12.11
6
+ #2 ERROR: failed to do request: Head "https://ghcr.io/v2/astral-sh/uv/manifests/0.12.11": Forbidden
7
+ ------
8
+ > [internal] load metadata for ghcr.io/astral-sh/uv:0.12.11:
9
+ ------
10
+ Dockerfile:1
11
+ --------------------
12
+ 1 | >>> FROM ghcr.io/astral-sh/uv:0.12.11
13
+ 2 | RUN true
14
+ 3 |
15
+ --------------------
16
+ error: failed to solve: ghcr.io/astral-sh/uv:0.12.11: failed to resolve source metadata for ghcr.io/astral-sh/uv:0.12.11: failed to do request: Head "https://ghcr.io/v2/astral-sh/uv/manifests/0.12.11": Forbidden
@@ -0,0 +1,41 @@
1
+ #1 [internal] load build definition from Dockerfile
2
+ #1 transferring dockerfile: 325B done
3
+ #1 DONE 0.0s
4
+
5
+ #2 [internal] load metadata for docker.io/library/buildpack-deps:bookworm-scm
6
+ #2 DONE 0.2s
7
+
8
+ #3 [internal] load .dockerignore
9
+ #3 transferring context: 2B done
10
+ #3 DONE 0.0s
11
+
12
+ #4 [1/4] FROM docker.io/library/buildpack-deps:bookworm-scm@sha256:bb8654d03bd8341e702f1ae30adca91a11f4164da2d37dbe7a0bf49e4901bd03
13
+ #4 CACHED
14
+
15
+ #5 [2/4] RUN git clone -q https://github.com/psf/requests.git /tmp/r || true
16
+ #5 0.063 fatal: unable to access 'https://github.com/psf/requests.git/': CONNECT tunnel failed, response 403
17
+ #5 DONE 0.1s
18
+
19
+ #6 [3/4] RUN curl -fsSL https://raw.githubusercontent.com/psf/requests/main/README.md -o /dev/null || true
20
+ #6 0.065 curl: (22) The requested URL returned error: 403
21
+ #6 DONE 0.1s
22
+
23
+ #7 [4/4] RUN wget https://github.com/psf/requests/archive/refs/tags/v2.32.3.tar.gz -O /dev/null
24
+ #7 0.060 --2026-09-19 08:44:09-- https://github.com/psf/requests/archive/refs/tags/v2.32.3.tar.gz
25
+ #7 0.066 Connecting to 172.18.0.2:3128... connected.
26
+ #7 0.067 Proxy tunneling failed: ForbiddenUnable to establish SSL connection.
27
+ #7 ERROR: process "/bin/sh -c wget https://github.com/psf/requests/archive/refs/tags/v2.32.3.tar.gz -O /dev/null" did not complete successfully: exit code: 4
28
+ ------
29
+ > [4/4] RUN wget https://github.com/psf/requests/archive/refs/tags/v2.32.3.tar.gz -O /dev/null:
30
+ 0.060 --2026-09-19 08:44:09-- https://github.com/psf/requests/archive/refs/tags/v2.32.3.tar.gz
31
+ 0.066 Connecting to 172.18.0.2:3128... connected.
32
+ 0.067 Proxy tunneling failed: ForbiddenUnable to establish SSL connection.
33
+ ------
34
+ Dockerfile:4
35
+ --------------------
36
+ 2 | RUN git clone -q https://github.com/psf/requests.git /tmp/r || true
37
+ 3 | RUN curl -fsSL https://raw.githubusercontent.com/psf/requests/main/README.md -o /dev/null || true
38
+ 4 | >>> RUN wget https://github.com/psf/requests/archive/refs/tags/v2.32.3.tar.gz -O /dev/null
39
+ 5 |
40
+ --------------------
41
+ error: failed to solve: process "/bin/sh -c wget https://github.com/psf/requests/archive/refs/tags/v2.32.3.tar.gz -O /dev/null" did not complete successfully: exit code: 4
@@ -0,0 +1,43 @@
1
+ #1 [internal] load build definition from Dockerfile
2
+ #1 transferring dockerfile: 192B done
3
+ #1 DONE 0.0s
4
+
5
+ #2 [internal] load metadata for docker.io/library/python:3.12-slim
6
+ #2 DONE 0.2s
7
+
8
+ #3 [internal] load .dockerignore
9
+ #3 transferring context: 2B done
10
+ #3 DONE 0.0s
11
+
12
+ #4 [1/3] FROM docker.io/library/python:3.12-slim@sha256:2f17fc044b579bab302c2e8054d3a686e2cb9a83de48e70534b94cd8ebbe06a9
13
+ #4 CACHED
14
+
15
+ #5 [2/3] RUN pip install --no-cache-dir --index-url https://pypi.example-private.io/simple requests
16
+ #5 0.887 Looking in indexes: https://pypi.example-private.io/simple
17
+ #5 0.890 WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy.', OSError('Tunnel connection failed: 403 Forbidden'))': /simple/requests/
18
+ #5 1.391 WARNING: Retrying (Retry(total=3, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy.', OSError('Tunnel connection failed: 403 Forbidden'))': /simple/requests/
19
+ #5 2.393 WARNING: Retrying (Retry(total=2, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy.', OSError('Tunnel connection failed: 403 Forbidden'))': /simple/requests/
20
+ #5 4.395 WARNING: Retrying (Retry(total=1, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy.', OSError('Tunnel connection failed: 403 Forbidden'))': /simple/requests/
21
+ #5 8.397 WARNING: Retrying (Retry(total=0, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy.', OSError('Tunnel connection failed: 403 Forbidden'))': /simple/requests/
22
+ #5 8.401 ERROR: Could not find a version that satisfies the requirement requests (from versions: none)
23
+ #5 8.413 ERROR: No matching distribution found for requests
24
+ #5 ERROR: process "/bin/sh -c pip install --no-cache-dir --index-url https://pypi.example-private.io/simple requests" did not complete successfully: exit code: 1
25
+ ------
26
+ > [2/3] RUN pip install --no-cache-dir --index-url https://pypi.example-private.io/simple requests:
27
+ 0.887 Looking in indexes: https://pypi.example-private.io/simple
28
+ 0.890 WARNING: Retrying (Retry(total=4, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy.', OSError('Tunnel connection failed: 403 Forbidden'))': /simple/requests/
29
+ 1.391 WARNING: Retrying (Retry(total=3, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy.', OSError('Tunnel connection failed: 403 Forbidden'))': /simple/requests/
30
+ 2.393 WARNING: Retrying (Retry(total=2, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy.', OSError('Tunnel connection failed: 403 Forbidden'))': /simple/requests/
31
+ 4.395 WARNING: Retrying (Retry(total=1, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy.', OSError('Tunnel connection failed: 403 Forbidden'))': /simple/requests/
32
+ 8.397 WARNING: Retrying (Retry(total=0, connect=None, read=None, redirect=None, status=None)) after connection broken by 'ProxyError('Cannot connect to proxy.', OSError('Tunnel connection failed: 403 Forbidden'))': /simple/requests/
33
+ 8.401 ERROR: Could not find a version that satisfies the requirement requests (from versions: none)
34
+ 8.413 ERROR: No matching distribution found for requests
35
+ ------
36
+ Dockerfile:2
37
+ --------------------
38
+ 1 | FROM python:3.12-slim
39
+ 2 | >>> RUN pip install --no-cache-dir --index-url https://pypi.example-private.io/simple requests
40
+ 3 | RUN pip install --no-cache-dir requests
41
+ 4 |
42
+ --------------------
43
+ error: failed to solve: process "/bin/sh -c pip install --no-cache-dir --index-url https://pypi.example-private.io/simple requests" did not complete successfully: exit code: 1
@@ -0,0 +1,54 @@
1
+ #1 [internal] load build definition from Dockerfile
2
+ #1 transferring dockerfile: 193B done
3
+ #1 DONE 0.0s
4
+
5
+ #2 [internal] load metadata for docker.io/library/python:3.12-slim
6
+ #2 DONE 0.2s
7
+
8
+ #3 [internal] load .dockerignore
9
+ #3 transferring context: 2B done
10
+ #3 DONE 0.0s
11
+
12
+ #4 [1/3] FROM docker.io/library/python:3.12-slim@sha256:2f17fc044b579bab302c2e8054d3a686e2cb9a83de48e70534b94cd8ebbe06a9
13
+ #4 DONE 0.0s
14
+
15
+ #5 [internal] load build context
16
+ #5 transferring context: 26B done
17
+ #5 DONE 0.0s
18
+
19
+ #6 [2/3] COPY uv /usr/local/bin/uv
20
+ #6 CACHED
21
+
22
+ #7 [3/3] RUN uv pip install --system "requests @ https://github.com/psf/requests/archive/refs/tags/v2.32.3.tar.gz"
23
+ #7 0.175 Using Python 3.12.14 environment at: /usr/local
24
+ #7 9.090 × Failed to download and build `requests @
25
+ #7 9.090 │ https://github.com/psf/requests/archive/refs/tags/v2.32.3.tar.gz`
26
+ #7 9.090 ├─▶ Request failed after 3 retries in 8.9s
27
+ #7 9.090 ├─▶ Failed to fetch:
28
+ #7 9.090 │ `https://github.com/psf/requests/archive/refs/tags/v2.32.3.tar.gz`
29
+ #7 9.090 ├─▶ error sending request for url
30
+ #7 9.090 │ (https://github.com/psf/requests/archive/refs/tags/v2.32.3.tar.gz)
31
+ #7 9.090 ├─▶ client error (Connect)
32
+ #7 9.090 ╰─▶ tunnel error: unsuccessful
33
+ #7 ERROR: process "/bin/sh -c uv pip install --system \"requests @ https://github.com/psf/requests/archive/refs/tags/v2.32.3.tar.gz\"" did not complete successfully: exit code: 1
34
+ ------
35
+ > [3/3] RUN uv pip install --system "requests @ https://github.com/psf/requests/archive/refs/tags/v2.32.3.tar.gz":
36
+ 0.175 Using Python 3.12.14 environment at: /usr/local
37
+ 9.090 × Failed to download and build `requests @
38
+ 9.090 │ https://github.com/psf/requests/archive/refs/tags/v2.32.3.tar.gz`
39
+ 9.090 ├─▶ Request failed after 3 retries in 8.9s
40
+ 9.090 ├─▶ Failed to fetch:
41
+ 9.090 │ `https://github.com/psf/requests/archive/refs/tags/v2.32.3.tar.gz`
42
+ 9.090 ├─▶ error sending request for url
43
+ 9.090 │ (https://github.com/psf/requests/archive/refs/tags/v2.32.3.tar.gz)
44
+ 9.090 ├─▶ client error (Connect)
45
+ 9.090 ╰─▶ tunnel error: unsuccessful
46
+ ------
47
+ Dockerfile:3
48
+ --------------------
49
+ 1 | FROM python:3.12-slim
50
+ 2 | COPY uv /usr/local/bin/uv
51
+ 3 | >>> RUN uv pip install --system "requests @ https://github.com/psf/requests/archive/refs/tags/v2.32.3.tar.gz"
52
+ 4 |
53
+ --------------------
54
+ error: failed to solve: process "/bin/sh -c uv pip install --system \"requests @ https://github.com/psf/requests/archive/refs/tags/v2.32.3.tar.gz\"" did not complete successfully: exit code: 1
@@ -0,0 +1,30 @@
1
+ warning libmamba Download error (56) Failure when receiving data from the peer [https://conda.anaconda.org/conda-forge/noarch/repodata.json.zst]
2
+ CONNECT tunnel failed, response 403
3
+ warning libmamba Retrying in 2 seconds
4
+ warning libmamba Download error (56) Failure when receiving data from the peer [https://conda.anaconda.org/conda-forge/linux-64/repodata.json.zst]
5
+ CONNECT tunnel failed, response 403
6
+ warning libmamba Retrying in 2 seconds
7
+ warning libmamba Download error (56) Failure when receiving data from the peer [https://conda.anaconda.org/conda-forge/noarch/repodata.json.zst]
8
+ CONNECT tunnel failed, response 403
9
+ warning libmamba Retrying in 2 seconds
10
+ warning libmamba Download error (56) Failure when receiving data from the peer [https://conda.anaconda.org/conda-forge/linux-64/repodata.json.zst]
11
+ CONNECT tunnel failed, response 403
12
+ warning libmamba Retrying in 2 seconds
13
+ warning libmamba Download error (56) Failure when receiving data from the peer [https://conda.anaconda.org/conda-forge/noarch/repodata.json.zst]
14
+ CONNECT tunnel failed, response 403
15
+ warning libmamba Retrying in 2 seconds
16
+ warning libmamba Download error (56) Failure when receiving data from the peer [https://conda.anaconda.org/conda-forge/linux-64/repodata.json.zst]
17
+ CONNECT tunnel failed, response 403
18
+ warning libmamba Retrying in 2 seconds
19
+ warning libmamba Download error (56) Failure when receiving data from the peer [https://conda.anaconda.org/conda-forge/noarch/repodata.json.zst]
20
+ CONNECT tunnel failed, response 403
21
+ warning libmamba Retrying in 2 seconds
22
+ critical libmamba Multiple errors occurred:
23
+ Download error (56) Failure when receiving data from the peer [https://conda.anaconda.org/conda-forge/noarch/repodata.json.zst]
24
+ CONNECT tunnel failed, response 403
25
+ Subdir conda-forge/noarch not loaded!
26
+ If you run into this error repeatedly, your package cache may be corrupted.
27
+ Please try running `mamba clean -a` to remove this cache before retrying the operation.
28
+
29
+ If you still are having issues, please report the error on `mamba-org/mamba`'s issue tracker:
30
+ https://github.com/mamba-org/mamba/issues/new?assignees=&labels=&projects=&template=bug.yml