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
This commit is contained in:
parent
e2ac6448c2
commit
e7a368af0f
7 changed files with 406 additions and 21 deletions
68
tests/test_construct_policy.py
Normal file
68
tests/test_construct_policy.py
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
"""ops-mason-construct can build a lane but never log in as one (MASON-IN-0005)."""
|
||||
|
||||
import re
|
||||
from pathlib import Path
|
||||
|
||||
POLICY = Path(__file__).resolve().parents[1] / "policies" / "ops-mason-construct.hcl"
|
||||
|
||||
|
||||
def _stanzas() -> dict[str, str]:
|
||||
text = "\n".join(line.split("#", 1)[0] for line in POLICY.read_text().splitlines())
|
||||
return {
|
||||
m.group(1): m.group(2)
|
||||
for m in re.finditer(r'path\s+"([^"]+)"\s*\{(.*?)\n?\s*\}\s*(?=path|\Z)', text, re.S)
|
||||
}
|
||||
|
||||
|
||||
def _caps(body: str) -> set[str]:
|
||||
m = re.search(r"capabilities\s*=\s*\[([^\]]*)\]", body)
|
||||
return set(re.findall(r'"(\w+)"', m.group(1))) if m else set()
|
||||
|
||||
|
||||
def test_login_and_value_paths_are_denied():
|
||||
stanzas = _stanzas()
|
||||
for path in [
|
||||
"auth/approle/role/+/role-id",
|
||||
"auth/approle/role/+/secret-id",
|
||||
"auth/approle/role/+/secret-id/*",
|
||||
"auth/approle/role/+/custom-secret-id",
|
||||
"auth/token/create",
|
||||
"auth/token/create/*",
|
||||
"auth/token/create-orphan",
|
||||
"platform/data/*",
|
||||
"operators/data/*",
|
||||
"secret/data/*",
|
||||
"sys/policies/acl/ops-mason-construct",
|
||||
"sys/policies/acl/ops-mason-survey",
|
||||
"sys/policies/acl/default",
|
||||
"sys/policies/acl/root",
|
||||
]:
|
||||
assert _caps(stanzas[path]) == {"deny"}, path
|
||||
|
||||
|
||||
def test_kv_data_is_create_only():
|
||||
stanzas = _stanzas()
|
||||
for path in ["platform/data/workloads/*", "platform/data/suppliers/*"]:
|
||||
assert _caps(stanzas[path]) == {"create"}, path
|
||||
for path, body in stanzas.items():
|
||||
if "/data/" in path:
|
||||
assert not _caps(body) & {"read", "update", "list"}, path
|
||||
|
||||
|
||||
def test_policy_writes_limited_to_workload_read_prefix():
|
||||
for path, body in _stanzas().items():
|
||||
if path.startswith("sys/policies/acl/") and _caps(body) & {"create", "update", "delete"}:
|
||||
assert path == "sys/policies/acl/workload-kv-read-*", path
|
||||
|
||||
|
||||
def test_role_writes_restrict_token_policies():
|
||||
for path, body in _stanzas().items():
|
||||
if path.startswith("auth/") and "/role/" in path and _caps(body) & {"create", "update"}:
|
||||
assert '"token_policies" = ["workload-kv-read-*"]' in body, path
|
||||
assert re.search(r'denied_parameters\s*=\s*\{\s*"policies"\s*=\s*\[\]', body), path
|
||||
|
||||
|
||||
def test_no_mount_or_auth_method_writes():
|
||||
for path, body in _stanzas().items():
|
||||
if path.startswith(("sys/mounts/", "sys/auth/")):
|
||||
assert _caps(body) <= {"read", "list", "deny"}, path
|
||||
Loading…
Add table
Add a link
Reference in a new issue