runta-sdk 0.2.3__tar.gz → 0.2.4__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 (363) hide show
  1. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/PKG-INFO +5 -3
  2. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/README.md +4 -2
  3. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/pyproject.toml +1 -1
  4. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/runta_sdk.egg-info/PKG-INFO +5 -3
  5. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/streaming_transfer.py +210 -47
  6. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_download_dir_contents.py +271 -2
  7. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/integrations/harbor/runta_harbor/__init__.py +0 -0
  8. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/integrations/harbor/runta_harbor/environment.py +0 -0
  9. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/integrations/harbor/runta_harbor/py.typed +0 -0
  10. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/integrations/openai-agents-runta/src/agents_runta/__init__.py +0 -0
  11. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/integrations/openai-agents-runta/src/agents_runta/durable/__init__.py +0 -0
  12. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/integrations/openai-agents-runta/src/agents_runta/durable/runner.py +0 -0
  13. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/integrations/openai-agents-runta/src/agents_runta/durable/store.py +0 -0
  14. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/integrations/openai-agents-runta/src/agents_runta/py.typed +0 -0
  15. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/integrations/openai-agents-runta/src/agents_runta/sandbox.py +0 -0
  16. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/runta_sdk.egg-info/SOURCES.txt +0 -0
  17. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/runta_sdk.egg-info/dependency_links.txt +0 -0
  18. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/runta_sdk.egg-info/requires.txt +0 -0
  19. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/runta_sdk.egg-info/top_level.txt +0 -0
  20. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/setup.cfg +0 -0
  21. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/__init__.py +0 -0
  22. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/__init__.py +0 -0
  23. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/async_file_io.py +0 -0
  24. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/async_http.py +0 -0
  25. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/byte_budget.py +0 -0
  26. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/config.py +0 -0
  27. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/execution.py +0 -0
  28. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/execution.sh +0 -0
  29. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/helpers.py +0 -0
  30. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/http_limits.py +0 -0
  31. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/__init__.py +0 -0
  32. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/__init__.py +0 -0
  33. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/auth/__init__.py +0 -0
  34. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/auth/begin_device_authorization.py +0 -0
  35. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/auth/exchange_device_token.py +0 -0
  36. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/auth/revoke_current_token.py +0 -0
  37. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/checkpoints/__init__.py +0 -0
  38. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/checkpoints/create_checkpoint.py +0 -0
  39. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/checkpoints/delete_checkpoint.py +0 -0
  40. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/checkpoints/get_checkpoint.py +0 -0
  41. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/checkpoints/list_checkpoints.py +0 -0
  42. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/cloud_agents/__init__.py +0 -0
  43. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/cloud_agents/cancel_cloud_agent_run.py +0 -0
  44. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/cloud_agents/create_cloud_agent.py +0 -0
  45. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/cloud_agents/create_cloud_agent_artifact.py +0 -0
  46. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/cloud_agents/create_cloud_agent_computer_session.py +0 -0
  47. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/cloud_agents/create_cloud_agent_run.py +0 -0
  48. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/cloud_agents/delete_cloud_agent.py +0 -0
  49. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/cloud_agents/delete_cloud_agent_artifact.py +0 -0
  50. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/cloud_agents/delete_cloud_agent_workspace_file.py +0 -0
  51. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/cloud_agents/execute_cloud_agent_workspace_operation.py +0 -0
  52. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/cloud_agents/follow_up_cloud_agent_run.py +0 -0
  53. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/cloud_agents/get_cloud_agent.py +0 -0
  54. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/cloud_agents/get_cloud_agent_artifact.py +0 -0
  55. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/cloud_agents/get_cloud_agent_run.py +0 -0
  56. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/cloud_agents/list_cloud_agent_artifacts.py +0 -0
  57. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/cloud_agents/list_cloud_agent_runs.py +0 -0
  58. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/cloud_agents/list_cloud_agent_session_events.py +0 -0
  59. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/cloud_agents/list_cloud_agents.py +0 -0
  60. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/cloud_agents/resume_cloud_agent_run.py +0 -0
  61. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/cloud_agents/stream_cloud_agent_run_events.py +0 -0
  62. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/cloud_agents/update_cloud_agent.py +0 -0
  63. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/cloud_agents/write_cloud_agent_workspace_file.py +0 -0
  64. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/events/__init__.py +0 -0
  65. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/events/get_organization_event.py +0 -0
  66. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/events/get_organization_token_analysis.py +0 -0
  67. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/events/list_organization_events.py +0 -0
  68. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/events/list_organization_token_analysis.py +0 -0
  69. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/events/list_organization_token_savings.py +0 -0
  70. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/files/__init__.py +0 -0
  71. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/files/read_runtime_file.py +0 -0
  72. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/files/write_runtime_file.py +0 -0
  73. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/git_hub/__init__.py +0 -0
  74. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/git_hub/create_git_hub_authorization_request.py +0 -0
  75. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/git_hub/create_git_hub_runtime_binding.py +0 -0
  76. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/git_hub/delete_git_hub_runtime_binding.py +0 -0
  77. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/git_hub/get_git_hub_authorization_request.py +0 -0
  78. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/git_hub/get_git_hub_runtime_binding.py +0 -0
  79. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/git_hub/list_git_hub_authorization_requests.py +0 -0
  80. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/git_hub/list_git_hub_branches.py +0 -0
  81. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/git_hub/list_git_hub_repositories.py +0 -0
  82. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/git_hub/replace_git_hub_runtime_bindings.py +0 -0
  83. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/health/__init__.py +0 -0
  84. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/health/head_healthz.py +0 -0
  85. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/health/healthz.py +0 -0
  86. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/identity/__init__.py +0 -0
  87. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/identity/get_me.py +0 -0
  88. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/managed_model_providers/__init__.py +0 -0
  89. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/managed_model_providers/list_managed_model_providers.py +0 -0
  90. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/managed_model_providers/update_managed_model_provider.py +0 -0
  91. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/runtimes/__init__.py +0 -0
  92. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/runtimes/cancel_runtime_image_build.py +0 -0
  93. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/runtimes/create_runtime.py +0 -0
  94. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/runtimes/create_runtime_image_build.py +0 -0
  95. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/runtimes/create_runtime_vnc_credential.py +0 -0
  96. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/runtimes/delete_runtime.py +0 -0
  97. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/runtimes/delete_runtime_image.py +0 -0
  98. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/runtimes/disable_runtime_vnc.py +0 -0
  99. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/runtimes/dismiss_runtime_image_build.py +0 -0
  100. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/runtimes/enable_runtime_vnc.py +0 -0
  101. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/runtimes/get_runtime.py +0 -0
  102. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/runtimes/get_runtime_image_build.py +0 -0
  103. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/runtimes/list_runtime_image_builds.py +0 -0
  104. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/runtimes/list_runtime_images.py +0 -0
  105. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/runtimes/list_runtime_vnc_credentials.py +0 -0
  106. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/runtimes/list_runtimes.py +0 -0
  107. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/runtimes/patch_runtime.py +0 -0
  108. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/runtimes/pause_runtime.py +0 -0
  109. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/runtimes/resume_runtime.py +0 -0
  110. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/runtimes/revoke_runtime_vnc_credential.py +0 -0
  111. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/runtimes/start_runtime.py +0 -0
  112. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/runtimes/stop_runtime.py +0 -0
  113. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/secrets/__init__.py +0 -0
  114. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/secrets/create_secret.py +0 -0
  115. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/secrets/delete_secret.py +0 -0
  116. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/secrets/get_secret.py +0 -0
  117. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/secrets/list_secrets.py +0 -0
  118. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/secrets/set_secret.py +0 -0
  119. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/ssh_keys/__init__.py +0 -0
  120. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/ssh_keys/attach_runtime_ssh_key.py +0 -0
  121. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/ssh_keys/create_ssh_key.py +0 -0
  122. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/ssh_keys/delete_ssh_key.py +0 -0
  123. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/ssh_keys/detach_runtime_ssh_key.py +0 -0
  124. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/ssh_keys/get_ssh_host_key.py +0 -0
  125. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/ssh_keys/list_runtime_ssh_keys.py +0 -0
  126. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/api/ssh_keys/list_ssh_keys.py +0 -0
  127. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/client.py +0 -0
  128. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/errors.py +0 -0
  129. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/__init__.py +0 -0
  130. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/allowlist_egress_policy.py +0 -0
  131. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/allowlist_egress_policy_mode.py +0 -0
  132. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/approved_git_hub_authorization.py +0 -0
  133. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/approved_git_hub_authorization_status.py +0 -0
  134. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/begin_device_authorization_request.py +0 -0
  135. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/begin_device_authorization_request_client_id.py +0 -0
  136. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/checkpoint.py +0 -0
  137. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/checkpoint_pagination.py +0 -0
  138. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/checkpoint_response.py +0 -0
  139. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/checkpoint_runtime_restore_request.py +0 -0
  140. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/checkpoint_source_runtime.py +0 -0
  141. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/cloud_agent.py +0 -0
  142. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/cloud_agent_artifact.py +0 -0
  143. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/cloud_agent_computer_session.py +0 -0
  144. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/cloud_agent_computer_session_channels.py +0 -0
  145. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/cloud_agent_event.py +0 -0
  146. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/cloud_agent_harness_request.py +0 -0
  147. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/cloud_agent_latest_reply.py +0 -0
  148. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/cloud_agent_list.py +0 -0
  149. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/cloud_agent_prompt_image.py +0 -0
  150. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/cloud_agent_prompt_image_mime_type.py +0 -0
  151. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/cloud_agent_prompt_image_type.py +0 -0
  152. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/cloud_agent_run.py +0 -0
  153. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/cloud_agent_runtime_reference.py +0 -0
  154. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/cloud_agent_runtime_reference_type.py +0 -0
  155. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/cloud_agent_session_events.py +0 -0
  156. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/cloud_agent_vnc_session_channel.py +0 -0
  157. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/cloud_agent_workspace_delete_request.py +0 -0
  158. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/cloud_agent_workspace_write_request.py +0 -0
  159. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/cloud_agent_workspace_write_result.py +0 -0
  160. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/cold_restore_resource_requests.py +0 -0
  161. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/cold_restore_resources.py +0 -0
  162. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/create_checkpoint_request.py +0 -0
  163. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/create_checkpoint_request_kind.py +0 -0
  164. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/create_cloud_agent_artifact_request.py +0 -0
  165. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/create_cloud_agent_request.py +0 -0
  166. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/create_cloud_agent_run_request.py +0 -0
  167. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/create_git_hub_authorization_request_request.py +0 -0
  168. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/create_git_hub_runtime_binding_request.py +0 -0
  169. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/create_llm_token_saving_policy.py +0 -0
  170. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/create_runtime_image_build_request.py +0 -0
  171. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/create_runtime_image_build_request_architecture.py +0 -0
  172. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/create_runtime_image_selection.py +0 -0
  173. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/create_runtime_resource_requests.py +0 -0
  174. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/create_runtime_resources.py +0 -0
  175. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/create_secret_request.py +0 -0
  176. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/create_ssh_key_request.py +0 -0
  177. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/create_vnc_credential_request.py +0 -0
  178. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/create_vnc_credential_response.py +0 -0
  179. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/denied_git_hub_authorization.py +0 -0
  180. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/denied_git_hub_authorization_status.py +0 -0
  181. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/denylist_egress_policy.py +0 -0
  182. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/denylist_egress_policy_mode.py +0 -0
  183. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/device_authorization_start.py +0 -0
  184. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/device_authorization_start_response.py +0 -0
  185. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/device_token_error.py +0 -0
  186. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/device_token_response.py +0 -0
  187. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/disabled_idle_policy.py +0 -0
  188. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/disabled_idle_policy_mode.py +0 -0
  189. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/empty_object.py +0 -0
  190. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/empty_response.py +0 -0
  191. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/error_body.py +0 -0
  192. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/error_envelope.py +0 -0
  193. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/event.py +0 -0
  194. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/event_list.py +0 -0
  195. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/event_list_response.py +0 -0
  196. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/event_response.py +0 -0
  197. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/exchange_device_token_request.py +0 -0
  198. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/expired_git_hub_authorization.py +0 -0
  199. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/expired_git_hub_authorization_status.py +0 -0
  200. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/fresh_runtime_create_request.py +0 -0
  201. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/fresh_runtime_create_request_environment_variables.py +0 -0
  202. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/git_hub_authorization_decision_metadata.py +0 -0
  203. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/git_hub_authorization_request.py +0 -0
  204. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/git_hub_authorization_request_list.py +0 -0
  205. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/git_hub_authorization_request_list_response.py +0 -0
  206. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/git_hub_authorization_request_response.py +0 -0
  207. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/git_hub_branch.py +0 -0
  208. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/git_hub_branch_list.py +0 -0
  209. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/git_hub_branch_list_response.py +0 -0
  210. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/git_hub_installation.py +0 -0
  211. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/git_hub_repository.py +0 -0
  212. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/git_hub_repository_list.py +0 -0
  213. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/git_hub_repository_list_response.py +0 -0
  214. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/git_hub_runtime_binding.py +0 -0
  215. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/git_hub_runtime_binding_list.py +0 -0
  216. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/git_hub_runtime_binding_list_response.py +0 -0
  217. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/git_hub_runtime_binding_response.py +0 -0
  218. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/installed_git_hub_authorization.py +0 -0
  219. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/installed_git_hub_authorization_status.py +0 -0
  220. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/list_checkpoints_response.py +0 -0
  221. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/list_runtime_image_builds_response.py +0 -0
  222. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/list_runtime_images_response.py +0 -0
  223. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/list_runtimes_response.py +0 -0
  224. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/list_secrets_response.py +0 -0
  225. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/list_ssh_keys_response.py +0 -0
  226. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/list_vnc_credentials_response.py +0 -0
  227. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/llm_token_saving_policy.py +0 -0
  228. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/managed_model_provider.py +0 -0
  229. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/managed_model_provider_list.py +0 -0
  230. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/managed_model_provider_reference.py +0 -0
  231. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/managed_model_provider_reference_type.py +0 -0
  232. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/patch_llm_token_saving_policy.py +0 -0
  233. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/patch_runtime_request.py +0 -0
  234. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/patch_runtime_request_environment_variables.py +0 -0
  235. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/patch_runtime_resource_requests.py +0 -0
  236. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/patch_runtime_resources.py +0 -0
  237. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/pending_git_hub_authorization.py +0 -0
  238. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/pending_git_hub_authorization_status.py +0 -0
  239. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/public_checkpoint_state.py +0 -0
  240. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/public_error_code.py +0 -0
  241. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/public_ingress_protocol.py +0 -0
  242. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/public_ingress_spec.py +0 -0
  243. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/public_runtime_status.py +0 -0
  244. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/replace_git_hub_runtime_bindings_request.py +0 -0
  245. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/replace_git_hub_runtime_bindings_request_repositories_item.py +0 -0
  246. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime.py +0 -0
  247. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_desired_status.py +0 -0
  248. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_environment_variables.py +0 -0
  249. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_image.py +0 -0
  250. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_image_architectures_item.py +0 -0
  251. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_image_build.py +0 -0
  252. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_image_build_architecture.py +0 -0
  253. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_image_build_attempt.py +0 -0
  254. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_image_build_attempt_outcome.py +0 -0
  255. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_image_build_response.py +0 -0
  256. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_image_build_status.py +0 -0
  257. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_image_disk_capability.py +0 -0
  258. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_image_model_provider.py +0 -0
  259. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_image_protocol_binding.py +0 -0
  260. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_image_recommended_resources.py +0 -0
  261. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_image_subscription_option.py +0 -0
  262. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_image_web_ui.py +0 -0
  263. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_pagination.py +0 -0
  264. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_repository_selection.py +0 -0
  265. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_resource_current.py +0 -0
  266. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_resource_limits.py +0 -0
  267. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_resource_requests.py +0 -0
  268. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_resources.py +0 -0
  269. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_response.py +0 -0
  270. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_secret_configuration.py +0 -0
  271. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_workspace_file_entry.py +0 -0
  272. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_workspace_file_kind.py +0 -0
  273. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_workspace_operation_kind.py +0 -0
  274. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_workspace_operation_request.py +0 -0
  275. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_workspace_operation_result.py +0 -0
  276. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_workspace_port.py +0 -0
  277. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/runtime_workspace_search_match.py +0 -0
  278. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/secret.py +0 -0
  279. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/secret_egress_injection.py +0 -0
  280. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/secret_environment_injection.py +0 -0
  281. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/secret_file_injection.py +0 -0
  282. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/secret_injection_action.py +0 -0
  283. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/secret_response.py +0 -0
  284. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/set_secret_request.py +0 -0
  285. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/ssh_host_key.py +0 -0
  286. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/ssh_host_key_response.py +0 -0
  287. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/ssh_key.py +0 -0
  288. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/ssh_key_response.py +0 -0
  289. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/suspend_and_wakeup_idle_policy.py +0 -0
  290. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/suspend_and_wakeup_idle_policy_mode.py +0 -0
  291. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/suspend_only_idle_policy.py +0 -0
  292. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/suspend_only_idle_policy_mode.py +0 -0
  293. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/token_analysis_detail.py +0 -0
  294. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/token_analysis_detail_response.py +0 -0
  295. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/token_analysis_finding.py +0 -0
  296. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/token_analysis_finding_confidence.py +0 -0
  297. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/token_analysis_finding_kind.py +0 -0
  298. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/token_analysis_finding_severity.py +0 -0
  299. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/token_analysis_issue.py +0 -0
  300. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/token_analysis_issue_confidence.py +0 -0
  301. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/token_analysis_issue_kind.py +0 -0
  302. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/token_analysis_issue_severity.py +0 -0
  303. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/token_analysis_list.py +0 -0
  304. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/token_analysis_list_response.py +0 -0
  305. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/token_analysis_summary.py +0 -0
  306. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/token_analysis_tool_call.py +0 -0
  307. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/token_saving_event.py +0 -0
  308. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/token_saving_method.py +0 -0
  309. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/token_saving_method_method.py +0 -0
  310. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/token_savings_list.py +0 -0
  311. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/token_savings_list_response.py +0 -0
  312. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/token_savings_summary.py +0 -0
  313. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/update_cloud_agent_request.py +0 -0
  314. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/update_managed_model_provider_request.py +0 -0
  315. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/user_profile.py +0 -0
  316. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/user_profile_response.py +0 -0
  317. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/vnc_credential.py +0 -0
  318. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/vnc_credential_connection.py +0 -0
  319. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/vnc_credential_connection_security_type.py +0 -0
  320. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/vnc_credential_response.py +0 -0
  321. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/vnc_gateway_connection.py +0 -0
  322. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/vnc_gateway_connection_security_type.py +0 -0
  323. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/models/vnc_gateway_connection_username.py +0 -0
  324. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/openapi/types.py +0 -0
  325. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/pagination.py +0 -0
  326. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/rest_tls.py +0 -0
  327. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/retry.py +0 -0
  328. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/sync_http.py +0 -0
  329. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/tls_resumption.py +0 -0
  330. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/transport.py +0 -0
  331. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/_internal/user_agent.py +0 -0
  332. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/src/runta/py.typed +0 -0
  333. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_api_reference_generation.py +0 -0
  334. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_async_file_io.py +0 -0
  335. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_async_http_transport.py +0 -0
  336. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_checkpoint_metadata.py +0 -0
  337. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_config_and_helpers.py +0 -0
  338. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_connection_pool.py +0 -0
  339. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_delete_runtime_retry.py +0 -0
  340. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_directory_upload.py +0 -0
  341. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_directory_upload_concurrency.py +0 -0
  342. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_download_dir_contents_live.py +0 -0
  343. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_execution.py +0 -0
  344. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_execution_result_stream.py +0 -0
  345. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_fetch_openapi.py +0 -0
  346. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_get_runtime_retry.py +0 -0
  347. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_harbor_directory_download.py +0 -0
  348. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_harbor_e2e.py +0 -0
  349. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_harbor_integration.py +0 -0
  350. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_harbor_runta_environment.py +0 -0
  351. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_live.py +0 -0
  352. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_openai_extra_packaging.py +0 -0
  353. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_openapi_contract.py +0 -0
  354. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_openapi_transport.py +0 -0
  355. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_read_retries.py +0 -0
  356. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_rest_deployment.py +0 -0
  357. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_rest_tls.py +0 -0
  358. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_retry_policy.py +0 -0
  359. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_runtime_readiness.py +0 -0
  360. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_streaming_transfer.py +0 -0
  361. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_user_agent.py +0 -0
  362. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_websocket_tls.py +0 -0
  363. {runta_sdk-0.2.3 → runta_sdk-0.2.4}/tests/test_websocket_tls_resumption.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: runta-sdk
3
- Version: 0.2.3
3
+ Version: 0.2.4
4
4
  Summary: Python SDK for Runta runtime management
5
5
  Author: Runta
6
6
  License-Expression: MIT
@@ -158,8 +158,10 @@ example to ignore FIFOs and device nodes; by default these are rejected.
158
158
  Permissions follow `tarfile.data_filter` (including removal of unsafe mode bits
159
159
  and ownership). Safe links are preserved where supported; the standard library
160
160
  copies archive referents when link creation is unavailable. Unresolvable dangling
161
- symlinks are skipped on platforms that cannot create them. Use a current Python
162
- security patch release with safe tar link fallback; missing safety support raises
161
+ symlinks are skipped on platforms that cannot create them, preserving any
162
+ existing entry at that destination. The SDK uses native
163
+ filtered link fallback when available and provides a safe compatibility path on
164
+ older Python patch releases. A build without `tarfile.data_filter` still raises
163
165
  an error rather than extracting unsafely. As with standard tar extraction, do not
164
166
  allow another process to modify the destination concurrently during extraction.
165
167
 
@@ -130,8 +130,10 @@ example to ignore FIFOs and device nodes; by default these are rejected.
130
130
  Permissions follow `tarfile.data_filter` (including removal of unsafe mode bits
131
131
  and ownership). Safe links are preserved where supported; the standard library
132
132
  copies archive referents when link creation is unavailable. Unresolvable dangling
133
- symlinks are skipped on platforms that cannot create them. Use a current Python
134
- security patch release with safe tar link fallback; missing safety support raises
133
+ symlinks are skipped on platforms that cannot create them, preserving any
134
+ existing entry at that destination. The SDK uses native
135
+ filtered link fallback when available and provides a safe compatibility path on
136
+ older Python patch releases. A build without `tarfile.data_filter` still raises
135
137
  an error rather than extracting unsafely. As with standard tar extraction, do not
136
138
  allow another process to modify the destination concurrently during extraction.
137
139
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "runta-sdk"
7
- version = "0.2.3"
7
+ version = "0.2.4"
8
8
  description = "Python SDK for Runta runtime management"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: runta-sdk
3
- Version: 0.2.3
3
+ Version: 0.2.4
4
4
  Summary: Python SDK for Runta runtime management
5
5
  Author: Runta
6
6
  License-Expression: MIT
@@ -158,8 +158,10 @@ example to ignore FIFOs and device nodes; by default these are rejected.
158
158
  Permissions follow `tarfile.data_filter` (including removal of unsafe mode bits
159
159
  and ownership). Safe links are preserved where supported; the standard library
160
160
  copies archive referents when link creation is unavailable. Unresolvable dangling
161
- symlinks are skipped on platforms that cannot create them. Use a current Python
162
- security patch release with safe tar link fallback; missing safety support raises
161
+ symlinks are skipped on platforms that cannot create them, preserving any
162
+ existing entry at that destination. The SDK uses native
163
+ filtered link fallback when available and provides a safe compatibility path on
164
+ older Python patch releases. A build without `tarfile.data_filter` still raises
163
165
  an error rather than extracting unsafely. As with standard tar extraction, do not
164
166
  allow another process to modify the destination concurrently during extraction.
165
167
 
@@ -9,6 +9,7 @@ import errno
9
9
  from contextlib import asynccontextmanager, contextmanager
10
10
  import json
11
11
  import os
12
+ import posixpath
12
13
  import queue
13
14
  import socket
14
15
  import ssl
@@ -1146,9 +1147,82 @@ def _safe_relative_name(name: str) -> None:
1146
1147
  raise tarfile.FilterError("download archive contains an unsafe path")
1147
1148
 
1148
1149
 
1150
+ @contextmanager
1151
+ def _preserve_link_destination(targetpath: str):
1152
+ """Keep an existing entry when link creation/fallback produces no output."""
1153
+ target = Path(targetpath)
1154
+ if not os.path.lexists(target):
1155
+ yield
1156
+ return
1157
+ if target.is_dir():
1158
+ raise FileExistsError(
1159
+ f"download member conflicts with destination type: {target}"
1160
+ )
1161
+ # Move the entry, never copy its contents. The backup remains on the same
1162
+ # filesystem, and is restored before a skipped/failed link returns to tarfile.
1163
+ with tempfile.TemporaryDirectory(prefix=".runta-link-", dir=target.parent) as temp:
1164
+ original = Path(temp) / "original"
1165
+ os.replace(target, original)
1166
+ try:
1167
+ yield
1168
+ except BaseException:
1169
+ if not os.path.lexists(target):
1170
+ os.replace(original, target)
1171
+ raise
1172
+ if not os.path.lexists(target):
1173
+ os.replace(original, target)
1174
+ # Avoid tarfile applying hard-link attributes to the restored file
1175
+ # after a referent was excluded by the filter.
1176
+ raise tarfile.ExtractError("link fallback was skipped")
1177
+
1178
+
1149
1179
  class _DirectoryMergeTarFile(tarfile.TarFile):
1150
1180
  """Replace file entries without writing through existing destination aliases."""
1151
1181
 
1182
+ merge_filter: Callable[[tarfile.TarInfo, str], tarfile.TarInfo | None]
1183
+ merge_root: str
1184
+
1185
+ def makelink_with_filter(
1186
+ self,
1187
+ tarinfo: tarfile.TarInfo,
1188
+ targetpath: str,
1189
+ filter_function=None,
1190
+ extraction_root=None,
1191
+ ) -> None:
1192
+ if tarinfo.issym():
1193
+ # Windows symlink targets need native separators when stored in the
1194
+ # reparse point; archive references remain in POSIX form elsewhere.
1195
+ tarinfo = tarinfo.replace(
1196
+ linkname=os.path.normpath(tarinfo.linkname), deep=False
1197
+ )
1198
+ # Backports with this method differ: some filter the referent only,
1199
+ # while others also check its metadata at the copy destination.
1200
+ # Enforce both checks independently of the native implementation.
1201
+ filter_function = (
1202
+ self.merge_filter if filter_function is None else filter_function
1203
+ )
1204
+ extraction_root = (
1205
+ self.merge_root if extraction_root is None else extraction_root
1206
+ )
1207
+ actual_name = os.path.relpath(targetpath, extraction_root).replace(os.sep, "/")
1208
+
1209
+ def guarded_filter(member, destination):
1210
+ filtered = filter_function(member, destination)
1211
+ if filtered is not None:
1212
+ _filter_contents_member(
1213
+ filtered.replace(name=actual_name, deep=False),
1214
+ destination,
1215
+ )
1216
+ return filtered
1217
+
1218
+ with _preserve_link_destination(targetpath):
1219
+ super().makelink_with_filter(
1220
+ tarinfo,
1221
+ targetpath,
1222
+ guarded_filter,
1223
+ extraction_root,
1224
+ )
1225
+
1152
1226
  def makefile(self, tarinfo: tarfile.TarInfo, targetpath: str) -> None:
1153
1227
  # Do this at the actual write path, after filtering. A filter can also
1154
1228
  # run for a link fallback's referent, whose path must remain untouched.
@@ -1161,20 +1235,145 @@ class _DirectoryMergeTarFile(tarfile.TarFile):
1161
1235
  super().makefile(tarinfo, targetpath)
1162
1236
 
1163
1237
 
1238
+ class _LegacyDirectoryMergeTarFile(_DirectoryMergeTarFile):
1239
+ """Supply filtered link fallback when the interpreter does not provide it."""
1240
+
1241
+ def makelink(self, tarinfo: tarfile.TarInfo, targetpath: str) -> None:
1242
+ with _preserve_link_destination(targetpath):
1243
+ self._make_compat_link(tarinfo, targetpath)
1244
+
1245
+ def _make_compat_link(self, tarinfo: tarfile.TarInfo, targetpath: str) -> None:
1246
+ try:
1247
+ if tarinfo.issym():
1248
+ Path(targetpath).unlink(missing_ok=True)
1249
+ os.symlink(os.path.normpath(tarinfo.linkname), targetpath)
1250
+ return
1251
+ source = os.path.join(self.merge_root, tarinfo.linkname)
1252
+ if os.path.exists(source):
1253
+ Path(targetpath).unlink(missing_ok=True)
1254
+ os.link(source, targetpath)
1255
+ return
1256
+ except (AttributeError, NotImplementedError, OSError):
1257
+ pass
1258
+
1259
+ try:
1260
+ referent = self._find_link_target(tarinfo)
1261
+ except KeyError:
1262
+ if tarinfo.issym():
1263
+ # Match tarfile's nonfatal treatment of an unsupported dangling
1264
+ # symlink, without suppressing filter or I/O errors.
1265
+ raise tarfile.ExtractError(
1266
+ "unable to resolve link inside archive"
1267
+ ) from None
1268
+ raise tarfile.FilterError(
1269
+ "hard link target is missing from the archive"
1270
+ ) from None
1271
+
1272
+ # The original archive name is needed for further link lookup. Validate
1273
+ # that location through the user filter, then independently validate the
1274
+ # filtered metadata at the actual write path without invoking user code.
1275
+ filtered = self.merge_filter(referent, self.merge_root)
1276
+ if filtered is None:
1277
+ return
1278
+ actual_name = os.path.relpath(targetpath, self.merge_root).replace(os.sep, "/")
1279
+ relocated = _filter_contents_member(
1280
+ filtered.replace(name=actual_name, deep=False),
1281
+ self.merge_root,
1282
+ )
1283
+ filtered = relocated.replace(name=filtered.name, deep=False)
1284
+
1285
+ # Recursive aliases can otherwise recurse indefinitely on old tarfile.
1286
+ active = getattr(self, "_active_link_fallbacks", set())
1287
+ key = (referent.offset, os.path.abspath(targetpath))
1288
+ if key in active:
1289
+ raise tarfile.FilterError(
1290
+ "download archive contains a cyclic link fallback"
1291
+ )
1292
+ self._active_link_fallbacks = active
1293
+ active.add(key)
1294
+ try:
1295
+ # Reuse the seekable tar's file reader and the existing makefile
1296
+ # replacement semantics; no separate link-copy implementation.
1297
+ self._extract_member(filtered, targetpath)
1298
+ finally:
1299
+ active.remove(key)
1300
+
1301
+ def makelink_with_filter(
1302
+ self,
1303
+ tarinfo: tarfile.TarInfo,
1304
+ targetpath: str,
1305
+ filter_function=None,
1306
+ extraction_root=None,
1307
+ ) -> None:
1308
+ # Some vendor builds use the newer dispatcher without a usable native
1309
+ # implementation. Both dispatchers must enter the same guarded path.
1310
+ self.makelink(tarinfo, targetpath)
1311
+
1312
+
1313
+ def _filter_contents_member(
1314
+ member: tarfile.TarInfo,
1315
+ destination: str,
1316
+ *,
1317
+ allow_special: bool = False,
1318
+ ) -> tarfile.TarInfo:
1319
+ """Mandatory checks, also applied at the physical link-copy destination."""
1320
+ _safe_relative_name(member.name)
1321
+ if PurePosixPath(member.name) == PurePosixPath("."):
1322
+ raise tarfile.FilterError("a filter cannot replace the destination root")
1323
+ if member.issym() or member.islnk():
1324
+ link = member.linkname.replace(os.sep, "/")
1325
+ if (
1326
+ PurePosixPath(link).is_absolute()
1327
+ or PureWindowsPath(link).drive
1328
+ or "\\" in link
1329
+ or ":" in link
1330
+ or "\x00" in link
1331
+ ):
1332
+ raise tarfile.FilterError("download archive contains an unsafe link")
1333
+ # Match patched data_filter: collapse internal '..' components before
1334
+ # checking/creating a link. Otherwise a later archive symlink can change
1335
+ # the meaning of a previously accepted dangling link on old Python.
1336
+ member = member.replace(linkname=posixpath.normpath(link), deep=False)
1337
+ if member.isdev() and allow_special:
1338
+ member = copy.copy(member)
1339
+ member.type = tarfile.REGTYPE
1340
+ elif not (member.isreg() or member.isdir() or member.issym() or member.islnk()):
1341
+ # Older data_filter implementations can overlook special files with
1342
+ # mode=None. A callback must not be able to bypass this boundary.
1343
+ raise tarfile.SpecialFileError(member)
1344
+ member = tarfile.data_filter(member, destination)
1345
+ if (member.issym() or member.islnk()) and os.sep != "/":
1346
+ # Keep archive link references in POSIX form even when a native filter
1347
+ # returns Windows separators, so a later fallback can validate them too.
1348
+ member = member.replace(
1349
+ linkname=member.linkname.replace(os.sep, "/"), deep=False
1350
+ )
1351
+ target = Path(destination) / member.name
1352
+ if not allow_special and target.exists() and target.is_dir() != member.isdir():
1353
+ raise FileExistsError(
1354
+ f"download member conflicts with destination type: {target}"
1355
+ )
1356
+ return member
1357
+
1358
+
1164
1359
  def _extract_dir_contents(
1165
1360
  archive_path: Path,
1166
1361
  dst: Path,
1167
1362
  filter: Callable[[tarfile.TarInfo, str], tarfile.TarInfo | None] | None = None,
1168
1363
  ) -> None:
1169
1364
  data_filter = getattr(tarfile, "data_filter", None)
1170
- if data_filter is None or not hasattr(tarfile.TarFile, "makelink_with_filter"):
1365
+ if data_filter is None:
1171
1366
  raise RuntimeError(
1172
- "directory content downloads require a security-patched Python "
1173
- "with tarfile.data_filter and filtered link fallback"
1367
+ "directory content downloads require a Python build with tarfile.data_filter"
1174
1368
  )
1175
1369
  if dst.is_symlink():
1176
1370
  raise tarfile.FilterError("download destination must not be a symbolic link")
1177
- with _DirectoryMergeTarFile.open(archive_path, "r:", errorlevel=1) as archive:
1371
+ archive_type = (
1372
+ _DirectoryMergeTarFile
1373
+ if callable(getattr(tarfile.TarFile, "makelink_with_filter", None))
1374
+ else _LegacyDirectoryMergeTarFile
1375
+ )
1376
+ with archive_type.open(archive_path, "r:", errorlevel=1) as archive:
1178
1377
  members = archive.getmembers()
1179
1378
  if not members or members[0].name not in {".", "./"} or not members[0].isdir():
1180
1379
  raise _public.ApiError(
@@ -1211,53 +1410,17 @@ def _extract_dir_contents(
1211
1410
  ) -> tarfile.TarInfo | None:
1212
1411
  if member.name == ".":
1213
1412
  return None # Do not apply the source root's metadata to dst.
1214
- _safe_relative_name(member.name)
1215
- # Check boundaries before invoking user code, but allow the callback
1216
- # to skip special files before data_filter rejects those file types.
1217
- if member.issym() or member.islnk():
1218
- link = member.linkname
1219
- if (
1220
- PurePosixPath(link).is_absolute()
1221
- or PureWindowsPath(link).drive
1222
- or "\\" in link
1223
- or ":" in link
1224
- or "\x00" in link
1225
- ):
1226
- raise tarfile.FilterError(
1227
- "download archive contains an unsafe link"
1228
- )
1229
- probe = copy.copy(member)
1230
- if probe.isdev():
1231
- probe.type = tarfile.REGTYPE
1232
- data_filter(probe, destination)
1413
+ # Allow callbacks to skip special files, but validate all paths
1414
+ # and link targets before and after user code.
1415
+ _filter_contents_member(member, destination, allow_special=True)
1233
1416
  if filter is not None:
1234
1417
  member = filter(copy.copy(member), destination)
1235
1418
  if member is None:
1236
1419
  return None
1237
- _safe_relative_name(member.name)
1238
- if PurePosixPath(member.name) == PurePosixPath("."):
1239
- raise tarfile.FilterError(
1240
- "a filter cannot replace the destination root"
1241
- )
1242
- if member.issym() or member.islnk():
1243
- link = member.linkname
1244
- if (
1245
- PurePosixPath(link).is_absolute()
1246
- or PureWindowsPath(link).drive
1247
- or "\\" in link
1248
- or ":" in link
1249
- or "\x00" in link
1250
- ):
1251
- raise tarfile.FilterError(
1252
- "download archive contains an unsafe link"
1253
- )
1254
- member = data_filter(member, destination)
1255
- target = Path(destination) / member.name
1256
- if target.exists() and target.is_dir() != member.isdir():
1257
- raise FileExistsError(
1258
- f"download member conflicts with destination type: {target}"
1259
- )
1260
- return member
1420
+ return _filter_contents_member(member, destination)
1421
+
1422
+ archive.merge_filter = safe_filter
1423
+ archive.merge_root = os.fspath(dst)
1261
1424
 
1262
1425
  # errorlevel=1 (the default) propagates security/I/O failures while
1263
1426
  # allowing stdlib's nonfatal unresolved-link fallback to skip a link.
@@ -16,6 +16,23 @@ from runta._internal import streaming_transfer as transfer
16
16
  from runta._internal.async_file_io import _AsyncFileIO
17
17
 
18
18
 
19
+ @pytest.fixture(
20
+ autouse=True,
21
+ params=(
22
+ ["native", "compat"]
23
+ if callable(getattr(tarfile.TarFile, "makelink_with_filter", None))
24
+ else ["compat"]
25
+ ),
26
+ )
27
+ def link_fallback_capability(request, monkeypatch):
28
+ """Exercise fallback selection on patched hosts as well as real old Python."""
29
+ if request.param == "compat":
30
+ monkeypatch.setattr(
31
+ tarfile.TarFile, "makelink_with_filter", None, raising=False
32
+ )
33
+ return request.param
34
+
35
+
19
36
  def make_archive(path, entries=()):
20
37
  """Entries are (name, data/type, linkname), rooted at the remote tar's '.'."""
21
38
  with tarfile.open(path, "w") as archive:
@@ -98,7 +115,8 @@ async def test_transfer_merges_and_cleans(tmp_path, monkeypatch, asynchronous, e
98
115
  assert all(not path.parent.exists() for path in paths)
99
116
 
100
117
 
101
- def test_permissions_and_links(tmp_path):
118
+ @pytest.mark.parametrize("filter", [None, tarfile.data_filter])
119
+ def test_permissions_and_links(tmp_path, filter):
102
120
  target = extract(
103
121
  tmp_path,
104
122
  [
@@ -107,6 +125,7 @@ def test_permissions_and_links(tmp_path):
107
125
  ("./nested/sym", tarfile.SYMTYPE, "../data"),
108
126
  ("./hard", tarfile.LNKTYPE, "./data"),
109
127
  ],
128
+ filter,
110
129
  )
111
130
  assert (target / "nested/sym").is_symlink()
112
131
  assert (target / "nested/sym").read_bytes() == b"payload"
@@ -385,7 +404,7 @@ def test_remote_command_resolves_top_directory_and_quotes(tmp_path, symlink):
385
404
 
386
405
  def test_missing_security_support_fails_closed(tmp_path, monkeypatch):
387
406
  monkeypatch.delattr(tarfile, "data_filter")
388
- with pytest.raises(RuntimeError, match="security-patched"):
407
+ with pytest.raises(RuntimeError, match="tarfile.data_filter"):
389
408
  extract(tmp_path, [("./data", b"payload", "")])
390
409
  assert not (tmp_path / "target").exists()
391
410
 
@@ -539,3 +558,253 @@ def test_skipped_member_preserves_existing_alias(tmp_path):
539
558
  extract(tmp_path, [("./replace", b"new", "")], skip)
540
559
  assert (target / "replace").is_symlink()
541
560
  assert (target / "keep").read_bytes() == b"original"
561
+
562
+
563
+ @pytest.mark.parametrize("rename_referent", [False, True])
564
+ def test_link_fallback_filters_referent_at_actual_destination(
565
+ tmp_path, monkeypatch, rename_referent
566
+ ):
567
+ outside = tmp_path / "safe"
568
+ outside.write_text("outside")
569
+ real_symlink = os.symlink
570
+
571
+ def fail_alias(link, destination, *args, **kwargs):
572
+ if os.path.normpath(link) == os.path.normpath("deep/ref"):
573
+ raise OSError("force alias to copy its referent")
574
+ return real_symlink(link, destination, *args, **kwargs)
575
+
576
+ def callback(member, destination):
577
+ if rename_referent and member.name == "deep/ref":
578
+ return member.replace(name="deep/renamed")
579
+ return member
580
+
581
+ monkeypatch.setattr(os, "symlink", fail_alias)
582
+ with pytest.raises(tarfile.FilterError):
583
+ extract(
584
+ tmp_path,
585
+ [
586
+ ("./safe", b"inside", ""),
587
+ ("./deep/ref", tarfile.SYMTYPE, "../safe"),
588
+ ("./alias", tarfile.SYMTYPE, "deep/ref"),
589
+ ],
590
+ callback,
591
+ )
592
+ assert outside.read_text() == "outside"
593
+ assert not os.path.lexists(tmp_path / "target/alias")
594
+
595
+
596
+ def test_later_link_cannot_turn_an_accepted_link_into_an_escape(tmp_path):
597
+ target = extract(
598
+ tmp_path,
599
+ [
600
+ ("./alias", tarfile.SYMTYPE, "directory/../outside"),
601
+ ("./directory", tarfile.SYMTYPE, "."),
602
+ ],
603
+ )
604
+ assert (target / "alias").is_symlink()
605
+ assert (target / "alias").resolve() == target / "outside"
606
+
607
+
608
+ def test_callback_cannot_enable_special_files_with_missing_mode(tmp_path):
609
+ def callback(member, destination):
610
+ member.mode = None
611
+ return member
612
+
613
+ with pytest.raises(tarfile.SpecialFileError):
614
+ extract(tmp_path, [("./fifo", tarfile.FIFOTYPE, "")], callback)
615
+ assert not (tmp_path / "target/fifo").exists()
616
+
617
+
618
+ def test_compat_rejects_cyclic_link_copy(tmp_path, monkeypatch):
619
+ monkeypatch.setattr(tarfile.TarFile, "makelink_with_filter", None, raising=False)
620
+
621
+ def unavailable(*args, **kwargs):
622
+ raise OSError("links prohibited")
623
+
624
+ monkeypatch.setattr(os, "symlink", unavailable)
625
+ with pytest.raises(tarfile.FilterError, match="cyclic"):
626
+ extract(
627
+ tmp_path,
628
+ [
629
+ ("./a", tarfile.SYMTYPE, "b"),
630
+ ("./b", tarfile.SYMTYPE, "a"),
631
+ ],
632
+ )
633
+ assert not (tmp_path / "target/a").exists()
634
+ assert not (tmp_path / "target/b").exists()
635
+
636
+
637
+ @pytest.mark.parametrize("alias", ["file", "symlink", "hardlink", "dangling"])
638
+ def test_unsupported_dangling_link_preserves_existing_destination(
639
+ tmp_path, monkeypatch, alias
640
+ ):
641
+ target = tmp_path / "target"
642
+ target.mkdir()
643
+ keep = target / "keep"
644
+ keep.write_bytes(b"keep")
645
+ report = target / "report"
646
+ if alias == "file":
647
+ report.write_bytes(b"original")
648
+ elif alias == "hardlink":
649
+ os.link(keep, report)
650
+ else:
651
+ report.symlink_to("old-missing" if alias == "dangling" else "keep")
652
+ original_stat = report.lstat()
653
+
654
+ def unavailable(*args, **kwargs):
655
+ raise OSError("links prohibited")
656
+
657
+ monkeypatch.setattr(os, "symlink", unavailable)
658
+ extract(
659
+ tmp_path,
660
+ [
661
+ ("./report", tarfile.SYMTYPE, "new-missing"),
662
+ ("./last", b"last", ""),
663
+ ],
664
+ )
665
+ assert os.path.lexists(report)
666
+ assert report.lstat().st_mode == original_stat.st_mode
667
+ assert keep.read_bytes() == b"keep"
668
+ if alias == "file":
669
+ assert report.read_bytes() == b"original"
670
+ elif alias == "hardlink":
671
+ assert os.path.samefile(keep, report)
672
+ else:
673
+ assert os.readlink(report) == ("old-missing" if alias == "dangling" else "keep")
674
+ assert (target / "last").read_bytes() == b"last"
675
+ assert not list(target.glob(".runta-link-*"))
676
+
677
+
678
+ def test_filtered_fallback_preserves_existing_destination_metadata(
679
+ tmp_path, monkeypatch
680
+ ):
681
+ target = tmp_path / "target"
682
+ target.mkdir()
683
+ report = target / "report"
684
+ report.write_bytes(b"original")
685
+ report.chmod(0o600)
686
+ before = report.stat()
687
+
688
+ def unavailable(*args, **kwargs):
689
+ raise OSError("links prohibited")
690
+
691
+ def skip_referent(member, destination):
692
+ return None if member.name == "data" else member
693
+
694
+ monkeypatch.setattr(os, "link", unavailable)
695
+ extract(
696
+ tmp_path,
697
+ [
698
+ ("./data", b"new", ""),
699
+ ("./report", tarfile.LNKTYPE, "./data"),
700
+ ("./last", b"last", ""),
701
+ ],
702
+ skip_referent,
703
+ )
704
+ assert report.read_bytes() == b"original"
705
+ assert report.stat().st_mode == before.st_mode
706
+ assert report.stat().st_mtime_ns == before.st_mtime_ns
707
+ assert (target / "last").read_bytes() == b"last"
708
+ assert not list(target.glob(".runta-link-*"))
709
+
710
+
711
+ @pytest.mark.parametrize("fault", ["filter", "copy"])
712
+ def test_link_fallback_failure_restores_existing_destination(
713
+ tmp_path, monkeypatch, fault
714
+ ):
715
+ target = tmp_path / "target"
716
+ target.mkdir()
717
+ report = target / "report"
718
+ report.write_bytes(b"original")
719
+
720
+ def unavailable(*args, **kwargs):
721
+ raise OSError("links prohibited")
722
+
723
+ def callback(member, destination):
724
+ if fault == "filter" and member.name == "data":
725
+ raise ValueError("injected failure")
726
+ return member
727
+
728
+ def failed_copy(*args, **kwargs):
729
+ raise OSError("injected failure")
730
+
731
+ monkeypatch.setattr(os, "symlink", unavailable)
732
+ if fault == "copy":
733
+ monkeypatch.setattr(transfer._DirectoryMergeTarFile, "makefile", failed_copy)
734
+ with pytest.raises(
735
+ ValueError if fault == "filter" else OSError, match="injected failure"
736
+ ):
737
+ extract(
738
+ tmp_path,
739
+ [
740
+ ("./report", tarfile.SYMTYPE, "data"),
741
+ ("./data", b"new", ""),
742
+ ],
743
+ callback,
744
+ )
745
+ assert report.read_bytes() == b"original"
746
+ assert not list(target.glob(".runta-link-*"))
747
+
748
+
749
+ @pytest.mark.asyncio
750
+ async def test_cancel_drains_link_replacement_before_restoring_and_cleaning(
751
+ tmp_path, monkeypatch
752
+ ):
753
+ target = tmp_path / "target"
754
+ target.mkdir()
755
+ report = target / "report"
756
+ report.write_bytes(b"original")
757
+ entered = threading.Event()
758
+ release = threading.Event()
759
+ archives = []
760
+
761
+ async def download(*args, **kwargs):
762
+ archives.append(args[4])
763
+ await kwargs["_file_io"].run(
764
+ make_archive,
765
+ args[4],
766
+ [
767
+ ("./report", tarfile.SYMTYPE, "missing"),
768
+ ("./data", b"payload", ""),
769
+ ],
770
+ )
771
+
772
+ def unavailable(*args, **kwargs):
773
+ entered.set()
774
+ assert release.wait(5)
775
+ raise OSError("links prohibited")
776
+
777
+ monkeypatch.setattr(transfer, "_async_download_archive", download)
778
+ monkeypatch.setattr(os, "symlink", unavailable)
779
+ task = asyncio.create_task(
780
+ transfer.async_download_dir_contents(
781
+ "http://test",
782
+ "token",
783
+ "runtime",
784
+ "/src",
785
+ target,
786
+ timeout=1,
787
+ )
788
+ )
789
+ try:
790
+
791
+ async def wait_entered():
792
+ while not entered.is_set():
793
+ await asyncio.sleep(0)
794
+
795
+ await asyncio.wait_for(wait_entered(), 5)
796
+ task.cancel()
797
+ await asyncio.sleep(0)
798
+ task.cancel()
799
+ await asyncio.sleep(0)
800
+ assert not task.done()
801
+ assert archives[0].exists()
802
+ assert list(target.glob(".runta-link-*"))
803
+ finally:
804
+ release.set()
805
+ with pytest.raises(asyncio.CancelledError):
806
+ await task
807
+ assert report.read_bytes() == b"original"
808
+ assert (target / "data").read_bytes() == b"payload"
809
+ assert not list(target.glob(".runta-link-*"))
810
+ assert not archives[0].parent.exists()