import sys from pathlib import Path from unittest.mock import MagicMock, patch import pytest from sandboxer.extensions.bwrap_runner import _run from sandboxer.extensions.credential_delivery import execute, provider_argv CONTEXT = { "profile_id": "profile.proof", "project": "glas-harness", "actor": "agt", "run_id": "run-1", } def config(command=None): return { "credential_routes": { "proof": { "profiles": ["profile.proof"], "projects": ["glas-harness"], "actors": ["agt"], "exec_argv": command or ["/usr/bin/provider", "--"], } } } @pytest.mark.parametrize( "field,value", [("profile_id", "wrong"), ("project", "wrong"), ("actor", "usr"), ("run_id", "")] ) def test_wrong_consumer_refuses_before_provider(field, value): context = {**CONTEXT, field: value} with pytest.raises(ValueError, match="binding denied"): provider_argv(config(), ["proof"], context) @pytest.mark.parametrize("refs", [[], ["unknown"], ["proof", "proof"]]) def test_unknown_or_multiple_routes_refuse(refs): with pytest.raises(ValueError): provider_argv(config(), refs, CONTEXT) def test_provider_requires_absolute_command(): with pytest.raises(ValueError): provider_argv(config(["relative-provider", "--"]), ["proof"], CONTEXT) def test_redaction_precedes_truncation_and_environment_is_scoped(tmp_path): value = "synthetic-value-for-test" process = MagicMock(returncode=0) process.communicate.return_value = (value.encode() + b" suffix", value.encode()) payload = { "command": ["true"], "timeout_seconds": 1, "max_output_bytes": 5, "credential_env": {"ANTHROPIC_API_KEY": value}, } with patch("sandboxer.extensions.bwrap_runner.subprocess.Popen", return_value=process) as popen: response = _run(payload, tmp_path) assert response["stdout"] == "[REDA" and response["stderr"] == "[REDA" env = popen.call_args.kwargs["env"] assert env["ANTHROPIC_API_KEY"] == value assert "BAO_TOKEN" not in env and "VAULT_TOKEN" not in env @pytest.mark.parametrize( "values", [{"PATH": "bad"}, {"ANTHROPIC_API_KEY": ""}, {"ANTHROPIC_API_KEY": "has newline\n"}] ) def test_bad_credential_envelope_refuses_before_execution(tmp_path, values): with patch("sandboxer.extensions.bwrap_runner.subprocess.Popen") as popen: with pytest.raises(ValueError): _run( { "command": ["true"], "timeout_seconds": 1, "max_output_bytes": 8, "credential_env": values, }, tmp_path, ) popen.assert_not_called() @pytest.mark.parametrize( "body", [ "print('sensitive-provider-failure'); raise SystemExit(1)", "print('sensitive-provider-failure')", "print('x'*100000)", ], ) def test_provider_failure_never_escapes(tmp_path, body): provider = tmp_path / "provider.py" provider.write_text(body) request = { "credential_route_refs": ["proof"], "execution_context": CONTEXT, "timeout_seconds": 1, "max_output_bytes": 8, "command": ["true"], } with pytest.raises(RuntimeError, match="^owner credential delivery failed$"): execute(config([sys.executable, str(provider), "--"]), request, tmp_path / "unused.sock") def test_parent_api_key_is_not_provider_fallback(tmp_path, monkeypatch): monkeypatch.setenv("ANTHROPIC_API_KEY", "ambient-secret") provider = tmp_path / "provider.py" provider.write_text( "import os,json; assert 'ANTHROPIC_API_KEY' not in os.environ; " "print(json.dumps({'exit_code':0}))" ) result = execute( config([sys.executable, str(provider), "--"]), { "credential_route_refs": ["proof"], "execution_context": CONTEXT, "timeout_seconds": 1, "max_output_bytes": 8, }, Path("/unused"), ) assert result == {"exit_code": 0}