feat(WARDEN-WP-0014): T3 — OpenBao proxy lane (--fetch / --exec)

Adds transparent, policy-gated, audited proxy of a non-SSH credential
through `warden access`, for exec_capable lanes. Three guardrails in code:

- G1 caller identity: runs the owner's tool with the caller's own env;
  warden injects no token of its own (caller_auth_present check).
- G2 transit-only: --fetch inherits stdout (never PIPE) so the value
  never enters warden's memory or any log; --exec injects into the child
  env only. Audit (access-audit.log) is metadata-only.
- G3 policy gate: check_fetch_policy runs before any fetch; with
  policy.enabled=false the proxy refuses unless --no-policy is given.

resolve_fetch_command refuses unresolved <…> placeholders rather than
guess owner-side names. New warden/proxy.py + policy.check_fetch_policy;
tests/test_proxy.py asserts all three guardrails. 168 passed, lint clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-27 16:26:03 +02:00
parent 830a775bcf
commit 6dfa69e310
5 changed files with 588 additions and 11 deletions

View File

@@ -129,19 +129,25 @@ state_hub_task_id: "c1497263-7124-459f-b63a-d0c0c7005c86"
```task
id: WARDEN-WP-0014-T03
status: todo
status: done
priority: high
state_hub_task_id: "6d3eb0e4-309c-4065-893e-6c4053fb0db2"
```
- [ ] `warden access <need> --fetch` — policy-gate (G3) → `exec` the owning tool
(`bao kv get ...`) **as the caller** → stream value to stdout. No buffering, no log.
- [ ] `warden access <need> --exec -- <cmd>` — run a child command with the secret
injected into *its* env only (à la `op run`); value never lands in the caller's
shell history or persistent env.
- [ ] Enforce guardrails G1G3 in code; unit + integration tests assert: no value on
disk, no value in logs, no standing warden credential, gate runs before fetch.
- [ ] Audit event (metadata only) written per fetch — reuse the signatures-log pattern.
- [x] `warden access <need> --fetch` — policy-gate (G3) → run the owning tool
(`bao kv get ...`) **as the caller** with **inherited stdout** → value streams to
stdout and never enters warden's memory (`proxy_fetch`). No buffering, no log.
- [x] `warden access <need> --exec -- <cmd>` — runs the child with the secret injected
into *its* env only (`proxy_exec`); value never lands in the caller's shell env;
`--field` names the env var (e.g. `NPM_AUTH_TOKEN`).
- [x] Guardrails G1G3 in code (`warden/proxy.py`, `_access_proxy` in `cli.py`):
G1 caller token only (no warden credential; `caller_auth_present`); G2 transit-only
(inherit-stdout fetch; no disk/log write); G3 `check_fetch_policy` before any exec,
`--no-policy` required to proxy ungated. `tests/test_proxy.py` asserts all three,
plus `resolve_fetch_command` refuses unresolved `<…>` placeholders. Live smoke
against a fake `bao` confirmed gate-refusal, stream, exec-inject, and a
secret-free audit log.
- [x] Metadata-only audit per call (`write_audit``state_dir/access-audit.log`).
### T4 — key-cape / login orchestration lane