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

10 KiB

id type title status state_hub_workstream_id
MASON-WP-0001 workplan Foundation: the four-phase construction process, exercised on a real demand finished 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.

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).

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.

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.

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.
id: MASON-WP-0001-T05
status: done
priority: high
state_hub_task_id: "01782608-aa5a-4f9b-a1fb-9a64f6d9c299"