ops-mason/workplans/MASON-WP-0015-construct-grant.md
tegwick e7a368af0f MASON-IN-0005: restore ops-mason as the OpenBao builder (ops-mason-construct)
Founder decision 2026-10-18, "build, but never log in": a plan-scoped grant
that writes workload-kv-read-* policies, external-secrets-* and AppRole role
definitions, and create-only placeholder KV under platform/{workloads,suppliers},
and denies role-id, secret-id, token creation and all value reads, so the
MASON-IN-0004 chain stays broken. Adds bao-session.sh build, policy tests,
INTENT/AGENTS alignment and MASON-WP-0015. Not installed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 278674@bnt-lap001
Assistant-Session: 64827407-e196-4ce3-b70c-76e7b537493f
2026-10-18 11:48:27 +02:00

3.5 KiB

id type title domain repo status owner topic_slug created updated flavor depends_on
MASON-WP-0015 workplan Restore ops-mason as the OpenBao builder: the ops-mason-construct grant infotech ops-mason active claude netkingdom-security-architecture 2026-10-18 2026-10-18 implementation

ops-mason-construct grant

Decision: intakes/intakes.md MASON-IN-0005 (founder, 2026-10-18, "Build, but never log in"). ops-mason builds structure in OpenBao; ops-warden finds and provides it. The grant breaks the MASON-IN-0004 chain at the login step.

Review both INTENTs and draft the grant

id: MASON-WP-0015-T01
status: done
priority: high

Reviewed ops-mason and ops-warden INTENT.md. The bodies agree (ops-mason builds, ops-warden routes and assists); the read-only grant did not. Wrote policies/ops-mason-construct.hcl and tests/test_construct_policy.py, added bao-session.sh build <task>, and updated INTENT.md frontmatter and the AGENTS.md OpenBao section.

Install the policy (founder act)

id: MASON-WP-0015-T02
status: todo
priority: high

Same silent wrapper and hash receipt as the survey policy (AGENTS.md), with ops-mason-construct and /home/worsch/ops-mason/policies/ops-mason-construct.hcl. Confirm your OIDC session can mint a token carrying it (bao-session.sh build MASON-WP-0015-T03).

Live negative and positive tests

id: MASON-WP-0015-T03
status: wait
priority: high

Under the build grant, against throwaway names (workload-kv-read-mason-probe, external-secrets-mason-probe, platform/suppliers/mason/probe): policy and role create/delete succeed; a role with token_policies=default, or with legacy policies, is refused (this confirms glob support in allowed_parameters); role-id read, secret-id write, token create, data read, and a write over the existing probe path are all refused; a policy write outside workload-kv-read-* is refused. Record the results as a names-only receipt. If the glob check fails, stop and redesign the role stanzas before any build.

Executor and post-build check

id: MASON-WP-0015-T04
status: todo
priority: high

src/ops_mason/executor.py build_approle_kv_lane mints the role-id and secret-id itself (lines ~420-426). Split it so that it stops after the role definition and emits the founder delivery step. Add a post-build check that reads each written policy and compares it with the plan's policy file (normalising the trailing newline). Run the check in every build; a mismatch fails the build record.

Align ops-warden and railiance-platform references

id: MASON-WP-0015-T05
status: todo
priority: medium

ops-warden registry/routing/catalog.yaml and wiki/playbooks/openbao-structure-survey.md describe ops-mason as read-only. The railiance-platform references are in docs/credential-lane-designs/application-backup-delivery-2026-10-08.md and RPF-WP-0053 and RPF-WP-0057. Message each owner with MASON-IN-0005, pointers only. They edit their own files.

Close the Kubernetes variant

id: MASON-WP-0015-T06
status: todo
priority: medium

A Kubernetes role ops-mason builds can be logged in to by anyone holding a token for the bound ServiceAccount. Confirm that the kube identity ops-mason applies with cannot create serviceaccounts/token or Pods in namespaces it binds roles to (kubectl auth can-i). kubernetes_plane already refuses the Pod and Secret kinds. Record the result in INTENT.md's kubernetes-plane-apply entry.