Fix KV v2 policy path shape; live end-to-end verification succeeded
Two more real bugs found completing this lane for real: 1. platform-admin's own policy had no entry for the new reins/ mount -- the founder's paste-once-provision write 403'd because the admin identity that created the mount was never granted access to operate on it. Fixed live (added path "reins/*" matching every other mount already in that policy). 2. _policy_hcl wrote the bare KV-v1-shaped path (reins/rein-openweights/openrouter) instead of KV v2's data/+metadata/ sub-paths -- bao token capabilities on the bare path even reported full access, but the actual kv get still 403'd, because OpenBao evaluates the real request against the data/-prefixed path. Caught when the AppRole's own read failed during live verification. Fixed in code (now emits both data/ and metadata/ paths), locked in with a dedicated unit test, and re-applied to the live policy. Live end-to-end verification succeeded after both fixes: real AppRole login, real KV v2 read via the corrected policy, real OpenRouter call, real commit -- with OPENROUTER_API_KEY unset the whole time. Plan status: catalogued. glas-harness/GLAS-WP-0002-T02 is closed by this. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
parent
846ef0561c
commit
9bcb5819de
3 changed files with 79 additions and 4 deletions
|
|
@ -69,8 +69,22 @@ def _run(bao_bin: str, args: list[str], input_text: str | None = None) -> str:
|
|||
|
||||
|
||||
def _policy_hcl(kv_path: str, capabilities: tuple[str, ...]) -> str:
|
||||
"""Policy HCL for a KV v2 path — grants on both data/ and metadata/ sub-paths.
|
||||
|
||||
KV v2 routes actual secret reads/writes through `<mount>/data/<path>`;
|
||||
a policy written against the bare `<mount>/<path>` (the KV v1 shape)
|
||||
silently denies everything on a v2 mount. Caught live during
|
||||
MASON-WP-0001-T05's build — `bao token capabilities` on the bare path
|
||||
reported full access, but the actual `kv get` still 403'd, because
|
||||
OpenBao evaluates policy against the real `data/`-prefixed path, not
|
||||
the one a caller might naively check capabilities against.
|
||||
"""
|
||||
mount, _, rest = kv_path.partition("/")
|
||||
caps = ", ".join(f'"{c}"' for c in capabilities)
|
||||
return f'path "{kv_path}" {{\n capabilities = [{caps}]\n}}\n'
|
||||
return (
|
||||
f'path "{mount}/data/{rest}" {{\n capabilities = [{caps}]\n}}\n\n'
|
||||
f'path "{mount}/metadata/{rest}" {{\n capabilities = [{caps}]\n}}\n'
|
||||
)
|
||||
|
||||
|
||||
def build_approle_kv_lane(plan: ConstructionPlan, spec: AppRoleKVSpec) -> dict[str, str]:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue