WARDEN: separate fetch evaluator URL for secret-read checks (CUST-WP-0075)
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s

check_fetch_policy now posts only to policy.fetch_flex_auth_url (access-engine
pin flex-auth-ops-warden-fetch, workstation 127.0.0.1:19091). Signing keeps
policy.flex_auth_url. Unset or unreachable fetch evaluator fails closed with a
message naming it; no fallback to the signing pin or to allow. warden access
advisory output names the fetch evaluator. Recorded under WARDEN-WP-0039-T03.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 3775@bnt-lap001
Assistant-Session: cfacb6a5-ad5b-4f79-ac67-053e3b0d34a3
This commit is contained in:
tegwick 2026-10-03 09:18:54 +02:00
parent 30747f84c4
commit 7d4381e887
11 changed files with 292 additions and 28 deletions

View file

@ -24,6 +24,9 @@ policy:
# flex-auth.flex-auth.svc Service does not exist. From a workstation, reach it
# through a port-forward or tunnel and point this at that local address.
flex_auth_url: http://flex-auth-ops-warden.flex-auth.svc.cluster.local:8080
# Fetch-check pin (CUST-WP-0075), used only by `warden access` fetches.
# No fallback to flex_auth_url; unset means every fetch is refused.
fetch_flex_auth_url: http://flex-auth-ops-warden-fetch.flex-auth.svc.cluster.local.:8080
zone_registry_path: registry/flex-auth/production_registry_snapshot.json
failure_modes:
z0-experimental: fail_open

View file

@ -98,6 +98,10 @@ def policy_gate_status() -> str:
cfg = load_config()
except ConfigError:
return "advisory — no warden.yaml (caller identity; gate not enforced)"
if cfg.policy.flex_auth_url:
return f"zone-aware — flex-auth at {cfg.policy.flex_auth_url}"
return "zone-aware — evaluator unconfigured; unknown-zone fail_open applies"
fetch_url = cfg.policy.fetch_flex_auth_url
if fetch_url:
return f"zone-aware — fetches gated by flex-auth-ops-warden-fetch at {fetch_url}"
return (
"fail-closed — secret-read evaluator unconfigured "
"(policy.fetch_flex_auth_url unset); fetches are refused"
)

View file

@ -1551,6 +1551,8 @@ def access(
)
if expanded.policy_ref:
console.print(f" policy : {expanded.policy_ref} [dim]({gate})[/dim]")
elif entry.exec_capable:
console.print(f" gate : [dim]{gate}[/dim]")
console.print(f" wiki : {entry.wiki_ref}")
console.print(f" canon : {entry.canon_ref}")

View file

@ -45,7 +45,11 @@ class CallerAuthConfig:
@dataclass
class PolicyConfig:
# SSH signing pin (flex-auth-ops-warden). Admits only resource.system ops-warden.
flex_auth_url: Optional[str] = None
# Secret-read pin (flex-auth-ops-warden-fetch, CUST-WP-0075). Used only by
# check_fetch_policy; there is no fallback to flex_auth_url.
fetch_flex_auth_url: Optional[str] = None
zone_registry_path: Optional[Path] = None
failure_modes: Dict[str, str] = field(
default_factory=lambda: {
@ -211,8 +215,12 @@ def load_config(path: Optional[Path] = None) -> WardenConfig:
)
zone_registry_path = policy_raw.get("zone_registry_path")
flex_auth_url = str(policy_raw.get("flex_auth_url", "")).strip() or None
fetch_flex_auth_url = (
str(policy_raw.get("fetch_flex_auth_url", "") or "").strip() or None
)
policy_cfg = PolicyConfig(
flex_auth_url=flex_auth_url,
fetch_flex_auth_url=fetch_flex_auth_url,
zone_registry_path=(
Path(os.path.expanduser(str(zone_registry_path)))
if zone_registry_path

View file

@ -191,15 +191,21 @@ def check_fetch_policy(
The action is ``read`` on a ``secret`` resource owned by another subsystem —
ops-warden is the conduit, not the owner. Unresolved target workload identity
selects the explicit ``unknown`` profile; no secret value enters the request.
The check goes only to ``cfg.fetch_flex_auth_url`` — the secret-read pin
(flex-auth-ops-warden-fetch, CUST-WP-0075). It never falls back to the SSH
signing pin (``cfg.flex_auth_url``), whose caller binding admits only the
``ops-warden`` system. An unset or unreachable fetch evaluator always fails
closed, whatever the zone failure mode.
"""
zone = "unknown"
fail_closed = _is_fail_closed(cfg, zone)
if cfg.flex_auth_url is None:
_evaluator_failure(
"flex-auth URL is not configured for security zone 'unknown'",
fail_closed=fail_closed,
if cfg.fetch_flex_auth_url is None:
raise CAError(
"secret-read evaluator not configured: set policy.fetch_flex_auth_url "
"(flex-auth-ops-warden-fetch pin); fetch checks never use the SSH "
"signing pin policy.flex_auth_url"
)
return None
subject_id = os.environ.get(cfg.subject_env, "").strip() or "operator"
request = {
"subject": {"id": subject_id, "type": "operator", "tenant": cfg.tenant},
@ -213,8 +219,8 @@ def check_fetch_policy(
"context": {"need_id": need_id, "owner_repo": owner_repo, "domain": domain},
}
url = cfg.flex_auth_url.rstrip("/") + "/v1/check"
headers = _caller_headers(cfg, fail_closed=fail_closed)
url = cfg.fetch_flex_auth_url.rstrip("/") + "/v1/check"
headers = _caller_headers(cfg, fail_closed=True)
try:
response = httpx.post(url, json=request, headers=headers, timeout=10.0)
response.raise_for_status()
@ -231,12 +237,10 @@ def check_fetch_policy(
)
return None
except httpx.RequestError as e:
_evaluator_failure(
f"flex-auth unreachable at {cfg.flex_auth_url!r} for security zone 'unknown'",
fail_closed=fail_closed,
cause=e,
)
return None
raise CAError(
"secret-read evaluator (flex-auth-ops-warden-fetch) unreachable at "
f"{cfg.fetch_flex_auth_url!r}; fetch refused (no fallback to the signing pin)"
) from e
try:
decision = response.json()

View file

@ -0,0 +1,138 @@
"""Secret-read checks use their own evaluator pin, never the SSH signing pin (CUST-WP-0075)."""
from unittest.mock import patch
import httpx
import pytest
from warden.access import policy_gate_status
from warden.ca import CAError
from warden.config import PolicyConfig, load_config
from warden.models import ActorType, CertSpec
from warden.policy import check_fetch_policy, check_sign_policy
SIGN_URL = "http://127.0.0.1:19090"
FETCH_URL = "http://127.0.0.1:19091"
def _allow(url, json=None, headers=None, timeout=None):
return httpx.Response(
200,
json={"effect": "allow", "id": "decision:fetch", "reason": "secret_read_lane_matched"},
request=httpx.Request("POST", url),
)
def _fetch(cfg):
return check_fetch_policy(
cfg, need_id="forgejo-admin-api-token", owner_repo="railiance-platform", domain=None
)
def test_fetch_check_goes_to_fetch_pin_never_sign_pin():
cfg = PolicyConfig(flex_auth_url=SIGN_URL, fetch_flex_auth_url=FETCH_URL)
with patch("warden.policy.httpx.post", side_effect=_allow) as post:
assert _fetch(cfg) == "decision:fetch"
urls = [c.args[0] for c in post.call_args_list]
assert urls == [f"{FETCH_URL}/v1/check"]
body = post.call_args.kwargs["json"]
assert body["resource"]["system"] == "railiance-platform"
assert body["action"] == "read"
@pytest.mark.parametrize("failure_mode", ["fail_open", "fail_closed"])
def test_unset_fetch_url_fails_closed_without_using_sign_pin(failure_mode):
cfg = PolicyConfig(flex_auth_url=SIGN_URL)
cfg.failure_modes["unknown"] = failure_mode
with patch("warden.policy.httpx.post") as post:
with pytest.raises(CAError, match="policy.fetch_flex_auth_url") as err:
_fetch(cfg)
assert "secret-read evaluator not configured" in str(err.value)
post.assert_not_called()
@pytest.mark.parametrize("failure_mode", ["fail_open", "fail_closed"])
def test_unreachable_fetch_url_fails_closed(failure_mode):
cfg = PolicyConfig(flex_auth_url=SIGN_URL, fetch_flex_auth_url=FETCH_URL)
cfg.failure_modes["unknown"] = failure_mode
calls = []
def boom(url, **kwargs):
calls.append(url)
raise httpx.ConnectError("refused", request=httpx.Request("POST", url))
with patch("warden.policy.httpx.post", side_effect=boom):
with pytest.raises(CAError, match="flex-auth-ops-warden-fetch\\) unreachable"):
_fetch(cfg)
assert calls == [f"{FETCH_URL}/v1/check"]
def test_fetch_403_keeps_existing_refusal_text():
cfg = PolicyConfig(flex_auth_url=SIGN_URL, fetch_flex_auth_url=FETCH_URL)
response = httpx.Response(403, request=httpx.Request("POST", f"{FETCH_URL}/v1/check"))
with patch("warden.policy.httpx.post", return_value=response):
with pytest.raises(CAError) as err:
_fetch(cfg)
assert str(err.value) == (
"flex-auth refused fetch policy check (HTTP 403); "
"caller authentication or system binding was rejected"
)
def test_sign_check_still_uses_sign_pin(tmp_path):
cfg = PolicyConfig(flex_auth_url=SIGN_URL, fetch_flex_auth_url=FETCH_URL)
pub = tmp_path / "id.pub"
pub.write_text("ssh-ed25519 AAAA test\n")
spec = CertSpec(actor_name="agt-example", actor_type=ActorType.AGT,
pubkey_path=pub, ttl_hours=1, principals=["agt"])
with patch("warden.policy.httpx.post", side_effect=_allow) as post:
assert check_sign_policy(cfg, spec) == "decision:fetch"
assert [c.args[0] for c in post.call_args_list] == [f"{SIGN_URL}/v1/check"]
assert post.call_args.kwargs["json"]["resource"]["system"] == "ops-warden"
def _write_cfg(tmp_path, monkeypatch, policy_block):
cfg = tmp_path / "warden.yaml"
cfg.write_text(
"backend: local\nca_key: /tmp/none\n" + policy_block
)
monkeypatch.setenv("WARDEN_CONFIG", str(cfg))
return cfg
def test_config_loads_fetch_url(tmp_path, monkeypatch):
_write_cfg(tmp_path, monkeypatch,
f"policy:\n flex_auth_url: {SIGN_URL}\n fetch_flex_auth_url: {FETCH_URL}\n")
cfg = load_config()
assert cfg.policy.flex_auth_url == SIGN_URL
assert cfg.policy.fetch_flex_auth_url == FETCH_URL
def test_gate_status_names_fetch_evaluator(tmp_path, monkeypatch):
_write_cfg(tmp_path, monkeypatch,
f"policy:\n flex_auth_url: {SIGN_URL}\n fetch_flex_auth_url: {FETCH_URL}\n")
status = policy_gate_status()
assert "flex-auth-ops-warden-fetch" in status and FETCH_URL in status
assert SIGN_URL not in status
def test_gate_status_unset_fetch_url_says_refused(tmp_path, monkeypatch):
_write_cfg(tmp_path, monkeypatch, f"policy:\n flex_auth_url: {SIGN_URL}\n")
status = policy_gate_status()
assert "fetch_flex_auth_url unset" in status and "refused" in status
def test_access_advisory_prints_fetch_evaluator(tmp_path, monkeypatch):
from pathlib import Path
from typer.testing import CliRunner
from warden.cli import app
catalog = Path(__file__).resolve().parents[1] / "registry" / "routing" / "catalog.yaml"
monkeypatch.setenv("WARDEN_ROUTING_CATALOG", str(catalog))
_write_cfg(tmp_path, monkeypatch,
f"policy:\n flex_auth_url: {SIGN_URL}\n fetch_flex_auth_url: {FETCH_URL}\n")
result = CliRunner().invoke(app, ["access", "forgejo-admin-api-token"])
assert result.exit_code == 0, result.output
flat = " ".join(result.output.split())
assert "flex-auth-ops-warden-fetch" in flat and FETCH_URL in flat

View file

@ -14,7 +14,7 @@ from warden.policy import check_fetch_policy, check_sign_policy
@pytest.mark.parametrize("failure_mode", ["fail_open", "fail_closed"])
@pytest.mark.parametrize("operation", ["sign", "fetch"])
def test_explicit_refusal_blocks_under_every_outage_mode(tmp_path, status, failure_mode, operation):
cfg = PolicyConfig(flex_auth_url="http://pdp.test")
cfg = PolicyConfig(flex_auth_url="http://pdp.test", fetch_flex_auth_url="http://pdp.test")
cfg.failure_modes["unknown"] = failure_mode
public_key = tmp_path / "id.pub"
public_key.write_text("ssh-ed25519 AAAA test\n")
@ -37,7 +37,7 @@ def test_explicit_refusal_blocks_under_every_outage_mode(tmp_path, status, failu
@pytest.mark.parametrize("status", [500, 503])
@pytest.mark.parametrize("failure_mode", ["fail_open", "fail_closed"])
def test_actual_evaluator_failure_retains_declared_outage_mode(status, failure_mode):
cfg = PolicyConfig(flex_auth_url="http://pdp.test")
cfg = PolicyConfig(flex_auth_url="http://sign.test", fetch_flex_auth_url="http://pdp.test")
cfg.failure_modes["unknown"] = failure_mode
response = httpx.Response(status, request=httpx.Request("POST", "http://pdp.test/v1/check"))
with patch("warden.policy.httpx.post", return_value=response):

View file

@ -203,11 +203,18 @@ def _proxy_env(monkeypatch, tmp_path):
monkeypatch.setenv("WARDEN_CONFIG", str(_warden_yaml(tmp_path)))
def test_cli_proxy_unknown_zone_fail_open_reaches_transport_guard(monkeypatch, tmp_path):
def _allow_fetch_gate(monkeypatch):
"""Stand in for an allowing secret-read evaluator (flex-auth-ops-warden-fetch)."""
monkeypatch.setattr(
"warden.policy.check_fetch_policy", lambda *a, **k: "decision:test-fetch"
)
def test_cli_proxy_unset_fetch_evaluator_fails_closed(monkeypatch, tmp_path):
_proxy_env(monkeypatch, tmp_path)
monkeypatch.setenv("VAULT_TOKEN", "caller")
# The unknown-zone profile proceeds when no evaluator is configured, then
# the independent safe-transport boundary still refuses captured stdout.
# No policy.fetch_flex_auth_url: the fetch is refused before any transport,
# whatever the unknown-zone failure mode (CUST-WP-0075).
monkeypatch.setattr(
"warden.proxy.subprocess.run",
lambda *a, **k: (_ for _ in ()).throw(AssertionError("fetch ran despite gate")),
@ -217,8 +224,9 @@ def test_cli_proxy_unknown_zone_fail_open_reaches_transport_guard(monkeypatch, t
["access", "npm", "--domain", "coulomb_social", "--field", "NPM_AUTH_TOKEN",
"--path", "platform/x/y/z", "--fetch"],
)
assert r.exit_code == 6
assert "unknown-zone fail_open" in r.output
assert r.exit_code == 4
assert "fetch_flex_auth_url" in r.output
assert "fail_open applied" not in r.output
def test_cli_proxy_requires_caller_auth(monkeypatch, tmp_path):
@ -240,7 +248,10 @@ def test_cli_explicit_policy_refusal_never_fetches_or_starts_child(monkeypatch,
_proxy_env(monkeypatch, tmp_path)
cfg = tmp_path / "warden.yaml"
cfg.write_text(cfg.read_text() + "policy:\n flex_auth_url: http://pdp.test\n")
cfg.write_text(
cfg.read_text()
+ "policy:\n flex_auth_url: http://sign.test\n fetch_flex_auth_url: http://pdp.test\n"
)
monkeypatch.setenv("VAULT_TOKEN", "caller-test-value")
monkeypatch.setattr(
"warden.policy.httpx.post",
@ -634,6 +645,7 @@ def test_build_wrapped_fetch_refuses_placeholder_path():
def test_access_fetch_to_nonterminal_stdout_is_refused(tmp_path, monkeypatch):
"""The anti-pattern: streaming a value to captured stdout is refused (exit 6)."""
_proxy_env(monkeypatch, tmp_path)
_allow_fetch_gate(monkeypatch)
monkeypatch.setenv("VAULT_TOKEN", "caller-token") # G1 caller-auth precheck
# The guard trips before the fetch runs; make a real bao call fail loudly if reached.
monkeypatch.setattr(
@ -649,6 +661,7 @@ def test_access_fetch_to_nonterminal_stdout_is_refused(tmp_path, monkeypatch):
def test_access_fingerprint_masks_and_bypasses_stdout_guard(monkeypatch, tmp_path):
"""--fingerprint prints a masked fingerprint (never the value) even to captured stdout."""
_proxy_env(monkeypatch, tmp_path)
_allow_fetch_gate(monkeypatch)
monkeypatch.setenv("VAULT_TOKEN", "caller-token")
class _Fake:
@ -668,6 +681,7 @@ def test_access_fingerprint_masks_and_bypasses_stdout_guard(monkeypatch, tmp_pat
def test_access_agent_high_risk_raw_stream_refused(tmp_path, monkeypatch):
"""WP-0026 T04: WARDEN_AGENT_ID + risk=high refuses raw value stream (exit 7)."""
_proxy_env(monkeypatch, tmp_path)
_allow_fetch_gate(monkeypatch)
monkeypatch.setenv("VAULT_TOKEN", "caller-token")
monkeypatch.setenv("WARDEN_AGENT_ID", "grok")
# Prefer high-risk lane; use --unsafe-stdout so T02 would allow if T04 failed.
@ -687,6 +701,7 @@ def test_access_issued_agent_subject_refuses_raw_stream_without_legacy_marker(
):
"""WP-0034 T02: the issued KeyCape subject is sufficient for exit 7."""
_proxy_env(monkeypatch, tmp_path)
_allow_fetch_gate(monkeypatch)
monkeypatch.setenv("VAULT_TOKEN", "caller-token")
monkeypatch.delenv("WARDEN_AGENT_ID", raising=False)
monkeypatch.setenv(
@ -706,6 +721,7 @@ def test_access_issued_agent_subject_refuses_raw_stream_without_legacy_marker(
def test_access_agent_high_risk_fingerprint_allowed(tmp_path, monkeypatch):
"""Agents may use --fingerprint on high-risk lanes (no raw value)."""
_proxy_env(monkeypatch, tmp_path)
_allow_fetch_gate(monkeypatch)
monkeypatch.setenv("VAULT_TOKEN", "caller-token")
monkeypatch.setenv("WARDEN_AGENT_ID", "grok")

View file

@ -128,6 +128,20 @@ value; the owner remains OpenBao, key-cape, flex-auth, or the routed subsystem.
---
## Policy gate for proxied credential reads
`warden access <need>` with `--exec`, `--fetch`, `--to-file`, `--wrap` or
`--fingerprint` runs a flex-auth `read` check before any fetch. That check goes
to the **fetch evaluator** `flex-auth-ops-warden-fetch`
(`policy.fetch_flex_auth_url`, workstation `http://127.0.0.1:19091` through
ops-bridge tunnel `flex-auth-ops-warden-fetch-railiance01`). It does not go to
the SSH signing pin `flex-auth-ops-warden` (`policy.flex_auth_url`,
`127.0.0.1:19090`), which admits only the `ops-warden` system. If the fetch
evaluator is unset or unreachable, the fetch is refused (exit 4). It is never
sent to the signing pin and never allowed by default. The `gate` line of
`warden access <need>` names the evaluator in use. Config:
`wiki/OpsWardenConfig.md` → "Two evaluators" (CUST-WP-0075).
## Examples — do NOT ask ops-warden to own or vend
| Request | Correct path |

View file

@ -36,10 +36,12 @@ ca_key: ~/.ssh/ops-ca-user
inventory_path: ~/.config/warden/inventory.yaml
state_dir: ~/.local/state/warden
# Zone-aware flex-auth gate. With no URL, the explicit unknown/build profile
# fails open and records that no evaluator decision was available.
# Zone-aware flex-auth gate. With no signing URL, the explicit unknown/build
# profile fails open for signing and records that no evaluator decision was
# available. Fetch checks need fetch_flex_auth_url and fail closed without it.
policy:
flex_auth_url: http://127.0.0.1:8080
fetch_flex_auth_url: http://127.0.0.1:8081
zone_registry_path: /path/to/compiled-flex-auth-registry.json
failure_modes:
z0-experimental: fail_open
@ -96,6 +98,7 @@ state_dir: ~/.local/state/warden
# Configure after flex-auth ssh-certificate policies are deployed:
# policy:
# flex_auth_url: http://flex-auth-ops-warden.flex-auth.svc.cluster.local:8080
# fetch_flex_auth_url: http://flex-auth-ops-warden-fetch.flex-auth.svc.cluster.local.:8080
# zone_registry_path: /etc/warden/production_registry_snapshot.json
```
@ -253,6 +256,7 @@ zone. Signing records `policy_decision_id` when present plus `policy_zone`,
```yaml
policy:
flex_auth_url: http://127.0.0.1:8080
fetch_flex_auth_url: http://127.0.0.1:8081
zone_registry_path: registry/flex-auth/production_registry_snapshot.json
failure_modes:
z0-experimental: fail_open
@ -274,6 +278,32 @@ for an unavailable or invalid evaluator.
Full request shape and rollout notes: `wiki/PolicyGatedSigning.md`.
### Two evaluators: signing and fetch checks (CUST-WP-0075)
| Key | Pin | Used by | Admits |
|-----|-----|---------|--------|
| `policy.flex_auth_url` | `flex-auth-ops-warden` (workstation `127.0.0.1:19090`) | `warden sign`, `warden issue` | `resource.system: ops-warden` only |
| `policy.fetch_flex_auth_url` | `flex-auth-ops-warden-fetch` (workstation `127.0.0.1:19091`) | `warden access <need>` fetch transports (`check_fetch_policy`) | `read` for catalog lanes with status `active`, `exec_capable: true` and lane `secret`, for owner systems bound in access-engine `values/ops-warden-fetch.yaml` |
Both use the same caller identity (`policy.caller_auth`: the ops-warden service
account token, audience `flex-auth`). For fetches a missing caller token refuses
the fetch instead of sending an unauthenticated request.
The fetch check never falls back to `flex_auth_url`: the signing pin binds only
the `ops-warden` system, so every fetch for another owner would get 403. If
`fetch_flex_auth_url` is unset or the evaluator is unreachable, the fetch fails
closed (exit 4) with a message naming the missing fetch evaluator, whatever the
`unknown` failure mode says. An explicit 401/403 still maps to "flex-auth
refused fetch policy check (HTTP 403); caller authentication or system binding
was rejected". `warden access <need>` prints which evaluator gates fetches on
its `gate` line (or `policy` line).
In-cluster address: `http://flex-auth-ops-warden-fetch.flex-auth.svc.cluster.local.:8080`
(keep the trailing dot). access-engine `tools/gen_ops_warden_fetch.py` generates
the pin's readable set from this repo's routing catalog. When you add or retire a
lane of that kind, tell access-engine so it can regenerate the set and roll a new
image. Deployment notes: access-engine `examples/ops-warden-fetch/README.md`.
---
## Environment variables
@ -302,6 +332,29 @@ tunnels:
cert_command: "warden sign agt-state-hub-bridge --pubkey ~/.ssh/agt-state-hub-bridge_ed25519.pub"
```
Workstation tunnels to the two flex-auth pins (`remote_host` is each pin
Service's ClusterIP, see access-engine `examples/ops-warden-fetch/README.md`):
```yaml
tunnels:
flex-auth-ops-warden-railiance01: # signing pin -> policy.flex_auth_url
host: 92.205.62.239
direction: local
remote_host: <flex-auth-ops-warden ClusterIP>
remote_port: 8080
local_port: 19090
health_check:
url: http://127.0.0.1:19090/healthz
flex-auth-ops-warden-fetch-railiance01: # fetch pin -> policy.fetch_flex_auth_url
host: 92.205.62.239
direction: local
remote_host: <flex-auth-ops-warden-fetch ClusterIP>
remote_port: 8080
local_port: 19091
health_check:
url: http://127.0.0.1:19091/healthz
```
`ops-bridge` runs `cert_command` before each SSH launch, captures stdout as the cert,
and passes it alongside the private key via `ssh -i <key> -i <cert>`.
See `wiki/CertCommandInterface.md` for the full contract and

View file

@ -9,7 +9,7 @@ flavor: residual
owner: codex
topic_slug: custodian
created: "2026-09-08"
updated: "2026-09-28"
updated: "2026-10-03"
origin: residual
origin_ref: HFACT-WP-0001
state_hub_workstream_id: "ae44a935-6fca-514c-a385-4550dd2b1fe8"
@ -64,7 +64,8 @@ status: wait
flavor: residual
priority: high
assignee: the-custodian
blocking_reason: "The configured ops-warden caller represents ops-warden; credential requests name their owner as resource.system. Need the flex-auth/credential-owner contract for that exact delegated read, without broadening caller bindings or relabelling resource ownership."
needs_human: true
blocking_reason: "Code side done 2026-10-03 (policy.fetch_flex_auth_url). Waits on founder go: deploy access-engine pin flex-auth-ops-warden-fetch, add tunnel flex-auth-ops-warden-fetch-railiance01, set the key in live warden.yaml, then record positive and wrong-owner evidence."
state_hub_task_id: "8ca28b63-2e04-5333-b635-011b124c1806"
```
@ -116,3 +117,24 @@ confirms resource.system is runtime policy vocabulary, not a repository rename.
Retain the explicit refusal. A native owner route's success does not grant this
interim proxy general delegated-read authority; exact positive and caller/owner/
tenant negative evidence is still required for the route that replaces it.
**T03 code side done 2026-10-03 (CUST-WP-0075, founder build-mode directive).**
access-engine answered the contract question with a dedicated fetch evaluator:
pin `flex-auth-ops-warden-fetch` (access-engine 02b15a7, `values/ops-warden-fetch.yaml`),
same caller (ops-warden SA, audience flex-auth), owner systems bound per lane,
request shape unchanged. ops-warden now sends `check_fetch_policy` only to the new
key `policy.fetch_flex_auth_url`; signing keeps `policy.flex_auth_url`. An unset or
unreachable fetch evaluator fails closed with a message naming it, with no fallback
to the signing pin and no fail-open. 401/403 keep the existing refusal text.
`warden access <need>` names the fetch evaluator on its `gate` (or `policy`) line. Tests:
`tests/test_policy_fetch_evaluator.py`, plus updated proxy and refusal tests. Full
suite: 494 passed, 4 deselected. Docs: `wiki/OpsWardenConfig.md` ("Two
evaluators", tunnel example), `wiki/CredentialRouting.md`, production example.
Still open (founder go, `needs_human`): deploy the pin (access-engine
ADHOC-2026-10-03-T02), add the ops-bridge tunnel (local 19091 → the pin's Service
ClusterIP:8080), set `fetch_flex_auth_url: http://127.0.0.1:19091` in the live
`~/.config/warden/warden.yaml`, then record exact positive evidence and
wrong-owner/caller negative evidence before T03 closes. Until the key is set,
every proxied fetch refuses with "secret-read evaluator not configured". Before
that change, those fetches got a 403 from the signing pin.