Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 23 additions & 8 deletions src/agents/sandbox/entries/mounts/patterns.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,22 @@ async def _write_sensitive_config_file(
)


def _join_mountpoint_command(
cmd: list[str],
env_vars: list[tuple[str, str]],
*,
redact: bool = False,
) -> str:
joined_cmd = " ".join(shlex.quote(part) for part in cmd)
if not env_vars:
return joined_cmd

env_parts = " ".join(
f"{name}={shlex.quote('REDACTED' if redact else value)}" for name, value in env_vars
)
return f"{env_parts} {joined_cmd}"


class MountPatternBase(BaseModel, abc.ABC):
@abc.abstractmethod
async def apply(
Expand Down Expand Up @@ -425,24 +441,23 @@ async def apply(
cmd.extend(["--prefix", mountpoint_config.prefix])
cmd.extend([bucket, sandbox_path_str(path)])

env_parts: list[str] = []
env_vars: list[tuple[str, str]] = []
access_key_id = mountpoint_config.access_key_id
secret_access_key = mountpoint_config.secret_access_key
session_token = mountpoint_config.session_token
if access_key_id and secret_access_key:
env_parts.append(f"AWS_ACCESS_KEY_ID={shlex.quote(access_key_id)}")
env_parts.append(f"AWS_SECRET_ACCESS_KEY={shlex.quote(secret_access_key)}")
env_vars.append(("AWS_ACCESS_KEY_ID", access_key_id))
env_vars.append(("AWS_SECRET_ACCESS_KEY", secret_access_key))
if session_token:
env_parts.append(f"AWS_SESSION_TOKEN={shlex.quote(session_token)}")
env_vars.append(("AWS_SESSION_TOKEN", session_token))

joined_cmd = " ".join(shlex.quote(part) for part in cmd)
if env_parts:
joined_cmd = f"{' '.join(env_parts)} {joined_cmd}"
joined_cmd = _join_mountpoint_command(cmd, env_vars)
display_cmd = _join_mountpoint_command(cmd, env_vars, redact=True)

result = await session.exec("sh", "-lc", joined_cmd, shell=False)
if not result.ok():
raise MountCommandError(
command=joined_cmd,
command=display_cmd,
stderr=result.stderr.decode("utf-8", errors="replace"),
context={"bucket": bucket},
)
Expand Down
25 changes: 25 additions & 0 deletions tests/sandbox/test_mount_patterns.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from agents.sandbox.entries.mounts.patterns import _join_mountpoint_command


def test_join_mountpoint_command_redacts_aws_credentials_for_display() -> None:
env_vars = [
("AWS_ACCESS_KEY_ID", "AKIAEXAMPLE"),
("AWS_SECRET_ACCESS_KEY", "super-secret"),
("AWS_SESSION_TOKEN", "session-token"),
]

real_command = _join_mountpoint_command(
["mount-s3", "bucket-name", "/workspace/mnt"], env_vars
)
display_command = _join_mountpoint_command(
["mount-s3", "bucket-name", "/workspace/mnt"], env_vars, redact=True
)

assert "super-secret" in real_command
assert "session-token" in real_command
assert "AKIAEXAMPLE" in real_command
assert "super-secret" not in display_command
assert "session-token" not in display_command
assert "AKIAEXAMPLE" not in display_command
assert display_command.count("REDACTED") == 3
assert "mount-s3 bucket-name /workspace/mnt" in display_command
Loading