Fix contained OpenBao login handoff
Assistant: codex Assistant-Model: gpt-5.6-sol Assistant-Session: 01a058f3-8ba0-7692-a042-9a870fc3d663
This commit is contained in:
parent
4e267179db
commit
b4c1d3900a
3 changed files with 81 additions and 6 deletions
|
|
@ -12,8 +12,9 @@ intact. Three guardrails are enforced here in code:
|
|||
the tool with inherited stdout/stderr so the value never enters warden's memory;
|
||||
sanctioned exec/file transports hold it only for their bounded handoff. The
|
||||
high-risk attended-login lane is stricter: it captures every client byte inside
|
||||
an isolated helper session, permits no output, self-revokes, and cleans up. Audit
|
||||
records are metadata only.
|
||||
an isolated helper session, never returns that output, requires successful
|
||||
persistence to a private token helper, self-revokes, and cleans up. Audit records
|
||||
are metadata only.
|
||||
* **G3 — policy gate before fetch.** The CLI runs ``check_fetch_policy`` before
|
||||
calling anything here; this module refuses to run an unresolved command template.
|
||||
|
||||
|
|
@ -380,9 +381,11 @@ def proxy_attended_login_exec(
|
|||
"""Run an attended login and one silent child inside a private helper home.
|
||||
|
||||
The default home is proven writable before the OIDC client starts. Login,
|
||||
child, and revocation output are captured and discarded. Any non-empty output,
|
||||
persistence defect, or non-zero result fails closed; any possibly issued token
|
||||
is revoked before the isolated helper directory is removed.
|
||||
child, and revocation output are captured and discarded. A successful login
|
||||
may return client output only after the private helper has been populated;
|
||||
persistence defects and non-zero results fail closed. The reviewed child must
|
||||
remain silent. Any possibly issued token is revoked before the isolated helper
|
||||
directory is removed.
|
||||
"""
|
||||
if not child_argv:
|
||||
raise ProxyError(
|
||||
|
|
@ -428,7 +431,7 @@ def proxy_attended_login_exec(
|
|||
except (OSError, ProxyError):
|
||||
helper_valid = False
|
||||
|
||||
if login.returncode != 0 or login_output.strip() or not helper_valid:
|
||||
if login.returncode != 0 or not helper_valid:
|
||||
revoked = _revoke_contained(
|
||||
resolved.argv[0], env=env, possible_output=login_output
|
||||
)
|
||||
|
|
|
|||
|
|
@ -391,6 +391,42 @@ def test_attended_login_unexpected_output_is_contained_revoked_and_cleaned(
|
|||
assert not (tmp_path / ".warden-attended-login").exists()
|
||||
|
||||
|
||||
def test_attended_login_contained_success_output_never_escapes(monkeypatch, tmp_path, capsys):
|
||||
monkeypatch.setattr(Path, "home", lambda: tmp_path)
|
||||
sentinel = "hvs.NONPRODUCTION_CONTAINED_LOGIN"
|
||||
child_ran = False
|
||||
|
||||
def fake_run(argv, **kw):
|
||||
nonlocal child_ran
|
||||
helper = Path(kw["env"]["HOME"]) / ".vault-token"
|
||||
if argv[:2] == ["bao", "login"]:
|
||||
helper.write_text(sentinel)
|
||||
helper.chmod(0o600)
|
||||
return subprocess.CompletedProcess(
|
||||
argv,
|
||||
0,
|
||||
stdout=json.dumps({"auth": {"client_token": sentinel}}).encode(),
|
||||
stderr=b"",
|
||||
)
|
||||
if argv == ["reviewed-child"]:
|
||||
child_ran = True
|
||||
return subprocess.CompletedProcess(argv, 0, stdout=b"", stderr=b"")
|
||||
if argv[:3] == ["bao", "token", "revoke"]:
|
||||
return subprocess.CompletedProcess(argv, 0, stdout=b"", stderr=b"")
|
||||
raise AssertionError(argv)
|
||||
|
||||
monkeypatch.setattr("warden.proxy.subprocess.run", fake_run)
|
||||
assert proxy_attended_login_exec(
|
||||
ResolvedFetch(argv=["bao", "login", "-no-print"]),
|
||||
child_argv=["reviewed-child"],
|
||||
) == 0
|
||||
captured = capsys.readouterr()
|
||||
assert child_ran is True
|
||||
assert sentinel not in captured.out
|
||||
assert sentinel not in captured.err
|
||||
assert not (tmp_path / ".warden-attended-login").exists()
|
||||
|
||||
|
||||
def test_real_catalog_login_entry_is_login_lane():
|
||||
from warden.routing import load_catalog
|
||||
e = load_catalog(_repo_catalog()).get("key-cape-oidc-login")
|
||||
|
|
|
|||
36
workplans/WARDEN-WP-0034-attended-login-openbao-output.md
Normal file
36
workplans/WARDEN-WP-0034-attended-login-openbao-output.md
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
---
|
||||
id: WARDEN-WP-0034
|
||||
type: workplan
|
||||
title: "Accept contained OpenBao login output only after helper persistence"
|
||||
domain: infotech
|
||||
repo: ops-warden
|
||||
status: active
|
||||
owner: codex
|
||||
topic_slug: attended-login-openbao-output
|
||||
created: "2026-09-01"
|
||||
updated: "2026-09-01"
|
||||
---
|
||||
|
||||
## Repair attended-login handoff
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0034-T01
|
||||
status: done
|
||||
priority: high
|
||||
```
|
||||
|
||||
Allow a successful OpenBao login to proceed when its output is fully contained
|
||||
and the private mode-0600 token helper is populated. Continue failing closed on
|
||||
non-zero login, missing persistence, child output, revocation failure, or cleanup
|
||||
failure.
|
||||
|
||||
## Verify live contained operation
|
||||
|
||||
```task
|
||||
id: WARDEN-WP-0034-T02
|
||||
status: progress
|
||||
priority: high
|
||||
```
|
||||
|
||||
Run the proxy regression suite, reinstall the CLI, and complete one governed
|
||||
OpenBao platform-admin operation with deterministic self-revocation.
|
||||
Loading…
Add table
Add a link
Reference in a new issue