docs/review-optimize-checklist.md: six checks (naming, TTL/scoping,
redundancy, compaction, ease of use, posture), applied for real to the
rein-openweights plan's section 4 -- including a genuinely useful
finding (credentials.py already expects this exact path/delivery shape,
zero code changes needed to consume it).
docs/executive-summary-format.md: six fixed fields, no bao syntax, no
restating earlier sections, explicit approve/reject/revise decision.
Rendered for real into the plan's section 5 -- ready for an actual
decision.
src/ops_mason/{plan,executor,audit}.py: the phase-4 build executor for
credential_type openbao-approle-kv. Refuses to run against anything but
an approved plan -- verified the refusal never even calls subprocess.run.
role_id/secret_id (the AppRole's own access credential, not the
downstream secret) land as 0600 files, never logged; the HCL policy
goes over stdin, never argv; the audit trail is metadata-only. 12 tests,
all mocked at the bao boundary (no live OpenBao access from this
session).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
155 lines
8.5 KiB
Markdown
155 lines
8.5 KiB
Markdown
---
|
|
id: rein-openweights-openrouter-approle
|
|
demand_source: glas-harness/workplans/GLAS-WP-0002-T02
|
|
consumer_repo: rein-openweights
|
|
credential_type: openbao-approle-kv
|
|
status: reviewed
|
|
approved_by: null
|
|
approved_at: null
|
|
created: "2026-07-27"
|
|
updated: "2026-07-27"
|
|
---
|
|
|
|
# Construction plan: rein-openweights OpenBao AppRole
|
|
|
|
## 1. Demand
|
|
|
|
`rein-openweights` (the OpenRouter-driven rein in the glas-harness family)
|
|
needs to authenticate to OpenBao **non-interactively** — no operator OIDC
|
|
session, no human in the loop at run time — to fetch its OpenRouter API
|
|
key when it runs unattended (e.g. via a future scheduled trigger, or a
|
|
glas-harness gateway invocation with no operator present). This was
|
|
scoped as `glas-harness/GLAS-WP-0002-T02` ("Option B" — see that
|
|
workplan's discussion) and is currently blocked: the only credential path
|
|
exercised so far is the `OPENROUTER_API_KEY` env-var short-circuit in
|
|
`rein_openweights/credentials.py`; the AppRole/vault branch
|
|
(`_acquire_token`, `bao kv get`) is real code, live-verifiable, but has
|
|
never actually talked to OpenBao.
|
|
|
|
## 2. Existing-structure survey
|
|
|
|
**Checked:** `ops-warden/registry/routing/catalog.yaml` (readable directly
|
|
— no OpenBao session needed for this). **Not checked:** live `bao policy
|
|
list` / `bao auth list` / `bao secrets list` — this session has no valid
|
|
OpenBao token (`bao token lookup` returns `403`). Whoever executes phase 4
|
|
must re-verify against live state before applying anything below; this
|
|
survey is current as of what's on disk, not as of live OpenBao ACL state.
|
|
|
|
**Relevant existing catalog entry: `openrouter-llm-connect`**
|
|
(`ops-warden/registry/routing/catalog.yaml:283`) — an OpenRouter key
|
|
already exists at
|
|
`platform/workloads/activity-core/llm-connect/llm-connect-provider-secrets`
|
|
(field `OPENROUTER_API_KEY`), gated by policy
|
|
`workload-kv-read-llm-connect-provider-secrets`, `auth_method: caller's
|
|
own OpenBao token (operator OIDC via key-cape, or a token carrying
|
|
[that policy])`, marked `risk: high` ("provider API key with spend impact").
|
|
`rein-aharness`'s own mail-triage/brief-daily already reuse this exact
|
|
lane (see `binky-control/integrations/executor-worker-secrets.md`, Lane 1
|
|
— "REUSE (verified)").
|
|
|
|
**Does this existing lane satisfy the demand? Partially, by design, not
|
|
fully — reuse considered and declined:**
|
|
|
|
- The existing lane's `auth_method` is interactive-caller-shaped (OIDC /
|
|
"a token carrying the policy") — it was never scoped for a bare AppRole
|
|
login the way `agent-harness-binky-mail`'s Lane 3 was. Binding a new
|
|
AppRole to the *existing* policy is mechanically possible (Option A
|
|
from the original discussion) but would give `rein-openweights`
|
|
standing, non-interactive access to a policy explicitly flagged
|
|
`risk: high` for spend impact, shared with `activity-core`'s broader
|
|
usage — a wider blast radius than a single rein needs.
|
|
- **Recommendation: do not reuse.** Build a dedicated, narrowly-scoped
|
|
AppRole + KV path for `rein-openweights` specifically (matches
|
|
`credentials.py`'s existing default `reins/rein-openweights/openrouter`
|
|
path already in the code) — same reasoning `agent-harness-binky-mail`
|
|
used for its own dedicated lane rather than widening an existing one.
|
|
This keeps a leak scoped to exactly one consumer, one credential.
|
|
|
|
## 3. Proposed changes
|
|
|
|
| # | Action | Object | Reuse-vs-new rationale |
|
|
|---|---|---|---|
|
|
| 1 | create | KV v2 secret path `reins/rein-openweights/openrouter` (field `api_key`) | New, narrowly scoped — matches `credentials.py`'s existing default path; declined reuse of the shared `activity-core` path (see §2) |
|
|
| 2 | create | Policy `workload-kv-read-rein-openweights-openrouter` — read-only, scoped to exactly path #1 | New — mirrors the shape of `workload-kv-read-llm-connect-provider-secrets` but scoped to one path, not shared |
|
|
| 3 | create | AppRole `rein-openweights`, bound to policy #2 | New — mirrors `agent-harness-binky-mail`'s AppRole shape: `token_ttl=15m`, `token_max_ttl=30m`, bounded `token_num_uses`, `secret_id_ttl` per current posture (build-phase; see `ops-warden/wiki/WorkloadSecurityPosture.md`) |
|
|
| 4 | deliver | `role_id`/`secret_id` files, `0600`, to wherever the live verification runs (workstation or a future Railiance deployment) | New — matches `agent-harness-binky-mail`'s delivery pattern (`~/.local/agent-harness/approle-binky-mail`), analogous path for this consumer |
|
|
| 5 | propose | ops-warden catalog entry `rein-openweights-openrouter-approle` — pointer-only, `warden_executes: false`, `status: draft` | New — no existing entry covers this AppRole; `openrouter-llm-connect` entry stays as-is, untouched |
|
|
|
|
No tear-down in this plan — no existing lane is being retired or
|
|
compacted; the existing `openrouter-llm-connect` lane is explicitly kept
|
|
as-is for its current interactive-caller consumers.
|
|
|
|
## 4. Review notes (phase 2)
|
|
|
|
- **Naming convention check:** follows `<consumer>-<credential-purpose>`
|
|
shape used by `agent-harness-binky-mail` — proposed
|
|
`rein-openweights-openrouter-approle` for the AppRole/catalog id,
|
|
`workload-kv-read-rein-openweights-openrouter` for the policy (matches
|
|
the `workload-kv-read-<path-slug>` convention already visible in the
|
|
existing catalog).
|
|
- **TTL/scoping check:** `token_ttl=15m`/`token_max_ttl=30m`/bounded
|
|
`token_num_uses` matches `agent-harness-binky-mail` exactly — no reason
|
|
to diverge, this consumer's access pattern (one-shot credential fetch
|
|
per run) is identical in shape.
|
|
- **Redundancy check:** confirmed no second existing AppRole or policy
|
|
already scoped to `reins/rein-openweights/*` — this is genuinely new
|
|
structure, not a duplicate.
|
|
- **Compaction opportunity:** none identified — nothing existing becomes
|
|
redundant once this lands; the shared `activity-core` lane keeps its
|
|
own consumers.
|
|
- **Ease of use for the consumer:** matches directly — `credentials.py`
|
|
already reads `REIN_OPENWEIGHTS_APPROLE_DIR` (defaults to a
|
|
`role_id`/`secret_id` file pair) and a KV path override via
|
|
`REIN_OPENWEIGHTS_OPENROUTER_KV_PATH` (defaulting to exactly
|
|
`reins/rein-openweights/openrouter`, field `api_key`) — this plan's
|
|
path #1 and delivery #4 need **zero code changes** in
|
|
`rein-openweights` to consume; the code was already written expecting
|
|
this exact shape.
|
|
- **Posture check:** build phase (one founder-operator, pre-revenue) per
|
|
`ops-warden/wiki/WorkloadSecurityPosture.md` — `agent-harness-binky-mail`
|
|
used `secret_id_ttl=0` (no expiry) at this same posture; carrying that
|
|
forward here rather than adding a rotation schedule neither
|
|
`agent-harness-binky-mail` nor current posture requires. **Explicit
|
|
assumption, not a silent default** — flagged again in the executive
|
|
summary below for the approval decision to confirm or override.
|
|
|
|
## 5. Executive summary (phase 3)
|
|
|
|
**One-line ask:** create a narrowly-scoped, non-interactive credential
|
|
lane so `rein-openweights` can fetch its own OpenRouter API key at run
|
|
time without an operator present.
|
|
|
|
**Who/what gets access:** a new OpenBao AppRole named `rein-openweights`.
|
|
Nothing else — no existing role, human, or service gains anything new.
|
|
|
|
**To what:** read-only access to exactly one KV path,
|
|
`reins/rein-openweights/openrouter` (field `api_key`) — a path that does
|
|
not exist today and holds nothing else. The AppRole cannot read the
|
|
existing shared `activity-core`/`llm-connect` secret or any other path.
|
|
|
|
**For how long:** each login is a 15-minute token, renewable up to a
|
|
30-minute cap, bounded number of uses per token — matches the existing
|
|
`agent-harness-binky-mail` lane exactly. The AppRole credential itself
|
|
(`role_id`/`secret_id`) does not expire on a schedule at current
|
|
(build-phase) posture, same choice already made for
|
|
`agent-harness-binky-mail`.
|
|
|
|
**Blast radius if the credential leaks:** whoever holds a valid
|
|
`role_id`/`secret_id` pair can mint a short-lived token that reads one
|
|
OpenRouter API key — nothing else in OpenBao. Actual damage from the
|
|
OpenRouter key itself is real but bounded (API spend on that key, no
|
|
data-store or infra access) and independent of this plan (same exposure
|
|
`openrouter-llm-connect`'s existing consumers already carry).
|
|
|
|
**Cost to reverse:** delete one AppRole, one policy, one KV path — three
|
|
`bao` commands, no other lane or consumer affected. Fully isolated
|
|
blast/reversal radius by construction (that was the point of declining
|
|
reuse in §2).
|
|
|
|
**Decision needed:** approve as proposed, reject, or send back to phase 1
|
|
with feedback (e.g. different TTL, different path name, or "actually
|
|
reuse the shared lane instead").
|
|
|
|
## 6. Build result (phase 4)
|
|
|
|
<!-- Appended once MASON-WP-0001-T04/T05 execute this plan after approval. -->
|