docs/construction-plan-format.md: one file per plan (plans/<id>.md), frontmatter status tracker (draft -> reviewed -> approved -> built -> catalogued, the phase-4 hard gate), six body sections threading all four phases through one document. Proven against real demand: plans/rein-openweights-openrouter-approle.md, phases 1-2 filled in. Found and reasoned through a real existing-structure question along the way -- the openrouter-llm-connect catalog lane could technically be reused, but its auth_method is interactive-caller-shaped and its policy is shared/high-risk; recommends a dedicated, narrowly scoped AppRole instead, same reasoning agent-harness-binky-mail used for its own dedicated lane. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
6.2 KiB
| id | demand_source | consumer_repo | credential_type | status | approved_by | approved_at | created | updated |
|---|---|---|---|---|---|---|---|---|
| rein-openweights-openrouter-approle | glas-harness/workplans/GLAS-WP-0002-T02 | rein-openweights | openbao-approle-kv | draft | null | null | 2026-07-27 | 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_methodis interactive-caller-shaped (OIDC / "a token carrying the policy") — it was never scoped for a bare AppRole login the wayagent-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 giverein-openweightsstanding, non-interactive access to a policy explicitly flaggedrisk: highfor spend impact, shared withactivity-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-openweightsspecifically (matchescredentials.py's existing defaultreins/rein-openweights/openrouterpath already in the code) — same reasoningagent-harness-binky-mailused 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 byagent-harness-binky-mail— proposedrein-openweights-openrouter-approlefor the AppRole/catalog id,workload-kv-read-rein-openweights-openrouterfor the policy (matches theworkload-kv-read-<path-slug>convention already visible in the existing catalog). - TTL/scoping check:
token_ttl=15m/token_max_ttl=30m/boundedtoken_num_usesmatchesagent-harness-binky-mailexactly — 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-corelane keeps its own consumers. - Open item carried into phase 3/4: confirm current build-phase
posture (
ops-warden/wiki/WorkloadSecurityPosture.md) still supportssecret_id_ttl=0(no expiry, matchingagent-harness-binky-mail's choice) rather than a rotation schedule — note this explicitly in the executive summary rather than assuming it silently.