Fix permissions issue in docker Sandbox (#11549)

This commit is contained in:
Tim O'Farrell
2025-10-28 14:24:54 -06:00
committed by GitHub
parent 7447cfdb3d
commit fccc6f3196
10 changed files with 58 additions and 60 deletions

30
enterprise/poetry.lock generated
View File

@@ -5737,7 +5737,7 @@ llama = ["llama-index (>=0.12.29,<0.13.0)", "llama-index-core (>=0.12.29,<0.13.0
[[package]]
name = "openhands-agent-server"
version = "1.0.0a3"
version = "1.0.0a4"
description = "OpenHands Agent Server - REST/WebSocket interface for OpenHands AI Agent"
optional = false
python-versions = ">=3.12"
@@ -5758,9 +5758,9 @@ wsproto = ">=1.2.0"
[package.source]
type = "git"
url = "https://github.com/All-Hands-AI/agent-sdk.git"
reference = "8d8134ca5a87cc3e90e3ff968327a7f4c961e22e"
resolved_reference = "8d8134ca5a87cc3e90e3ff968327a7f4c961e22e"
url = "https://github.com/OpenHands/agent-sdk.git"
reference = "ce0a71af55dfce101f7419fbdb0116178f01e109"
resolved_reference = "ce0a71af55dfce101f7419fbdb0116178f01e109"
subdirectory = "openhands-agent-server"
[[package]]
@@ -5805,9 +5805,9 @@ memory-profiler = "^0.61.0"
numpy = "*"
openai = "1.99.9"
openhands-aci = "0.3.2"
openhands-agent-server = {git = "https://github.com/All-Hands-AI/agent-sdk.git", rev = "8d8134ca5a87cc3e90e3ff968327a7f4c961e22e", subdirectory = "openhands-agent-server"}
openhands-sdk = {git = "https://github.com/All-Hands-AI/agent-sdk.git", rev = "8d8134ca5a87cc3e90e3ff968327a7f4c961e22e", subdirectory = "openhands-sdk"}
openhands-tools = {git = "https://github.com/All-Hands-AI/agent-sdk.git", rev = "8d8134ca5a87cc3e90e3ff968327a7f4c961e22e", subdirectory = "openhands-tools"}
openhands-agent-server = {git = "https://github.com/OpenHands/agent-sdk.git", rev = "ce0a71af55dfce101f7419fbdb0116178f01e109", subdirectory = "openhands-agent-server"}
openhands-sdk = {git = "https://github.com/OpenHands/agent-sdk.git", rev = "ce0a71af55dfce101f7419fbdb0116178f01e109", subdirectory = "openhands-sdk"}
openhands-tools = {git = "https://github.com/OpenHands/agent-sdk.git", rev = "ce0a71af55dfce101f7419fbdb0116178f01e109", subdirectory = "openhands-tools"}
opentelemetry-api = "^1.33.1"
opentelemetry-exporter-otlp-proto-grpc = "^1.33.1"
pathspec = "^0.12.1"
@@ -5863,7 +5863,7 @@ url = ".."
[[package]]
name = "openhands-sdk"
version = "1.0.0a3"
version = "1.0.0a4"
description = "OpenHands SDK - Core functionality for building AI agents"
optional = false
python-versions = ">=3.12"
@@ -5886,14 +5886,14 @@ boto3 = ["boto3 (>=1.35.0)"]
[package.source]
type = "git"
url = "https://github.com/All-Hands-AI/agent-sdk.git"
reference = "8d8134ca5a87cc3e90e3ff968327a7f4c961e22e"
resolved_reference = "8d8134ca5a87cc3e90e3ff968327a7f4c961e22e"
url = "https://github.com/OpenHands/agent-sdk.git"
reference = "ce0a71af55dfce101f7419fbdb0116178f01e109"
resolved_reference = "ce0a71af55dfce101f7419fbdb0116178f01e109"
subdirectory = "openhands-sdk"
[[package]]
name = "openhands-tools"
version = "1.0.0a3"
version = "1.0.0a4"
description = "OpenHands Tools - Runtime tools for AI agents"
optional = false
python-versions = ">=3.12"
@@ -5913,9 +5913,9 @@ pydantic = ">=2.11.7"
[package.source]
type = "git"
url = "https://github.com/All-Hands-AI/agent-sdk.git"
reference = "8d8134ca5a87cc3e90e3ff968327a7f4c961e22e"
resolved_reference = "8d8134ca5a87cc3e90e3ff968327a7f4c961e22e"
url = "https://github.com/OpenHands/agent-sdk.git"
reference = "ce0a71af55dfce101f7419fbdb0116178f01e109"
resolved_reference = "ce0a71af55dfce101f7419fbdb0116178f01e109"
subdirectory = "openhands-tools"
[[package]]

View File

@@ -12,8 +12,8 @@ from openhands.app_server.app_conversation.app_conversation_models import (
AppConversationStartTask,
)
from openhands.app_server.services.injector import Injector
from openhands.sdk import Workspace
from openhands.sdk.utils.models import DiscriminatedUnionMixin
from openhands.sdk.workspace.remote.async_remote_workspace import AsyncRemoteWorkspace
class AppConversationService(ABC):
@@ -90,8 +90,7 @@ class AppConversationService(ABC):
async def run_setup_scripts(
self,
task: AppConversationStartTask,
workspace: Workspace,
working_dir: str,
workspace: AsyncRemoteWorkspace,
) -> AsyncGenerator[AppConversationStartTask, None]:
"""Run the setup scripts for the project and yield status updates"""
yield task

View File

@@ -36,35 +36,36 @@ class GitAppConversationService(AppConversationService, ABC):
self,
task: AppConversationStartTask,
workspace: AsyncRemoteWorkspace,
working_dir: str,
) -> AsyncGenerator[AppConversationStartTask, None]:
task.status = AppConversationStartTaskStatus.PREPARING_REPOSITORY
yield task
await self.clone_or_init_git_repo(task, workspace, working_dir)
await self.clone_or_init_git_repo(task, workspace)
task.status = AppConversationStartTaskStatus.RUNNING_SETUP_SCRIPT
yield task
await self.maybe_run_setup_script(workspace, working_dir)
await self.maybe_run_setup_script(workspace)
task.status = AppConversationStartTaskStatus.SETTING_UP_GIT_HOOKS
yield task
await self.maybe_setup_git_hooks(workspace, working_dir)
await self.maybe_setup_git_hooks(workspace)
async def clone_or_init_git_repo(
self,
task: AppConversationStartTask,
workspace: AsyncRemoteWorkspace,
working_dir: str,
):
request = task.request
if not request.selected_repository:
if self.init_git_in_empty_workspace:
_logger.debug('Initializing a new git repository in the workspace.')
await workspace.execute_command(
'git init && git config --global --add safe.directory '
+ working_dir
cmd = (
'git init && git config --global '
f'--add safe.directory {workspace.working_dir}'
)
result = await workspace.execute_command(cmd, workspace.working_dir)
if result.exit_code:
_logger.warning(f'Git init failed: {result.stderr}')
else:
_logger.info('Not initializing a new git repository.')
return
@@ -79,7 +80,8 @@ class GitAppConversationService(AppConversationService, ABC):
# Clone the repo - this is the slow part!
clone_command = f'git clone {remote_repo_url} {dir_name}'
await workspace.execute_command(clone_command, working_dir)
result = await workspace.execute_command(clone_command, workspace.working_dir)
print(result)
# Checkout the appropriate branch
if request.selected_branch:
@@ -89,15 +91,14 @@ class GitAppConversationService(AppConversationService, ABC):
random_str = base62.encodebytes(os.urandom(16))
openhands_workspace_branch = f'openhands-workspace-{random_str}'
checkout_command = f'git checkout -b {openhands_workspace_branch}'
await workspace.execute_command(checkout_command, working_dir)
await workspace.execute_command(checkout_command, workspace.working_dir)
async def maybe_run_setup_script(
self,
workspace: AsyncRemoteWorkspace,
working_dir: str,
):
"""Run .openhands/setup.sh if it exists in the workspace or repository."""
setup_script = working_dir + '/.openhands/setup.sh'
setup_script = workspace.working_dir + '/.openhands/setup.sh'
await workspace.execute_command(
f'chmod +x {setup_script} && source {setup_script}', timeout=600
@@ -111,11 +112,10 @@ class GitAppConversationService(AppConversationService, ABC):
async def maybe_setup_git_hooks(
self,
workspace: AsyncRemoteWorkspace,
working_dir: str,
):
"""Set up git hooks if .openhands/pre-commit.sh exists in the workspace or repository."""
command = 'mkdir -p .git/hooks && chmod +x .openhands/pre-commit.sh'
result = await workspace.execute_command(command, working_dir)
result = await workspace.execute_command(command, workspace.working_dir)
if result.exit_code:
return
@@ -131,7 +131,9 @@ class GitAppConversationService(AppConversationService, ABC):
f'mv {PRE_COMMIT_HOOK} {PRE_COMMIT_LOCAL} &&'
f'chmod +x {PRE_COMMIT_LOCAL}'
)
result = await workspace.execute_command(command, working_dir)
result = await workspace.execute_command(
command, workspace.working_dir
)
if result.exit_code != 0:
_logger.error(
f'Failed to preserve existing pre-commit hook: {result.stderr}',

View File

@@ -181,11 +181,11 @@ class LiveStatusAppConversationService(GitAppConversationService):
# Run setup scripts
workspace = AsyncRemoteWorkspace(
host=agent_server_url, api_key=sandbox.session_api_key
host=agent_server_url,
api_key=sandbox.session_api_key,
working_dir=sandbox_spec.working_dir,
)
async for updated_task in self.run_setup_scripts(
task, workspace, sandbox_spec.working_dir
):
async for updated_task in self.run_setup_scripts(task, workspace):
yield updated_task
# Build the start request

View File

@@ -40,10 +40,10 @@ def get_default_sandbox_specs():
'OPENVSCODE_SERVER_ROOT': '/openhands/.openvscode-server',
'OH_ENABLE_VNC': '0',
'LOG_JSON': 'true',
'OH_CONVERSATIONS_PATH': '/home/openhands/conversations',
'OH_BASH_EVENTS_DIR': '/home/openhands/bash_events',
'OH_CONVERSATIONS_PATH': '/workspace/conversations',
'OH_BASH_EVENTS_DIR': '/workspace/bash_events',
},
working_dir='/home/openhands/workspace',
working_dir='/workspace/project',
)
]

View File

@@ -11,7 +11,7 @@ from openhands.sdk.utils.models import DiscriminatedUnionMixin
# The version of the agent server to use for deployments.
# Typically this will be the same as the values from the pyproject.toml
AGENT_SERVER_IMAGE = 'ghcr.io/openhands/agent-server:2381484-python'
AGENT_SERVER_IMAGE = 'ghcr.io/openhands/agent-server:ce0a71a-python'
class SandboxSpecService(ABC):

View File

@@ -21,7 +21,7 @@ class EncryptionKey(BaseModel):
@field_serializer('key')
def serialize_key(self, key: SecretStr, info: Any):
"""Conditionally serialize the key based on context."""
if info.context and info.context.get('reveal_secrets'):
if info.context and info.context.get('expose_secrets'):
return key.get_secret_value()
return str(key) # Returns '**********' by default

25
poetry.lock generated
View File

@@ -1,4 +1,4 @@
# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand.
# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand.
[[package]]
name = "aiofiles"
@@ -5711,11 +5711,8 @@ files = [
{file = "lxml-5.4.0-cp36-cp36m-win_amd64.whl", hash = "sha256:7ce1a171ec325192c6a636b64c94418e71a1964f56d002cc28122fceff0b6121"},
{file = "lxml-5.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:795f61bcaf8770e1b37eec24edf9771b307df3af74d1d6f27d812e15a9ff3872"},
{file = "lxml-5.4.0-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:29f451a4b614a7b5b6c2e043d7b64a15bd8304d7e767055e8ab68387a8cacf4e"},
{file = "lxml-5.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:891f7f991a68d20c75cb13c5c9142b2a3f9eb161f1f12a9489c82172d1f133c0"},
{file = "lxml-5.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4aa412a82e460571fad592d0f93ce9935a20090029ba08eca05c614f99b0cc92"},
{file = "lxml-5.4.0-cp37-cp37m-manylinux_2_28_aarch64.whl", hash = "sha256:ac7ba71f9561cd7d7b55e1ea5511543c0282e2b6450f122672a2694621d63b7e"},
{file = "lxml-5.4.0-cp37-cp37m-manylinux_2_28_x86_64.whl", hash = "sha256:c5d32f5284012deaccd37da1e2cd42f081feaa76981f0eaa474351b68df813c5"},
{file = "lxml-5.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:ce31158630a6ac85bddd6b830cffd46085ff90498b397bd0a259f59d27a12188"},
{file = "lxml-5.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:31e63621e073e04697c1b2d23fcb89991790eef370ec37ce4d5d469f40924ed6"},
{file = "lxml-5.4.0-cp37-cp37m-win32.whl", hash = "sha256:be2ba4c3c5b7900246a8f866580700ef0d538f2ca32535e991027bdaba944063"},
{file = "lxml-5.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:09846782b1ef650b321484ad429217f5154da4d6e786636c38e434fa32e94e49"},
@@ -7275,7 +7272,7 @@ llama = ["llama-index (>=0.12.29,<0.13.0)", "llama-index-core (>=0.12.29,<0.13.0
[[package]]
name = "openhands-agent-server"
version = "1.0.0a3"
version = "1.0.0a4"
description = "OpenHands Agent Server - REST/WebSocket interface for OpenHands AI Agent"
optional = false
python-versions = ">=3.12"
@@ -7297,13 +7294,13 @@ wsproto = ">=1.2.0"
[package.source]
type = "git"
url = "https://github.com/OpenHands/agent-sdk.git"
reference = "93b481c50fab2bb45e6065606219155119d35656"
resolved_reference = "93b481c50fab2bb45e6065606219155119d35656"
reference = "ce0a71af55dfce101f7419fbdb0116178f01e109"
resolved_reference = "ce0a71af55dfce101f7419fbdb0116178f01e109"
subdirectory = "openhands-agent-server"
[[package]]
name = "openhands-sdk"
version = "1.0.0a3"
version = "1.0.0a4"
description = "OpenHands SDK - Core functionality for building AI agents"
optional = false
python-versions = ">=3.12"
@@ -7327,13 +7324,13 @@ boto3 = ["boto3 (>=1.35.0)"]
[package.source]
type = "git"
url = "https://github.com/OpenHands/agent-sdk.git"
reference = "93b481c50fab2bb45e6065606219155119d35656"
resolved_reference = "93b481c50fab2bb45e6065606219155119d35656"
reference = "ce0a71af55dfce101f7419fbdb0116178f01e109"
resolved_reference = "ce0a71af55dfce101f7419fbdb0116178f01e109"
subdirectory = "openhands-sdk"
[[package]]
name = "openhands-tools"
version = "1.0.0a3"
version = "1.0.0a4"
description = "OpenHands Tools - Runtime tools for AI agents"
optional = false
python-versions = ">=3.12"
@@ -7354,8 +7351,8 @@ pydantic = ">=2.11.7"
[package.source]
type = "git"
url = "https://github.com/OpenHands/agent-sdk.git"
reference = "93b481c50fab2bb45e6065606219155119d35656"
resolved_reference = "93b481c50fab2bb45e6065606219155119d35656"
reference = "ce0a71af55dfce101f7419fbdb0116178f01e109"
resolved_reference = "ce0a71af55dfce101f7419fbdb0116178f01e109"
subdirectory = "openhands-tools"
[[package]]
@@ -16524,4 +16521,4 @@ third-party-runtimes = ["daytona", "e2b-code-interpreter", "modal", "runloop-api
[metadata]
lock-version = "2.1"
python-versions = "^3.12,<3.14"
content-hash = "b8620f03973119b97edf2ce1d44e4d8706cb2ecf155710bc8e2094daa766d139"
content-hash = "aed9fa5020f1fdda19cf8191ac75021f2617e10e49757bcec23586b2392fd596"

View File

@@ -113,9 +113,9 @@ e2b-code-interpreter = { version = "^2.0.0", optional = true }
pybase62 = "^1.0.0"
# V1 dependencies
openhands-agent-server = { git = "https://github.com/OpenHands/agent-sdk.git", subdirectory = "openhands-agent-server", rev = "93b481c50fab2bb45e6065606219155119d35656" }
openhands-sdk = { git = "https://github.com/OpenHands/agent-sdk.git", subdirectory = "openhands-sdk", rev = "93b481c50fab2bb45e6065606219155119d35656" }
openhands-tools = { git = "https://github.com/OpenHands/agent-sdk.git", subdirectory = "openhands-tools", rev = "93b481c50fab2bb45e6065606219155119d35656" }
openhands-agent-server = { git = "https://github.com/OpenHands/agent-sdk.git", subdirectory = "openhands-agent-server", rev = "ce0a71af55dfce101f7419fbdb0116178f01e109" }
openhands-sdk = { git = "https://github.com/OpenHands/agent-sdk.git", subdirectory = "openhands-sdk", rev = "ce0a71af55dfce101f7419fbdb0116178f01e109" }
openhands-tools = { git = "https://github.com/OpenHands/agent-sdk.git", subdirectory = "openhands-tools", rev = "ce0a71af55dfce101f7419fbdb0116178f01e109" }
python-jose = { version = ">=3.3", extras = [ "cryptography" ] }
sqlalchemy = { extras = [ "asyncio" ], version = "^2.0.40" }
pg8000 = "^1.31.5"

View File

@@ -365,7 +365,7 @@ class TestDockerSandboxSpecServiceInjector:
assert 'OPENVSCODE_SERVER_ROOT' in specs[0].initial_env
assert 'OH_ENABLE_VNC' in specs[0].initial_env
assert 'LOG_JSON' in specs[0].initial_env
assert specs[0].working_dir == '/home/openhands/workspace'
assert specs[0].working_dir == '/workspace/project'
@patch(
'openhands.app_server.sandbox.docker_sandbox_spec_service._global_docker_client',