sand-boxer/tests/test_credential_delivery.py
tegwick 17d4160b6e
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
feat: deliver owner-bound credentials into bwrap commands
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a0726e-5232-73f2-aaca-2c05ceb62efb
2026-09-06 00:25:07 +02:00

126 lines
4 KiB
Python

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}