Skip to content
Merged
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
27 changes: 10 additions & 17 deletions core/harness/agents/external_backend.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,6 @@

import asyncio
import json
import os
import re
import shutil
import tempfile
from pathlib import Path
Expand All @@ -44,7 +42,15 @@
# ``PATH``, ``HOME``, locale, and proxy variables survive, so the CLI runs
# normally and reads its own credential store; a deliberately forwarded
# secret goes through the config env layer, which merges after the scrub.
SENSITIVE_ENV_PATTERN = re.compile(r"KEY|PASSWORD|SECRET|TOKEN", re.IGNORECASE)
#
# The implementation moved to :mod:`core.harness.env_sanitize` so the shell,
# hook, code-mode, and terminal call sites share one pattern instead of
# growing their own. Both names stay importable from here for callers (and
# tests) that already reference this module.
from core.harness.env_sanitize import (
SENSITIVE_ENV_PATTERN,
scrubbed_parent_env,
)

# Wall-clock budget for one external run, unless config overrides it. Long
# enough for a real subtask; short enough that a hung CLI frees its slot.
Expand Down Expand Up @@ -206,20 +212,6 @@ def backend_settings(name: str) -> dict[str, Any]:
return block if isinstance(block, dict) else {}


def scrubbed_parent_env(
extra_env: dict[str, str] | None = None,
) -> dict[str, str]:
"""The ambient environment minus credential-shaped names."""
env = {
key: value
for key, value in os.environ.items()
if not SENSITIVE_ENV_PATTERN.search(key)
}
if extra_env:
env.update(extra_env)
return env


async def run_external_subagent(
backend_name: str,
task: str,
Expand Down Expand Up @@ -293,6 +285,7 @@ def _stderr_tail(stderr: bytes | None) -> str:

__all__ = [
"BACKENDS",
"SENSITIVE_ENV_PATTERN",
"ExternalBackendError",
"backend_settings",
"resolve_backend",
Expand Down
6 changes: 5 additions & 1 deletion core/harness/code_mode/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
terminate_process_tree,
)
from core.agent_runtime.tools.base import Tool, tool_parameters
from core.harness.env_sanitize import scrubbed_parent_env
from core.harness.sandbox import build_exec_command

_RUNNER = str(Path(__file__).with_name("_runner.py"))
Expand Down Expand Up @@ -169,7 +170,10 @@ async def _run(self, argv: list[str], init: dict) -> str:
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
cwd=self._workspace,
env={**os.environ},
# The code-mode runtime executes model-authored Python, which
# can read the environment. Hand it a cred- scrubbed one so a
# stray os.environ dump cannot become tool output.
env=dict(scrubbed_parent_env()),
limit=_STREAM_LIMIT,
**subprocess_group_kwargs(),
)
Expand Down
Loading
Loading