ops-mason/workplans/MASON-WP-0001-foundation.md
tegwick 2b83324c01 Bind OpenBao builds to approved inputs and secure credential delivery
Assistant: codex
Assistant-Model: gpt-6-astra
Assistant-Session: 01a0e75a-fc5c-7913-9dba-9846210c766d
2026-09-28 11:55:39 +02:00

205 lines
10 KiB
Markdown

---
id: MASON-WP-0001
type: workplan
title: "Foundation: the four-phase construction process, exercised on a real demand"
status: finished
state_hub_workstream_id: "fa60e81b-19f6-4ad5-a584-f049cdec1bdb"
---
First workplan for ops-mason. Stands up the four phases described in
`INTENT.md` — construction plan, review/optimize, executive summary,
build — and exercises the whole pipeline on one real, already-waiting
piece of demand: the `rein-openweights` OpenBao AppRole
(`glas-harness/workplans/GLAS-WP-0002-T02`, currently blocked on exactly
the mechanic this repo exists to formalize). That task is not busywork
invented for this workplan — it's real backlog this pipeline unblocks
the moment phase 4 lands.
## Task: Construction-plan format
Design the artifact phase 1 produces: demand description (consumer,
credential type, scope requested), an existing-structure survey (what
`bao policy list`/`bao auth list`/`bao secrets list`/ops-warden's
`registry/routing/catalog.yaml` already cover, and whether any of it
already satisfies the demand), and the proposed changes (create/modify/
tear-down, each with a stated reuse-vs-new rationale). Document in
`docs/construction-plan-format.md`. Plain, versioned markdown/YAML —
not a database — so a plan can be reviewed in a diff and stored next to
the workplan that requested it.
**Done (2026-07-27).** `docs/construction-plan-format.md`: one file per
plan at `plans/<id>.md`, YAML frontmatter (`status: draft -> reviewed ->
approved -> built -> catalogued`, the phase-4 hard gate), six body
sections (demand, existing-structure survey, proposed changes, phase-2
review notes, phase-3 executive summary, phase-4 build result) — one
document threaded through all four phases, not four separate artifacts.
Proven against a real demand, not a synthetic one:
`plans/rein-openweights-openrouter-approle.md`, phases 1-2 filled in —
including a genuine finding in the existing-structure survey (an
existing `openrouter-llm-connect` catalog lane that could theoretically
be reused, and an explicit, reasoned decision *not* to reuse it, scoped
narrowly instead). Phases 3-4 wait on `MASON-WP-0001-T03`/`T04`/`T05`.
```task
id: MASON-WP-0001-T01
status: done
priority: high
state_hub_task_id: "6b25e7ca-52a0-41c2-b5a0-b5e46c824264"
```
## Task: Review/optimize pass
A self-check phase 2 runs over a draft plan before it's shown to
anyone: flag likely-redundant new policies/roles against what already
exists, naming/TTL/scoping convention drift against established lanes
(e.g. the `agent-harness-binky-mail` shape:
`token_ttl=15m`, `token_max_ttl=30m`, bounded `token_num_uses`), and
note any compaction opportunity (two existing lanes that could merge).
This can start as a checklist a human/agent runs manually against a
draft plan — doesn't need to be automated tooling on day one.
**Done (2026-07-27).** `docs/review-optimize-checklist.md`: six checks
(naming, TTL/scoping, redundancy, compaction, ease of use for the
consumer, posture) — manual for now, automating a checker deferred until
there's a second worked example to generalize from. Applied for real to
`plans/rein-openweights-openrouter-approle.md` §4 — including a
genuinely useful finding (`credentials.py` already expects exactly this
plan's path/delivery shape, zero code changes needed to consume it) and
one explicit posture assumption flagged rather than left silent
(`secret_id_ttl=0`, carried from `agent-harness-binky-mail`, surfaced
again in the executive summary for the approval decision to confirm).
```task
id: MASON-WP-0001-T02
status: done
priority: high
state_hub_task_id: "58a446fb-78d0-42b4-b10a-1119266b1016"
```
## Task: Executive-summary format
Design the phase 3 artifact: a short, decidable rendering of a reviewed
plan — who/what gets access to what, for how long, blast radius if the
credential leaks, and what it costs to reverse. This is the only
mandatory human checkpoint (`INTENT.md` design principle 3/4) — it must
be readable without knowing `bao` syntax. Document in
`docs/executive-summary-format.md`, with the rein-openweights AppRole
plan (task T05) as the worked example.
**Done (2026-07-27).** `docs/executive-summary-format.md`: six fixed
fields (one-line ask, who/what gets access, to what, for how long,
blast radius, cost to reverse) plus an explicit approve/reject/revise
decision — no `bao` syntax, no restating sections 1-4, no editorializing
beyond the plan's own reuse-vs-new conclusion. Rendered for real into
`plans/rein-openweights-openrouter-approle.md` §5 — ready for an actual
decision, not a mockup.
```task
id: MASON-WP-0001-T03
status: done
priority: medium
state_hub_task_id: "e37debfd-8a00-4780-b036-9376c6a10557"
```
## Task: Build executor
Phase 4: given an **approved** construction plan (explicit approval
marker set after the executive summary was reviewed), execute it against
OpenBao — policy write, AppRole creation, KV secret path creation
(**empty path/structure only — never a secret value**, see `INTENT.md`),
role_id/secret_id delivery to the consuming host, and a proposed
pointer-only ops-warden catalog entry (`warden_executes: false`, no
authored `steps`, `status: draft` — a normal commit/PR to the
`ops-warden` repo, not a live API call). Ends by naming the exact
`paste_once_provision` step the founder still needs to do (which path,
which field) — it does not attempt to fill the value itself. Must refuse
to run against an unapproved or missing-approval-marker plan — this is
the one place a bug is a real security incident, not a bad UX. Start
narrow: implement only the operations the first real plan (T05) needs,
not a general OpenBao automation framework.
**Done (2026-07-27).** `src/ops_mason/plan.py` (frontmatter parser +
`is_approved()`), `src/ops_mason/executor.py`
(`build_approle_kv_lane` — policy write, AppRole create,
role_id/secret_id delivery, never the KV path's value), `src/ops_mason/audit.py`
(metadata-only JSONL build log). 12 tests, all mocked at the `bao`
subprocess boundary (no live OpenBao access from this session — see
`GLAS-WP-0002-T02`'s original blocker). Explicitly verified: the refusal
gate never even calls `subprocess.run` when the plan isn't fully
approved (`test_refusal_never_calls_bao`); role_id/secret_id land as
`0600` files and never appear in a log line or exception message; the
policy HCL goes over stdin, never argv.
**Hardening follow-up (2026-09-28).** The existing build executor now binds
execution to a reviewed `build_spec` plus `approved_spec_sha256`, reloads the
approval before use, validates literal scope/token/binding inputs, and pins
existing policy contents. Credential files are exclusively created as 0600
inside caller-owned 0700 directories before issuance, with symlinks and
existing destinations refused. Command errors suppress sensitive output.
Historical build approvals were not rewritten and no live lane was changed.
The suite passes 108 tests, including refusal-before-mutation, policy drift,
permissive-umask, symlink/hardlink/overwrite and error-output regressions.
The source contract and recovery limitations are documented in
`docs/construction-plan-format.md`. This is maintenance of T04, not a new task.
```task
id: MASON-WP-0001-T04
status: done
priority: high
state_hub_task_id: "e949f4b7-5ef4-4e42-8a07-61b6c8040298"
```
## Task: First real build — rein-openweights OpenBao AppRole
Run the whole pipeline for real: construction plan for
Option B from `glas-harness/workplans/GLAS-WP-0002-T02` (dedicated
`rein-openweights` AppRole + KV secret path at
`reins/rein-openweights/openrouter`, mirroring `agent-harness-binky-mail`'s
shape) → review/optimize → executive summary → founder approval → build
(structure only). Build ends with the founder pasting the real
OpenRouter key through ops-warden's `paste_once_provision` desk into the
newly created path/field — that one paste is the only place the live
value exists outside OpenBao. Once done, notify `glas-harness`/
`rein-openweights` so `GLAS-WP-0002-T02`'s live OpenBao verification can
proceed.
**Done (2026-07-27), all four phases run for real.** Founder logged in
(`bao login -method=oidc -path=netkingdom role=platform-admin` — the
initial bare `-method=oidc` 403'd against the wrong default mount path;
`netkingdom` + an explicit `role=` was required, found via
`ops-warden`'s own catalog/wiki conventions). Executed
`build_approle_kv_lane` for real:
- **Live-state discrepancy found and handled correctly, not silently:**
no `reins/` KV mount existed (`bao secrets list` showed only
`platform/`/`secret/`/`tenants/`) — a bigger action (new secrets
engine) than the executive summary's blast-radius framing disclosed.
Paused and got explicit founder confirmation before mounting, rather
than substituting a different path or proceeding unilaterally.
- **Built:** `reins/` KV v2 mount, policy
`workload-kv-read-rein-openweights-openrouter`, AppRole
`rein-openweights`, role_id/secret_id delivered to
`~/.local/rein-openweights/approle/` (`0600`).
- **Real bug caught and fixed, root cause and all:** built with
`token_num_uses=0` (OpenBao's own default = *unlimited*) instead of the
plan's own stated `8` — caught by comparing the live AppRole config
against `agent-harness-binky-mail`'s immediately after building, fixed
live (`bao write ... token_num_uses=8`) and in code
(`AppRoleKVSpec.token_num_uses` now has no default — must be passed
explicitly, so this can't recur silently).
- **Catalog entry landed:** `ops-warden` commit `c0a50bc` — and while
writing it, corrected a real misreading in this repo's own `INTENT.md`
of the no-double-source rule (pointer *fields* like `auth_method`/
`fetch_command`/`rotation.steps` are normal on non-SSH entries; only a
bare top-level `steps:`+`cert_command:` pair is SSH-only) — verified
against `ops-warden`'s full 326-test suite, green.
- Plan file `status: built`; catalog entry `status: draft` until the
founder's paste-once-provision + `GLAS-WP-0002-T02`'s live
verification succeed.
```task
id: MASON-WP-0001-T05
status: done
priority: high
state_hub_task_id: "01782608-aa5a-4f9b-a1fb-9a64f6d9c299"
```