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:
tegwick 2026-07-27 01:50:18 +02:00
parent 846ef0561c
commit 9bcb5819de
3 changed files with 79 additions and 4 deletions

View file

@ -3,7 +3,7 @@ id: rein-openweights-openrouter-approle
demand_source: glas-harness/workplans/GLAS-WP-0002-T02
consumer_repo: rein-openweights
credential_type: openbao-approle-kv
status: built
status: catalogued
approved_by: "Bernd Worsch"
approved_at: "2026-07-27"
created: "2026-07-27"
@ -199,3 +199,47 @@ below — no secret material.
the real OpenRouter API key into `reins/rein-openweights/openrouter`
(field `api_key`) through ops-warden's `paste_once_provision` desk —
ops-mason built structure only, per `INTENT.md`.
## 7. Post-build corrections (found completing phases 4-onward for real)
Two more real bugs surfaced only by actually exercising the built lane,
both fixed at the root cause, not just patched live:
- **`platform-admin`'s own policy had no entry for the new `reins/`
mount.** The founder's `paste_once_provision` desk write failed
(`403`, "preflight capability check") because the admin identity that
created the mount was never granted access to operate on it — every
other KV mount (`platform/`, `secret/`, `tenants/`, ...) is explicitly
listed in `platform-admin`'s policy; `reins/*` wasn't, since the policy
predates the mount. Fixed by adding a `path "reins/*" {...}` block
matching the existing entries exactly. **Process gap, not just a code
bug:** `build_approle_kv_lane` creates the *consumer's* policy/AppRole
but never checks whether the *founder's own* admin policy can reach a
brand-new mount — worth a follow-up task to check this automatically
for any future plan that creates a new mount, not just this one.
- **The generated policy used the wrong path shape for a KV v2 mount.**
`_policy_hcl` wrote `path "reins/rein-openweights/openrouter"` — the
bare, KV-v1-shaped path. KV v2 routes actual reads/writes through
`<mount>/data/<path>` (with a separate `<mount>/metadata/<path>` for
version operations); a policy against the bare path silently denies
everything on a v2 mount. `bao token capabilities` on the bare path
had even reported full access earlier in this build — misleading,
since OpenBao evaluates the real request against the `data/`-prefixed
path, not whatever a caller checks capabilities against. Caught when
the AppRole's own `kv get` 403'd during the live `GLAS-WP-0002-T02`
verification. Fixed in `ops_mason/executor.py::_policy_hcl` (now
emits both `data/` and `metadata/` sub-paths) and re-applied to the
live policy; a dedicated unit test
(`test_policy_hcl_uses_kv_v2_data_and_metadata_paths`) locks the
correct shape in for every future plan.
**Live end-to-end verification succeeded (2026-07-27)** after both
fixes: real AppRole login → real KV v2 read via the corrected policy →
real OpenRouter API call → real 2-turn tool-calling loop → real commit
(`e30d520c79a3493aeea5e8ea4d5ec331512b781d`), with `OPENROUTER_API_KEY`
unset the whole time — the vault round trip, not the env-var
short-circuit, is what ran. `glas-harness/GLAS-WP-0002-T02` is closed by
this.
**Plan status: catalogued** — ops-warden entry promoted `draft` ->
`active` (see that repo's commit history).