chore: clean up sandbox and ssh related configs (#3301)

* clean up sandbox and ssh related stuff

* remove ssh hostname

* remove ssh hostname

* remove ssh password

* update config

* fix typo that breaks the test
This commit is contained in:
Xingyao Wang 2024-08-09 06:15:40 +08:00 committed by GitHub
parent 040b9cb75c
commit a5195b0e65
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 6 additions and 114 deletions

View File

@ -53,7 +53,6 @@ jobs:
env:
LLM_API_KEY: ${{ secrets.LLM_API_KEY }}
LLM_MODEL: ${{ vars.LLM_MODEL }}
SANDBOX_BOX_TYPE: ssh
run: |
# Append path to launch poetry
export PATH="/github/home/.local/bin:$PATH"

View File

@ -45,7 +45,6 @@ jobs:
ISSUE_BODY: ${{ github.event.issue.body }}
LLM_API_KEY: ${{ secrets.OPENAI_API_KEY }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
SANDBOX_BOX_TYPE: ssh
run: |
# Append path to launch poetry
export PATH="/github/home/.local/bin:$PATH"

View File

@ -3,7 +3,7 @@
CommitWriterAgent can help write git commit message. Example:
```bash
WORKSPACE_MOUNT_PATH="`PWD`" SANDBOX_BOX_TYPE="ssh" \
WORKSPACE_MOUNT_PATH="`PWD`" \
poetry run python opendevin/core/main.py -t "dummy task" -c CommitWriterAgent -d ./
```

View File

@ -55,22 +55,11 @@ workspace_base = "./workspace"
# Path to rewrite the workspace mount path to
#workspace_mount_rewrite = ""
# Run as devin
#run_as_devin = true
# Runtime environment
#runtime = "server"
# SSH hostname for the sandbox
#ssh_hostname = "localhost"
# SSH password for the sandbox
#ssh_password = ""
# SSH port for the sandbox
#ssh_port = 63710
#runtime = "eventstream"
# Name of the default agent
#default_agent = "CodeActAgent"
@ -181,9 +170,6 @@ llm_config = 'gpt3'
# Sandbox timeout in seconds
#timeout = 120
# Sandbox type (ssh, e2b, local)
#box_type = "ssh"
# Sandbox user ID
#user_id = 1000

View File

@ -38,7 +38,6 @@ ENV RUN_AS_DEVIN=true
# A random number--we need this to be different from the user's UID on the host machine
ENV OPENDEVIN_USER_ID=42420
ENV USE_HOST_NETWORK=false
ENV SSH_HOSTNAME=host.docker.internal
ENV WORKSPACE_BASE=/opt/workspace_base
ENV OPEN_DEVIN_BUILD_VERSION=$OPEN_DEVIN_BUILD_VERSION
RUN mkdir -p $WORKSPACE_BASE

View File

@ -72,8 +72,6 @@ WORKSPACE_BASE=$(pwd)/workspace
docker run -it \
--pull=always \
-e SANDBOX_USER_ID=$(id -u) \
-e PERSIST_SANDBOX="true" \
-e SSH_PASSWORD="make something up here" \
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
-v $WORKSPACE_BASE:/opt/workspace_base \
-v /var/run/docker.sock:/var/run/docker.sock \

View File

@ -72,8 +72,6 @@ WORKSPACE_BASE=$(pwd)/workspace
docker run -it \
--pull=always \
-e SANDBOX_USER_ID=$(id -u) \
-e PERSIST_SANDBOX="true" \
-e SSH_PASSWORD="make something up here" \
-e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \
-v $WORKSPACE_BASE:/opt/workspace_base \
-v /var/run/docker.sock:/var/run/docker.sock \

View File

@ -158,8 +158,6 @@ spec:
env:
- name: SANDBOX_USER_ID
value: "1000"
- name: SANDBOX_BOX_TYPE
value: 'local'
- name: WORKSPACE_MOUNT_PATH
value: "/opt/workspace_base"
volumeMounts:

View File

@ -145,7 +145,6 @@ class SandboxConfig(metaclass=Singleton):
"""Configuration for the sandbox.
Attributes:
box_type: The type of sandbox to use. Options are: ssh, e2b, local.
container_image: The container image to use for the sandbox.
user_id: The user ID for the sandbox.
timeout: The timeout for the sandbox.
@ -165,7 +164,6 @@ class SandboxConfig(metaclass=Singleton):
Default is None for general purpose browsing. Check evaluation/miniwob and evaluation/webarena for examples.
"""
box_type: str = 'ssh'
container_image: str = (
'ubuntu:22.04' # default to ubuntu:22.04 for eventstream runtime
)
@ -226,7 +224,6 @@ class AppConfig(metaclass=Singleton):
max_iterations: The maximum number of iterations.
max_budget_per_task: The maximum budget allowed per task, beyond which the agent will stop.
e2b_api_key: The E2B API key.
ssh_hostname: The SSH hostname.
disable_color: Whether to disable color. For terminals that don't support color.
debug: Whether to enable debugging.
enable_cli_session: Whether to enable saving and restoring the session when run from CLI.
@ -255,10 +252,7 @@ class AppConfig(metaclass=Singleton):
max_iterations: int = _MAX_ITERATIONS
max_budget_per_task: float | None = None
e2b_api_key: str = ''
ssh_hostname: str = 'localhost'
disable_color: bool = False
ssh_port: int = 63710
ssh_password: str | None = None
jwt_secret: str = uuid.uuid4().hex
debug: bool = False
enable_cli_session: bool = False
@ -330,7 +324,6 @@ class AppConfig(metaclass=Singleton):
'e2b_api_key',
'github_token',
'jwt_secret',
'ssh_password',
]:
attr_value = '******' if attr_value else None
@ -426,11 +419,6 @@ def load_from_env(cfg: AppConfig, env_or_toml_dict: dict | MutableMapping[str, s
f'Error setting env var {env_var_name}={value}: check that the value is of the right type'
)
if 'SANDBOX_TYPE' in env_or_toml_dict:
logger.opendevin_logger.error(
'SANDBOX_TYPE is deprecated. Please use SANDBOX_BOX_TYPE instead.'
)
env_or_toml_dict['SANDBOX_BOX_TYPE'] = env_or_toml_dict.pop('SANDBOX_TYPE')
# Start processing from the root of the config object
set_attr_from_env(cfg)
@ -520,8 +508,6 @@ def load_from_toml(cfg: AppConfig, toml_file: str = 'config.toml'):
keys_to_migrate = [key for key in core_config if key.startswith('sandbox_')]
for key in keys_to_migrate:
new_key = key.replace('sandbox_', '')
if new_key == 'type':
new_key = 'box_type'
if new_key in sandbox_config.__annotations__:
# read the key in sandbox and remove it from core
setattr(sandbox_config, new_key, core_config.pop(key))
@ -548,10 +534,6 @@ def finalize_config(cfg: AppConfig):
cfg.workspace_mount_path = os.path.abspath(cfg.workspace_base)
cfg.workspace_base = os.path.abspath(cfg.workspace_base)
# In local there is no sandbox, the workspace will have the same pwd as the host
if cfg.sandbox.box_type == 'local' and cfg.workspace_mount_path is not None:
cfg.workspace_mount_path_in_sandbox = cfg.workspace_mount_path
if cfg.workspace_mount_rewrite: # and not config.workspace_mount_path:
# TODO why do we need to check if workspace_mount_path is None?
base = cfg.workspace_base or os.getcwd()

View File

@ -87,7 +87,6 @@ class SensitiveDataFilter(logging.Filter):
'e2b_api_key',
'github_token',
'jwt_secret',
'ssh_password',
]
# add env var names

View File

@ -36,11 +36,9 @@ class ConfigType(str, Enum):
MAX_ITERATIONS = 'MAX_ITERATIONS'
AGENT = 'AGENT'
E2B_API_KEY = 'E2B_API_KEY'
SANDBOX_BOX_TYPE = 'SANDBOX_BOX_TYPE'
SANDBOX_USER_ID = 'SANDBOX_USER_ID'
SANDBOX_TIMEOUT = 'SANDBOX_TIMEOUT'
USE_HOST_NETWORK = 'USE_HOST_NETWORK'
SSH_HOSTNAME = 'SSH_HOSTNAME'
DISABLE_COLOR = 'DISABLE_COLOR'
DEBUG = 'DEBUG'
FILE_UPLOADS_MAX_FILE_SIZE_MB = 'FILE_UPLOADS_MAX_FILE_SIZE_MB'

View File

@ -56,7 +56,6 @@ cd "$PROJECT_ROOT" || exit 1
mkdir -p $WORKSPACE_BASE
# use environmental variable if exists, otherwise use "ssh"
SANDBOX_BOX_TYPE="${SANDBOX_TYPE:-ssh}"
TEST_RUNTIME="${TEST_RUNTIME:-eventstream}" # can be server or eventstream
# TODO: set this as default after ServerRuntime is deprecated
if [ "$TEST_RUNTIME" == "eventstream" ] && [ -z "$SANDBOX_CONTAINER_IMAGE" ]; then
@ -64,7 +63,6 @@ if [ "$TEST_RUNTIME" == "eventstream" ] && [ -z "$SANDBOX_CONTAINER_IMAGE" ]; th
fi
MAX_ITERATIONS=15
echo "SANDBOX_BOX_TYPE: $SANDBOX_BOX_TYPE"
echo "TEST_RUNTIME: $TEST_RUNTIME"
agents=(
@ -112,7 +110,6 @@ run_test() {
env SCRIPT_DIR="$SCRIPT_DIR" \
PROJECT_ROOT="$PROJECT_ROOT" \
SANDBOX_BOX_TYPE="$SANDBOX_BOX_TYPE" \
WORKSPACE_BASE=$WORKSPACE_BASE \
WORKSPACE_MOUNT_PATH=$WORKSPACE_MOUNT_PATH \
MAX_ITERATIONS=$MAX_ITERATIONS \
@ -183,7 +180,6 @@ regenerate_without_llm() {
set -x
env SCRIPT_DIR="$SCRIPT_DIR" \
PROJECT_ROOT="$PROJECT_ROOT" \
SANDBOX_BOX_TYPE="$SANDBOX_BOX_TYPE" \
WORKSPACE_BASE=$WORKSPACE_BASE \
WORKSPACE_MOUNT_PATH=$WORKSPACE_MOUNT_PATH \
MAX_ITERATIONS=$MAX_ITERATIONS \
@ -213,7 +209,6 @@ regenerate_with_llm() {
env SCRIPT_DIR="$SCRIPT_DIR" \
PROJECT_ROOT="$PROJECT_ROOT" \
DEBUG=true \
SANDBOX_BOX_TYPE="$SANDBOX_BOX_TYPE" \
WORKSPACE_BASE=$WORKSPACE_BASE \
WORKSPACE_MOUNT_PATH=$WORKSPACE_MOUNT_PATH \
DEFAULT_AGENT=$agent \

View File

@ -29,7 +29,6 @@ CONFIG = AppConfig(
workspace_base=os.getenv('WORKSPACE_BASE'),
workspace_mount_path=os.getenv('WORKSPACE_MOUNT_PATH'),
sandbox=SandboxConfig(
box_type=os.getenv('SANDBOX_BOX_TYPE', 'ssh'),
use_host_network=True,
),
)
@ -80,8 +79,7 @@ def validate_final_state(final_state: State | None, test_name: str):
(
os.getenv('DEFAULT_AGENT') == 'CodeActAgent'
or os.getenv('DEFAULT_AGENT') == 'CodeActSWEAgent'
)
and os.getenv('SANDBOX_BOX_TYPE', '').lower() != 'ssh',
),
reason='CodeActAgent/CodeActSWEAgent only supports ssh sandbox which is stateful',
)
@pytest.mark.skipif(
@ -118,18 +116,13 @@ def test_write_simple_script(current_test_name: str) -> None:
(
os.getenv('DEFAULT_AGENT') == 'CodeActAgent'
or os.getenv('DEFAULT_AGENT') == 'CodeActSWEAgent'
)
and os.getenv('SANDBOX_BOX_TYPE', '').lower() != 'ssh',
),
reason='CodeActAgent/CodeActSWEAgent only supports ssh sandbox which is stateful',
)
@pytest.mark.skipif(
os.getenv('DEFAULT_AGENT') == 'PlannerAgent',
reason='We only keep basic tests for PlannerAgent',
)
@pytest.mark.skipif(
os.getenv('SANDBOX_BOX_TYPE') == 'local',
reason='local sandbox shows environment-dependent absolute path for pwd command',
)
def test_edits(current_test_name: str):
# Copy workspace artifacts to workspace_base location
source_dir = os.path.join(os.path.dirname(__file__), 'workspace/test_edits/')
@ -163,10 +156,6 @@ Enjoy!
and os.getenv('DEFAULT_AGENT') != 'CodeActSWEAgent',
reason='currently only CodeActAgent and CodeActSWEAgent have IPython (Jupyter) execution by default',
)
@pytest.mark.skipif(
os.getenv('SANDBOX_BOX_TYPE') != 'ssh',
reason='Currently, only ssh sandbox supports stateful tasks',
)
def test_ipython(current_test_name: str):
# Execute the task
task = "Use Jupyter IPython to write a text file containing 'hello world' to '/workspace/test.txt'. Do not ask me for confirmation at any point."
@ -191,10 +180,6 @@ def test_ipython(current_test_name: str):
os.getenv('DEFAULT_AGENT') != 'ManagerAgent',
reason='Currently, only ManagerAgent supports task rejection',
)
@pytest.mark.skipif(
os.getenv('SANDBOX_BOX_TYPE') == 'local',
reason='FIXME: local sandbox does not capture stderr',
)
def test_simple_task_rejection(current_test_name: str):
# Give an impossible task to do: cannot write a commit message because
# the workspace is not a git repo
@ -211,10 +196,6 @@ def test_simple_task_rejection(current_test_name: str):
and os.getenv('DEFAULT_AGENT') != 'CodeActSWEAgent',
reason='currently only CodeActAgent and CodeActSWEAgent have IPython (Jupyter) execution by default',
)
@pytest.mark.skipif(
os.getenv('SANDBOX_BOX_TYPE') != 'ssh',
reason='Currently, only ssh sandbox supports stateful tasks',
)
def test_ipython_module(current_test_name: str):
# Execute the task
task = "Install and import pymsgbox==1.0.9 and print it's version in /workspace/test.txt. Do not ask me for confirmation at any point."
@ -245,8 +226,7 @@ def test_ipython_module(current_test_name: str):
(
os.getenv('DEFAULT_AGENT') == 'CodeActAgent'
or os.getenv('DEFAULT_AGENT') == 'CodeActSWEAgent'
)
and os.getenv('SANDBOX_BOX_TYPE', '').lower() != 'ssh',
),
reason='CodeActAgent/CodeActSWEAgent only supports ssh sandbox which is stateful',
)
def test_browse_internet(http_server, current_test_name: str):

View File

@ -52,7 +52,6 @@ def test_compat_env_to_config(monkeypatch, setup_env):
monkeypatch.setenv('AGENT_MEMORY_MAX_THREADS', '4')
monkeypatch.setenv('AGENT_MEMORY_ENABLED', 'True')
monkeypatch.setenv('DEFAULT_AGENT', 'CodeActAgent')
monkeypatch.setenv('SANDBOX_TYPE', 'local')
monkeypatch.setenv('SANDBOX_TIMEOUT', '10')
config = AppConfig()
@ -67,7 +66,6 @@ def test_compat_env_to_config(monkeypatch, setup_env):
assert config.get_agent_config().memory_max_threads == 4
assert config.get_agent_config().memory_enabled is True
assert config.default_agent == 'CodeActAgent'
assert config.sandbox.box_type == 'local'
assert config.sandbox.timeout == 10
@ -120,7 +118,6 @@ timeout = 1
[core]
workspace_base = "/opt/files2/workspace"
default_agent = "TestAgent"
sandbox_type = "local"
"""
)
@ -150,12 +147,8 @@ sandbox_type = "local"
assert default_config.get_agent_config('BrowsingAgent').memory_enabled is False
assert default_config.workspace_base == '/opt/files2/workspace'
assert default_config.sandbox.box_type == 'local'
assert default_config.sandbox.timeout == 1
# default config doesn't have a field sandbox_type
assert not hasattr(default_config, 'sandbox_type')
# before finalize_config, workspace_mount_path is UndefinedString.UNDEFINED if it was not set
assert default_config.workspace_mount_path is UndefinedString.UNDEFINED
assert (
@ -170,7 +163,7 @@ sandbox_type = "local"
assert default_config.workspace_mount_path == '/opt/files2/workspace'
def test_compat_load_sandbox_from_toml(default_config, temp_toml_file):
def test_compat_load_sandbox_from_toml(default_config: AppConfig, temp_toml_file: str):
# test loading configuration from a new-style TOML file
# uses a toml file with sandbox_vars instead of a sandbox section
with open(temp_toml_file, 'w', encoding='utf-8') as toml_file:
@ -184,7 +177,6 @@ memory_enabled = true
[core]
workspace_base = "/opt/files2/workspace"
sandbox_type = "local"
sandbox_timeout = 500
sandbox_container_image = "node:14"
sandbox_user_id = 1001
@ -199,7 +191,6 @@ default_agent = "TestAgent"
assert default_config.default_agent == 'TestAgent'
assert default_config.get_agent_config().memory_enabled is True
assert default_config.workspace_base == '/opt/files2/workspace'
assert default_config.sandbox.box_type == 'local'
assert default_config.sandbox.timeout == 500
assert default_config.sandbox.container_image == 'node:14'
assert default_config.sandbox.user_id == 1001
@ -208,7 +199,6 @@ default_agent = "TestAgent"
finalize_config(default_config)
# app config doesn't have fields sandbox_*
assert not hasattr(default_config, 'sandbox_type')
assert not hasattr(default_config, 'sandbox_timeout')
assert not hasattr(default_config, 'sandbox_container_image')
assert not hasattr(default_config, 'sandbox_user_id')
@ -229,7 +219,6 @@ api_key = "toml-api-key"
[core]
workspace_base = "/opt/files3/workspace"
sandbox_type = "local"
disable_color = true
sandbox_timeout = 500
sandbox_user_id = 1001
@ -237,7 +226,6 @@ sandbox_user_id = 1001
monkeypatch.setenv('LLM_API_KEY', 'env-api-key')
monkeypatch.setenv('WORKSPACE_BASE', 'UNDEFINED')
monkeypatch.setenv('SANDBOX_TYPE', 'e2b')
monkeypatch.setenv('SANDBOX_TIMEOUT', '1000')
monkeypatch.setenv('SANDBOX_USER_ID', '1002')
@ -262,7 +250,6 @@ sandbox_user_id = 1001
assert default_config.workspace_mount_path is UndefinedString.UNDEFINED
assert default_config.workspace_mount_path == 'UNDEFINED'
assert default_config.sandbox.box_type == 'e2b'
assert default_config.disable_color is True
assert default_config.sandbox.timeout == 1000
assert default_config.sandbox.user_id == 1002
@ -285,14 +272,12 @@ api_key = "toml-api-key"
workspace_base = "/opt/files3/workspace"
[sandbox]
box_type = "e2b"
timeout = 500
user_id = 1001
""")
monkeypatch.setenv('LLM_API_KEY', 'env-api-key')
monkeypatch.setenv('WORKSPACE_BASE', 'UNDEFINED')
monkeypatch.setenv('SANDBOX_TYPE', 'local')
monkeypatch.setenv('SANDBOX_TIMEOUT', '1000')
monkeypatch.setenv('SANDBOX_USER_ID', '1002')
@ -303,7 +288,6 @@ user_id = 1001
# before load_from_env, values are set to the values from the toml file
assert default_config.get_llm_config().api_key == 'toml-api-key'
assert default_config.sandbox.box_type == 'e2b'
assert default_config.sandbox.timeout == 500
assert default_config.sandbox.user_id == 1001
@ -314,7 +298,6 @@ user_id = 1001
assert default_config.get_llm_config().model == 'test-model'
assert default_config.get_llm_config().api_key == 'env-api-key'
assert default_config.sandbox.box_type == 'local'
assert default_config.sandbox.timeout == 1000
assert default_config.sandbox.user_id == 1002
@ -335,7 +318,6 @@ workspace_base = "/opt/files/workspace"
model = "test-model"
[sandbox]
box_type = "local"
timeout = 1
container_image = "custom_image"
user_id = 1001
@ -347,7 +329,6 @@ user_id = 1001
finalize_config(default_config)
assert default_config.get_llm_config().model == 'test-model'
assert default_config.sandbox.box_type == 'local'
assert default_config.sandbox.timeout == 1
assert default_config.sandbox.container_image == 'custom_image'
assert default_config.sandbox.user_id == 1001
@ -374,7 +355,6 @@ def test_defaults_dict_after_updates(default_config):
defaults_after_updates['workspace_mount_path']['default']
is UndefinedString.UNDEFINED
)
assert defaults_after_updates['sandbox']['box_type']['default'] == 'ssh'
assert defaults_after_updates['sandbox']['timeout']['default'] == 120
assert (
defaults_after_updates['sandbox']['container_image']['default']
@ -393,7 +373,6 @@ def test_invalid_toml_format(monkeypatch, temp_toml_file, default_config):
load_from_toml(default_config)
load_from_env(default_config, os.environ)
default_config.ssh_password = None # prevent leak
default_config.jwt_secret = None # prevent leak
for llm in default_config.llms.values():
llm.api_key = None # prevent leak
@ -405,13 +384,8 @@ def test_invalid_toml_format(monkeypatch, temp_toml_file, default_config):
def test_finalize_config(default_config):
# Test finalize config
assert default_config.workspace_mount_path is UndefinedString.UNDEFINED
default_config.sandbox.box_type = 'local'
finalize_config(default_config)
assert (
default_config.workspace_mount_path_in_sandbox
== default_config.workspace_mount_path
)
assert default_config.workspace_mount_path == os.path.abspath(
default_config.workspace_base
)
@ -426,16 +400,6 @@ def test_workspace_mount_path_default(default_config):
)
def test_workspace_mount_path_in_sandbox_local(default_config):
assert default_config.workspace_mount_path_in_sandbox == '/workspace'
default_config.sandbox.box_type = 'local'
finalize_config(default_config)
assert (
default_config.workspace_mount_path_in_sandbox
== default_config.workspace_mount_path
)
def test_workspace_mount_rewrite(default_config, monkeypatch):
default_config.workspace_base = '/home/user/project'
default_config.workspace_mount_rewrite = '/home/user:/sandbox'
@ -512,14 +476,11 @@ def test_api_keys_repr_str():
agents={'agent': agent_config},
e2b_api_key='my_e2b_api_key',
jwt_secret='my_jwt_secret',
ssh_password='my_ssh_password',
)
assert "e2b_api_key='******'" in repr(app_config)
assert "e2b_api_key='******'" in str(app_config)
assert "jwt_secret='******'" in repr(app_config)
assert "jwt_secret='******'" in str(app_config)
assert "ssh_password='******'" in repr(app_config)
assert "ssh_password='******'" in str(app_config)
# Check that no other attrs in AppConfig have 'key' or 'token' in their name
# This will fail when new attrs are added, and attract attention