From 6f2ae056c0451fa1dd4a6cdadfb986f1ec45c310 Mon Sep 17 00:00:00 2001 From: Alexandre Teixeira <111787685+alteixeira20@users.noreply.github.com> Date: Fri, 2 Oct 2026 23:23:40 +0100 Subject: [PATCH] chore(runtime): close Wave 3 review nits --- src/bg_jobs.py | 4 ---- src/browser_identity.py | 2 ++ src/tool_execution.py | 12 +--------- tests/test_wave3_browser_platform.py | 21 +++++++++++++++++ tests/test_wave3_subprocess_environment.py | 27 ++++++++++++++++++++++ 5 files changed, 51 insertions(+), 15 deletions(-) create mode 100644 tests/test_wave3_browser_platform.py create mode 100644 tests/test_wave3_subprocess_environment.py diff --git a/src/bg_jobs.py b/src/bg_jobs.py index 48cff4864..a8c3d4c32 100644 --- a/src/bg_jobs.py +++ b/src/bg_jobs.py @@ -404,10 +404,6 @@ def get(job_id: str, *, expected) -> Optional[Dict[str, Any]]: return rec -def list_for_session(session_id: str) -> List[Dict[str, Any]]: - return [r for r in _load().values() if r.get("session_id") == session_id] - - @store_transaction(lambda: _STORE) def kill(job_id: str, *, expected) -> Optional[Dict[str, Any]]: """Terminate a running job's process tree and mark it killed. Returns the diff --git a/src/browser_identity.py b/src/browser_identity.py index cfac39f2c..71131bf40 100644 --- a/src/browser_identity.py +++ b/src/browser_identity.py @@ -30,6 +30,8 @@ from src.process_lifecycle import ProcessIdentity, observe from src.constants import BROWSER_RESOURCES_DIR PRODUCER_VERSION = "0.35.0" +# Wave 3 session metadata supports only these observed glibc Linux artifacts. +# macOS/Windows and other architectures fail closed before any producer call. PRODUCER_HASHES = { "linux-x64": "b7a28c3a43a7008dd02585e2e60c391c08983f7a099149caed63c9f13f57b752", "linux-arm64": "92cd7d0897837ac648b9a6ab1965c69c5920e0f54df57e4295cdb1143b0541c8", diff --git a/src/tool_execution.py b/src/tool_execution.py index 4aa8c6be2..e495dd1fb 100644 --- a/src/tool_execution.py +++ b/src/tool_execution.py @@ -1246,8 +1246,6 @@ def _split_bg_marker(content: str): return False, content -import re as _re - # Variables a legitimate agent bash/python subprocess needs from the host. # Anything not listed here is never inherited. _SAFE_SUBPROCESS_VARS = frozenset({ @@ -1267,19 +1265,11 @@ _SAFE_SUBPROCESS_VARS = frozenset({ "LD_LIBRARY_PATH", }) -# Defence-in-depth: reject any allowlisted variable whose *name* matches -# a credential-bearing pattern (e.g. a user who sets PATH_TOKEN=...). -_SENSITIVE_PATTERN = _re.compile( - r"(?:KEY|TOKEN|SECRET|PASSW|AUTH|CREDENTIAL|PRIVATE|DATABASE_URL)", - _re.IGNORECASE, -) - - def _agent_subprocess_env() -> dict: base = { key: os.environ[key] for key in _SAFE_SUBPROCESS_VARS - if key in os.environ and not _SENSITIVE_PATTERN.search(key) + if key in os.environ } base.setdefault("PATH", os.environ.get("PATH") or os.defpath or "/usr/local/bin:/usr/bin:/bin") base.setdefault("LANG", "C.UTF-8") diff --git a/tests/test_wave3_browser_platform.py b/tests/test_wave3_browser_platform.py new file mode 100644 index 000000000..a0ae58d71 --- /dev/null +++ b/tests/test_wave3_browser_platform.py @@ -0,0 +1,21 @@ +"""Wave 3 metadata requires a real allowlisted Linux producer artifact.""" +import pytest +from src import browser_identity as browser +from src.agent_runtime.resources import ResourceIdentityError + + +@pytest.mark.parametrize('system,machine', [('Darwin', 'x86_64'), ('Darwin', 'arm64'), + ('Windows', 'AMD64'), ('Windows', 'ARM64'), ('Linux', 'riscv64')]) +async def test_unsupported_platform_fails_before_producer_execution(monkeypatch, system, machine): + monkeypatch.setattr(browser.platform, 'system', lambda: system) + monkeypatch.setattr(browser.platform, 'machine', lambda: machine) + async def forbidden(*args, **kwargs): pytest.fail('Unsupported producer was executed') + monkeypatch.setattr(browser, 'run_client', forbidden) + with pytest.raises(ResourceIdentityError, match='Unsupported browser producer platform'): + await browser.trusted_producer() + + +def test_observed_release_hash_contract_is_explicit(): + assert set(browser.PRODUCER_HASHES) == {'linux-x64', 'linux-arm64'} + assert browser.PRODUCER_VERSION == '0.35.0' + assert browser.SESSION_ACTIONS == {'session_info'} diff --git a/tests/test_wave3_subprocess_environment.py b/tests/test_wave3_subprocess_environment.py new file mode 100644 index 000000000..f0702c729 --- /dev/null +++ b/tests/test_wave3_subprocess_environment.py @@ -0,0 +1,27 @@ +"""Closed inheritance is the complete subprocess environment boundary.""" +from src import tool_execution + +def test_closed_subprocess_environment_drops_all_unlisted_credentials(monkeypatch): + from unittest.mock import patch + import os + ambient = {'PATH': '/usr/bin', 'LANG': 'C.UTF-8', 'OPENAI_API_KEY': 'secret', 'HF_TOKEN': 'secret', + 'AUTH_ENABLED': 'false', 'DATABASE_URL': 'secret', 'PATH_TOKEN': 'secret', + 'AWS_SECRET_ACCESS_KEY': 'secret', 'ARBITRARY': 'secret', 'HOME': '/server/secret'} + with patch.dict(os.environ, ambient, clear=True): + child = tool_execution._agent_subprocess_env() + assert child['PATH'] == '/usr/bin' + assert child['HOME'] == tool_execution._AGENT_WORKDIR + assert set(child) <= tool_execution._SAFE_SUBPROCESS_VARS | {'HOME', 'TERM', 'COLUMNS', 'LINES'} + assert all(child.get(name) != value for name, value in ambient.items() if name not in {'PATH', 'LANG'}) + + +async def test_real_python_child_does_not_inherit_ambient_credentials(workspace, monkeypatch): + from tests.test_runtime_resource_integration import authority, dispatch + for name in ('OPENAI_API_KEY', 'HF_TOKEN', 'PATH_TOKEN', 'DATABASE_URL', 'ODYSSEUS_INTERNAL_TOKEN'): + monkeypatch.setenv(name, 'never-inherit-this-value') + _, result = await dispatch(authority(workspace, 'python'), 'python', + 'import os\nprint(any(v == "never-inherit-this-value" for v in os.environ.values()))') + assert result['exit_code'] == 0 and result['output'] == 'False' + + +from tests.test_runtime_resource_integration import workspace