generated from coulomb/repo-seed
Fix warden access proxy for catalog fetch commands with shell pipes.
resolve_fetch_command used shlex.split, which treated `|` as a literal argument — breaking reuse-surface-hub-write-token (kubectl | base64 -d). Piped commands now run via shell=True with inherited stdio for --fetch.
This commit is contained in:
@@ -11,6 +11,7 @@ from typer.testing import CliRunner
|
||||
from warden.cli import app
|
||||
from warden.proxy import (
|
||||
ProxyError,
|
||||
ResolvedFetch,
|
||||
caller_auth_present,
|
||||
proxy_exec,
|
||||
proxy_fetch,
|
||||
@@ -45,10 +46,11 @@ def _entry(**over) -> RouteEntry:
|
||||
# --- resolve_fetch_command -------------------------------------------------
|
||||
|
||||
def test_resolve_builds_argv():
|
||||
argv = resolve_fetch_command(
|
||||
resolved = resolve_fetch_command(
|
||||
_entry(), domain="coulomb_social", field="NPM_AUTH_TOKEN", path="platform/x/y/z"
|
||||
)
|
||||
assert argv == ["bao", "kv", "get", "-field=NPM_AUTH_TOKEN", "platform/x/y/z"]
|
||||
assert resolved.argv == ["bao", "kv", "get", "-field=NPM_AUTH_TOKEN", "platform/x/y/z"]
|
||||
assert resolved.shell_cmd is None
|
||||
|
||||
|
||||
def test_resolve_refuses_unresolved_placeholder():
|
||||
@@ -62,6 +64,18 @@ def test_resolve_refuses_non_exec_capable():
|
||||
resolve_fetch_command(_entry(exec_capable=False, fetch_command=None))
|
||||
|
||||
|
||||
def test_resolve_piped_fetch_uses_shell_cmd():
|
||||
from warden.routing import load_catalog
|
||||
|
||||
catalog = load_catalog(Path(__file__).resolve().parents[1] / "registry" / "routing" / "catalog.yaml")
|
||||
entry = catalog.get("reuse-surface-hub-write-token")
|
||||
resolved = resolve_fetch_command(entry)
|
||||
assert resolved.argv is None
|
||||
assert resolved.shell_cmd is not None
|
||||
assert "| base64 -d" in resolved.shell_cmd
|
||||
assert "reuse-surface-env" in resolved.shell_cmd
|
||||
|
||||
|
||||
# --- G2: transit-only fetch (inherited stdout) -----------------------------
|
||||
|
||||
def test_proxy_fetch_inherits_stdout_never_pipes(monkeypatch):
|
||||
@@ -72,13 +86,27 @@ def test_proxy_fetch_inherits_stdout_never_pipes(monkeypatch):
|
||||
return subprocess.CompletedProcess(argv, 0)
|
||||
|
||||
monkeypatch.setattr("warden.proxy.subprocess.run", fake_run)
|
||||
rc = proxy_fetch(["bao", "kv", "get", "x"])
|
||||
rc = proxy_fetch(ResolvedFetch(argv=["bao", "kv", "get", "x"]))
|
||||
assert rc == 0
|
||||
# The value must never enter warden's memory — stdout is inherited, not piped.
|
||||
assert calls["stdout"] is None
|
||||
assert calls.get("stderr") is None
|
||||
|
||||
|
||||
def test_proxy_fetch_shell_pipeline_inherits_stdio(monkeypatch):
|
||||
calls = {}
|
||||
|
||||
def fake_run(cmd, **kw):
|
||||
calls.update(kw)
|
||||
return subprocess.CompletedProcess(cmd, 0)
|
||||
|
||||
monkeypatch.setattr("warden.proxy.subprocess.run", fake_run)
|
||||
rc = proxy_fetch(ResolvedFetch(shell_cmd="kubectl get x | base64 -d"))
|
||||
assert rc == 0
|
||||
assert calls["shell"] is True
|
||||
assert calls["stdout"] is None
|
||||
|
||||
|
||||
# --- G1 + inject: exec injects value into child env, adds no warden token ---
|
||||
|
||||
def test_proxy_exec_injects_only_into_child_env(monkeypatch):
|
||||
@@ -92,7 +120,11 @@ def test_proxy_exec_injects_only_into_child_env(monkeypatch):
|
||||
|
||||
monkeypatch.setattr("warden.proxy.subprocess.run", fake_run)
|
||||
monkeypatch.delenv("NPM_AUTH_TOKEN", raising=False)
|
||||
rc = proxy_exec(["bao", "kv", "get", "x"], env_var="NPM_AUTH_TOKEN", child_argv=["true"])
|
||||
rc = proxy_exec(
|
||||
ResolvedFetch(argv=["bao", "kv", "get", "x"]),
|
||||
env_var="NPM_AUTH_TOKEN",
|
||||
child_argv=["true"],
|
||||
)
|
||||
assert rc == 0
|
||||
# Value injected into child env (trailing newline stripped)…
|
||||
assert seen_env["NPM_AUTH_TOKEN"] == "SECRETVAL"
|
||||
@@ -100,9 +132,28 @@ def test_proxy_exec_injects_only_into_child_env(monkeypatch):
|
||||
assert "VAULT_TOKEN" not in {k for k in seen_env if k not in __import__("os").environ}
|
||||
|
||||
|
||||
def test_proxy_exec_shell_pipeline_captures_stdout(monkeypatch):
|
||||
seen_env = {}
|
||||
|
||||
def fake_run(cmd, **kw):
|
||||
if kw.get("shell"):
|
||||
return subprocess.CompletedProcess(cmd, 0, stdout="PIPEVAL\n")
|
||||
seen_env.update(kw["env"])
|
||||
return subprocess.CompletedProcess(cmd, 0)
|
||||
|
||||
monkeypatch.setattr("warden.proxy.subprocess.run", fake_run)
|
||||
rc = proxy_exec(
|
||||
ResolvedFetch(shell_cmd="kubectl get x | base64 -d"),
|
||||
env_var="REUSE_SURFACE_TOKEN",
|
||||
child_argv=["true"],
|
||||
)
|
||||
assert rc == 0
|
||||
assert seen_env["REUSE_SURFACE_TOKEN"] == "PIPEVAL"
|
||||
|
||||
|
||||
def test_proxy_exec_requires_env_var():
|
||||
with pytest.raises(ProxyError, match="requires --field"):
|
||||
proxy_exec(["bao"], env_var="", child_argv=["true"])
|
||||
proxy_exec(ResolvedFetch(argv=["bao"]), env_var="", child_argv=["true"])
|
||||
|
||||
|
||||
# --- G1 caller auth detection ----------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user