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
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

# AgentVeil

[![PyPI](https://img.shields.io/badge/PyPI-0.7.27-blue)](https://pypi.org/project/agentveil-mcp-proxy/0.7.27/)
[![PyPI](https://img.shields.io/badge/PyPI-0.7.28-blue)](https://pypi.org/project/agentveil-mcp-proxy/0.7.28/)
[![Python](https://img.shields.io/pypi/pyversions/agentveil-mcp-proxy)](https://pypi.org/project/agentveil-mcp-proxy/)
[![Tests](https://github.com/agentveil-protocol/agentveil-sdk/actions/workflows/tests.yml/badge.svg)](https://github.com/agentveil-protocol/agentveil-sdk/actions)
[![SDK License: MIT](https://img.shields.io/badge/SDK-MIT-informational)](LICENSING.md)
Expand Down
22 changes: 5 additions & 17 deletions packages/agentveil-mcp-proxy/agentveil_mcp_proxy/agent_launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -623,24 +623,12 @@ def _proxy_cli_argv(proxy_command: str, subcommand: list[str]) -> list[str]:
return [proxy_command, *subcommand]


def _proxy_cli_child_env() -> dict[str, str]:
def _proxy_cli_child_env(*, passphrase_file: Path | None = None) -> dict[str, str]:
"""Return an env that lets child interpreters import this package reliably."""

env = dict(os.environ)
package_root_path = Path(__file__).resolve().parents[1]
source_roots = [str(package_root_path)]
repo_root = package_root_path.parents[1]
if (repo_root / "agentveil").is_dir():
source_roots.append(str(repo_root))
existing = env.get("PYTHONPATH")
if existing:
paths = existing.split(os.pathsep)
prefix = [path for path in source_roots if path not in paths]
if prefix:
env["PYTHONPATH"] = os.pathsep.join([*prefix, existing])
else:
env["PYTHONPATH"] = os.pathsep.join(source_roots)
return env
from agentveil_mcp_proxy.approval.server import _proxy_cli_child_env as _center_child_env

return _center_child_env(passphrase_file=passphrase_file)


def _proxy_command_display(proxy_command: str) -> str:
Expand Down Expand Up @@ -738,7 +726,7 @@ def _spawn_approval_center(
"stdout": log_handle,
"stderr": log_handle,
"close_fds": True,
"env": _proxy_cli_child_env(),
"env": _proxy_cli_child_env(passphrase_file=passphrase_file),
}
if os.name == "posix":
kwargs["start_new_session"] = True
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1612,21 +1612,85 @@ def _proxy_cli_argv(proxy_command: str, subcommand: list[str]) -> list[str]:
return [proxy_command, *subcommand]


def _proxy_cli_child_env() -> dict[str, str]:
env = dict(os.environ)
_MANAGED_CENTER_ENV_KEYS = (
"PATH",
"USER",
"LOGNAME",
"SHELL",
"HOME",
"LANG",
"LC_ALL",
"LC_CTYPE",
"LC_MESSAGES",
"LC_NUMERIC",
"LC_TIME",
"TMPDIR",
"TEMP",
"TMP",
"TZ",
"TERM",
"SYSTEMROOT",
"WINDIR",
"COMSPEC",
"PATHEXT",
"PYTHONHOME",
"VIRTUAL_ENV",
)

_BLOCKED_MANAGED_CENTER_ENV_KEYS = frozenset({
"OPENAI_API_KEY",
"DEEPSEEK_API_KEY",
"AWS_SECRET_ACCESS_KEY",
})

_BLOCKED_MANAGED_CENTER_ENV_SUFFIXES = ("_TOKEN", "_SECRET", "_PASSWORD")


def _managed_center_env_key_is_blocked(key: str) -> bool:
upper = key.upper()
if upper in _BLOCKED_MANAGED_CENTER_ENV_KEYS:
return True
return any(upper.endswith(suffix) for suffix in _BLOCKED_MANAGED_CENTER_ENV_SUFFIXES)


def _managed_center_pythonpath(*, parent_env: Mapping[str, str]) -> str:
package_root_path = Path(__file__).resolve().parents[2]
source_roots = [str(package_root_path)]
repo_root = package_root_path.parents[1]
if (repo_root / "agentveil").is_dir():
source_roots.append(str(repo_root))
existing = env.get("PYTHONPATH")
existing = parent_env.get("PYTHONPATH")
if existing:
paths = existing.split(os.pathsep)
prefix = [path for path in source_roots if path not in paths]
if prefix:
env["PYTHONPATH"] = os.pathsep.join([*prefix, existing])
else:
env["PYTHONPATH"] = os.pathsep.join(source_roots)
return os.pathsep.join([*prefix, existing])
return existing
return os.pathsep.join(source_roots)


def _proxy_cli_child_env(
*,
passphrase_file: Path | None = None,
parent_env: Mapping[str, str] | None = None,
) -> dict[str, str]:
"""Return a bounded env for managed Approval Center child processes."""

from agentveil_mcp_proxy.identity import PASSPHRASE_ENV

source = dict(os.environ if parent_env is None else parent_env)
env: dict[str, str] = {}
for key in _MANAGED_CENTER_ENV_KEYS:
if _managed_center_env_key_is_blocked(key):
continue
value = source.get(key)
if isinstance(value, str) and value:
env[key] = value
env["PYTHONPATH"] = _managed_center_pythonpath(parent_env=source)
if passphrase_file is None:
passphrase = source.get(PASSPHRASE_ENV)
if isinstance(passphrase, str) and passphrase:
env[PASSPHRASE_ENV] = passphrase
return env


Expand Down Expand Up @@ -1957,7 +2021,7 @@ def spawn_managed_approval_center_process(
"stdout": log_handle,
"stderr": log_handle,
"close_fds": True,
"env": _proxy_cli_child_env(),
"env": _proxy_cli_child_env(passphrase_file=passphrase_file),
}
if os.name == "posix":
kwargs["start_new_session"] = True
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,9 @@ def _spawn_center(
]
if passphrase_file is not None:
args.extend(["--passphrase-file", str(passphrase_file)])
from agentveil_mcp_proxy.approval.server import _proxy_cli_child_env

kwargs["env"] = _proxy_cli_child_env(passphrase_file=passphrase_file)
return subprocess.Popen( # noqa: S603 - args constructed from validated paths
args,
**kwargs,
Expand Down
Loading
Loading