Name a dedicated reuse-surface hub-writer caller.

CCR-2026-0005 does not name a principal, and the platform-admin entity must not receive the workload policy. Add the draft role, verifier, and plan, drop the retired operators/nextcloud description, and record that tegwick's MFA factor is enrolled.

Assistant: grok
Assistant-Session: 01a13b2d-5f6d-7a32-b2c9-384625c55ca6
This commit is contained in:
tegwick 2026-10-14 18:19:14 +02:00
parent 6434877a44
commit fd2c5a5904
12 changed files with 841 additions and 17 deletions

View file

@ -0,0 +1,109 @@
id: CCR-DRAFT-REUSE-SURFACE-HUB-WRITER
kind: credential-change-request
schema_version: 1
request_type: workload-kv-read
title: Name the dedicated reuse-surface hub-writer caller
status: proposed
created: '2026-10-14'
updated: '2026-10-14'
requester:
agent: ops-mason
reason: 'CUST-WP-0081 / State Hub message 08b254af. CCR-2026-0005 is active and
does not name a caller. Entity 4a1f663c-0621-0483-edd0-f852274f4b6b carries
default, operator-custody and platform-admin, so its token can reach the data
path, the metadata path and siblings. Do not attach workload-kv-read-reuse-surface-runtime
to that entity. Bind a new OIDC role to a different principal. No secret value
is rotated or read by this request.'
review:
required: true
required_approvers:
- platform-operator
- reuse-surface-owner
comments: []
target:
domain: financials
tenant: reuse
workload: reuse-surface
environment: production
purpose: Attended read of the existing hub writer token by one dedicated caller.
openbao:
mount: platform
kv_path: platform/workloads/reuse/reuse-surface/runtime-secrets
fields:
- REUSE_SURFACE_TOKEN
- REUSE_SURFACE_FORGEJO_WEBHOOK_SECRET
policy_name: workload-kv-read-reuse-surface-runtime
policy_file: openbao/policies/workload-kv-read-reuse-surface-runtime.hcl
metadata_read: true
token_self_lifecycle: true
auth:
method: oidc
mount: netkingdom
role: reuse-surface-hub-writer-workload-kv-read
allowed_redirect_uris:
- http://localhost:8250/oidc/callback
- http://127.0.0.1:8250/oidc/callback
- http://127.0.0.1:18200/ui/vault/auth/netkingdom/oidc/callback
oidc_scopes:
- openid
- profile
- email
- groups
user_claim: sub
groups_claim: groups
bound_claims_type: string
bound_claims:
groups:
- reuse-surface-hub-writers
/assurance/level: aal2
bound_claims_confirmed: false
policies:
- workload-kv-read-reuse-surface-runtime
ttl: 15m
token_max_ttl: 30m
token_explicit_max_ttl: 30m
token_no_default_policy: true
token_type: service
access_frontdoor:
type: ops-warden
catalog_id: reuse-surface-hub-write-token
selector: reuse-surface federation hub write bearer token
command: 'After a passing member receipt, run warden access reuse-surface-hub-write-token
--exec --field REUSE_SURFACE_TOKEN -- <silent helper> with the unprinted lane
token. Do not use --fetch.'
resolvable: false
readiness: pending-review
risk:
classification: high
notes:
- REUSE_SURFACE_TOKEN writes to the production federation hub. This request does
not read or rotate it.
- The platform-admin entity must not receive this policy. OpenBao merges entity
policies into every token for that entity.
- The ESO policy workload-kv-read-reuse-surface-runtime-eso stays on its Kubernetes
role. This role does not attach it.
- bound_claims_confirmed stays false until key-cape confirms group reuse-surface-hub-writers
and a member entity other than 4a1f663c-0621-0483-edd0-f852274f4b6b.
- Public bao.coulomb.social ingress is not a callback. Use the workstation tunnel.
verification:
positive:
- A member token's policy set is exactly workload-kv-read-reuse-surface-runtime.
- That token's capabilities are read on the exact data path and the exact metadata path.
negative:
- The same token is deny on platform/data/workloads/reuse/reuse-surface, its metadata
parent, and platform/data/workloads/issue-core/issue-core/issue-core-runtime.
- A principal outside reuse-surface-hub-writers is refused by the role.
- Entity 4a1f663c-0621-0483-edd0-f852274f4b6b is not the member token's entity.
activation_conditions:
- platform-operator and reuse-surface-owner approve this caller binding.
- key-cape confirms the group and that the member entity has no platform-admin or
operator-custody identity policy.
- Founder applies policy and role through the delegated applier. No KV write.
- scripts/verify-reuse-surface-hub-writer.py member and non-member both pass.
Receipts stay mode 0600 and contain no token or field value.
lifecycle:
deactivate: delete auth/netkingdom/role/reuse-surface-hub-writer-workload-kv-read.
Leave the KV path, the ESO role, and CCR-2026-0005 delivery in place.
rotate: unchanged from CCR-2026-0005. This request does not rotate field values.
compromised: detach the role, revoke outstanding tokens for the role, and follow
the CCR-2026-0005 compromise procedure if a field value was exposed.

View file

@ -0,0 +1,23 @@
{
"role_type": "oidc",
"allowed_redirect_uris": [
"http://localhost:8250/oidc/callback",
"http://127.0.0.1:8250/oidc/callback",
"http://127.0.0.1:18200/ui/vault/auth/netkingdom/oidc/callback"
],
"oidc_scopes": ["openid", "profile", "email", "groups"],
"user_claim": "sub",
"groups_claim": "groups",
"bound_claims_type": "string",
"bound_claims": {
"groups": ["reuse-surface-hub-writers"],
"/assurance/level": "aal2"
},
"token_policies": ["workload-kv-read-reuse-surface-runtime"],
"token_no_default_policy": true,
"token_type": "service",
"token_ttl": "15m",
"token_max_ttl": "30m",
"token_explicit_max_ttl": "30m",
"verbose_oidc_logging": false
}

View file

@ -0,0 +1,22 @@
# Caller policy for the reuse-surface hub writer.
# Exact data and metadata read. Sibling and parent paths are not granted.
# Self lookup and revoke match credential-change.py generated_policy_hcl when
# metadata_read and token_self_lifecycle are true. No capabilities-self grant:
# the attended verifier queries sys/capabilities with the operator token.
# Do not attach this policy to entity 4a1f663c-0621-0483-edd0-f852274f4b6b.
path "platform/data/workloads/reuse/reuse-surface/runtime-secrets" {
capabilities = ["read"]
}
path "platform/metadata/workloads/reuse/reuse-surface/runtime-secrets" {
capabilities = ["read"]
}
path "auth/token/lookup-self" {
capabilities = ["read"]
}
path "auth/token/revoke-self" {
capabilities = ["update"]
}

View file

@ -0,0 +1,30 @@
# reuse-surface hub-writer attended verification
Plan: `plans/reuse-surface-hub-writer.md`. Draft CCR:
`builds/reuse-surface-hub-writer/credential-change-requests/CCR-DRAFT-REUSE-SURFACE-HUB-WRITER.yaml`.
Run this only after the founder has applied the role and key-cape has
confirmed group `reuse-surface-hub-writers`. The member must not be OpenBao
entity `4a1f663c-0621-0483-edd0-f852274f4b6b`.
The script leaves `~/.vault-token` in place and uses it only to call
`sys/capabilities`. The lane token is not printed and is revoked before the
script exits. A passing receipt is the sanitized verification record.
```bash
export BAO_ADDR=http://127.0.0.1:18200
python3 scripts/verify-reuse-surface-hub-writer.py member
python3 scripts/verify-reuse-surface-hub-writer.py non-member
```
`member` passes when the token's policies are exactly
`workload-kv-read-reuse-surface-runtime`, the entity is not the admin entity,
the runtime-secrets data and metadata paths are `read`, the parent paths and
`platform/data/workloads/issue-core/issue-core/issue-core-runtime` are `deny`,
and revoke succeeded.
`non-member` passes when the role refuses the login. Use a private window so
an existing KeyCape session is not reused.
Do not run `bao kv get` on this path to prove the lane. Do not attach the
workload policy to the admin entity.

View file

@ -1,16 +1,3 @@
operators/nextcloud:
description: ''
missing:
- description
- used_by
- rotation
- on_loss
on_loss: ''
owner: railiance-platform
review: draft
rotation: ''
sources: []
used_by: ''
operators/nextcloud/backup:
description: Operator login (BACKUP_USERNAME, BACKUP_PASSWORD) for the dedicated Nextcloud Storage Share
account Backup on nx4069.your-storageshare.de, the independent secondary backup copy lane.
@ -501,9 +488,11 @@ platform/workloads/reuse/reuse-surface/runtime-secrets:
sources:
- CCR-2026-0005-reuse-surface-runtime-secrets-lane.yaml
- ops-warden catalog reuse-surface-hub-write-token
- ops-mason plan reuse-surface-hub-writer (MASON-WP-0011; role not applied)
used_by: ExternalSecret reuse/reuse-surface-runtime -> Secret reuse-surface-env; ClusterSecretStore
openbao-reuse uses private railiance01 OpenBao and exact reuse/reuse-surface-eso Kubernetes identity.
Caller-facing OIDC policy workload-kv-read-reuse-surface-runtime remains separately retained.
The dedicated caller is OIDC role reuse-surface-hub-writer-workload-kv-read, not the platform-admin entity.
platform/workloads/secrets-engine/approval-client:
description: Hold the secrets-engine-approval confidential client secret in platform custody and project
it into the KeyCape runtime so KeyCape can verify presented client_credentials without the value living

View file

@ -0,0 +1,166 @@
---
id: reuse-surface-hub-writer
demand_source: the-custodian/workplans/CUST-WP-0081 and State Hub message 08b254af-59d4-4d1a-9544-fed3dcaaf213
consumer_repo: reuse-surface
credential_type: openbao-oidc-kv-read
status: draft
approved_by: null
approved_at: null
created: "2026-10-14"
updated: "2026-10-14"
---
# Construction plan: dedicated reuse-surface hub-writer caller
## 1. Demand
CUST-WP-0081 needs to register reviewed capabilities at the reuse-surface hub.
The write bearer already exists at
`platform/workloads/reuse/reuse-surface/runtime-secrets`, field
`REUSE_SURFACE_TOKEN`, delivered to the hub by External Secrets under
CCR-2026-0005. `warden access reuse-surface-hub-write-token --exec` is the
attended fetch. On 2026-10-14 that fetch returned OpenBao HTTP 403 after
flex-auth decision `decision:f730e3da14beebdd`. The helper did not run.
The operator then confirmed OpenBao CLI entity
`4a1f663c-0621-0483-edd0-f852274f4b6b` carries `default`, `operator-custody`
and `platform-admin`. `bao token capabilities` on that token reports
create, delete, list, read and update on the exact data path, the exact
metadata path, and an unrelated sibling. That token is not a dedicated
caller. OpenBao adds entity policies to every token for the entity, so
attaching `workload-kv-read-reuse-surface-runtime` to this entity would not
produce a token that carries only that policy. The request forbids that
attachment and forbids sending any secret value.
## 2. Existing-structure survey
Live `plan-survey.py` was not run. There is no `ops-mason-survey` grant in
this session, and the admin token must not be used as the survey credential.
This section is from the repositories on disk at 2026-10-14.
- Policy `workload-kv-read-reuse-surface-runtime`
(`railiance-platform/openbao/policies/workload-kv-read-reuse-surface-runtime.hcl`)
grants read on the exact data path and the exact metadata path. It grants
nothing else. Sibling denial is the absence of any other grant. No auth
role in railiance-platform names this policy.
- ESO uses the separate policy `workload-kv-read-reuse-surface-runtime-eso`
and Kubernetes role `reuse-surface-runtime-eso` (CCR-2026-0005, updated
2026-09-05). That lane is the hub pod's delivery path, not the workstation
caller.
- `agent-high-risk-boundary` denies data read and allows metadata read on
this path for tokens that carry it. `platform-admin` grants `platform/*`.
A token with both would be denied on the data path, because deny wins.
The reported capability set does not include deny, so the 403 and the
capability report are not the same effective token. The verifier must
measure the token that `warden access` will actually use.
- Catalog entry `reuse-surface-hub-write-token` is active and
`resolvable: true`. Its `auth_method` says the caller's own OpenBao token,
either operator OIDC or a token carrying the workload policy. It does not
name a role or an entity. CCR-2026-0005 does not name one either.
- Redirects that use `https://bao.coulomb.social` are stale. The public
ingress is gone. Fluid-telegram's role uses localhost, 127.0.0.1:8250, and
the 127.0.0.1:18200 tunnel.
**Does an existing lane already satisfy this demand?** The KV path and the
read policy do. The caller binding does not. The change is a role bound to
a different principal, plus the two self-lifecycle stanzas the platform
generator emits for `token_self_lifecycle: true`. No new secret, no new KV
path, no change to the ESO role.
## 3. Proposed changes
SEC-DSM §37, in order:
- Q1. The hub still requires its existing bearer. Reading that bearer from
OpenBao can use a person or service identity. Do not create a secret to
stand in for the caller.
- Q2. OpenBao accepts OIDC on `auth/netkingdom`. Use that. A KeyCape group
selects the principal. The principal's OpenBao entity must not be
`4a1f663c-0621-0483-edd0-f852274f4b6b` and must not carry `platform-admin`
or `operator-custody`.
- Q3. The OpenBao token is a 15-minute service token from the role. The hub
bearer stays the static field already in KV. No new issuance layer.
- Q4. Rotation of the hub bearer stays CCR-2026-0005. This plan does not
rotate it.
- Q5. No new persistent secret. Owner of the binding is railiance-platform.
The consumer is the attended hub-registration helper. Authority is the
OIDC role. Delivery is `warden access --exec` with the lane token.
Revocation is `auth/token/revoke-self` and deletion of the role.
Preference hierarchy: federated identity for the read, existing vaulted
static bearer for the hub. Not a new static secret and not a new AppRole.
1. `modify` policy `workload-kv-read-reuse-surface-runtime`. Add
`auth/token/lookup-self` read and `auth/token/revoke-self` update. Leave
the two KV paths as read. Do not add a glob deny: in OpenBao a deny on a
prefix also denies the more specific path. Sibling denial remains "not
granted", checked on a parent path and on
`platform/data/workloads/issue-core/issue-core/issue-core-runtime`.
2. `create` OIDC role `auth/netkingdom/role/reuse-surface-hub-writer-workload-kv-read`.
`token_policies` is only the workload policy, `token_no_default_policy` is
true, TTL 15m, max 30m, group `reuse-surface-hub-writers`, assurance
`aal2`. Callbacks are the workstation URIs above.
3. `create` KeyCape group `reuse-surface-hub-writers` and one member whose
OpenBao entity is not the forbidden entity and has no admin identity
policies. key-cape owns that group. `bound_claims_confirmed` stays false
until they confirm it.
4. No KV write. No attachment of this policy, or of
`workload-kv-read-reuse-surface-runtime-eso`, to entity
`4a1f663c-0621-0483-edd0-f852274f4b6b`.
Artifacts: `builds/reuse-surface-hub-writer/`. The CCR id is a draft.
railiance-platform assigns the real id and applies it. ops-mason does not
install the policy or the role.
## 4. Review notes
The 403 is not evidence that the path is closed to every token. It is
evidence that the token `warden access` used could not read the field.
The later capability check describes a different, broader token. The member
receipt has to show both facts on one token: exact policy set, and deny on
a sibling. A pass on the admin entity is a failure.
`credential-change.py` will not keep a hand-written `sys/capabilities-self`
stanza. The verifier therefore asks `sys/capabilities` with the operator
token and puts the lane token only in a mode-0600 body file that it
deletes. The receipt never contains the token.
Catalog `reuse-surface-hub-write-token` stays active. This plan does not
ask ops-warden to vend the value. After both verifier modes pass, ops-warden
can name the role in `auth_method`. Until then the entry's caller is unnamed
and the draft front door stays `pending-review`.
## 5. Attended apply and proof
Founder, after platform-operator and reuse-surface-owner approval, and after
key-cape confirms the group:
1. Copy the policy file over
`railiance-platform/openbao/policies/workload-kv-read-reuse-surface-runtime.hcl`
and apply the CCR with the delegated applier. Do not run `bao kv put`.
2. Keep an operator token in `~/.vault-token` for the capability query.
In a private window, as the group member:
```bash
python3 scripts/verify-reuse-surface-hub-writer.py member
python3 scripts/verify-reuse-surface-hub-writer.py non-member
```
3. Receipts are mode 0600 under
`~/.local/state/railiance/receipts/reuse-surface-hub-writer-*.txt`.
Copy the sanitized text into
`docs/evidence/` only after both results are `pass`. That copy is the
verification receipt. It is not written in advance.
4. Reply to message `08b254af` with the receipt text. Then a registration
command may use the same role's unprinted token:
```bash
warden access reuse-surface-hub-write-token --exec --field REUSE_SURFACE_TOKEN -- <silent helper>
```
Set `BAO_TOKEN` to the lane token for that one command. Do not use `--fetch`.
Do not export the field. Revoke the lane token when the command returns.
## 6. Result
Not applied. No live receipt yet.

View file

@ -0,0 +1,212 @@
#!/usr/bin/env python3
"""Attended proof of the reuse-surface hub-writer caller.
./scripts/verify-reuse-surface-hub-writer.py member
./scripts/verify-reuse-surface-hub-writer.py non-member
Logs in on auth/netkingdom role reuse-surface-hub-writer-workload-kv-read with
``bao login -token-only``, so the operator's token helper is left alone. The
lane token stays in memory. Capability queries run as the operator token
already present in the environment or token helper, because the workload
policy has no sys/capabilities-self grant. The receipt records policies,
entity id, path capabilities, and pass/fail. It does not record the token or
any KV value.
Sign in with a private browser window. A reused platform-admin session is the
wrong principal for ``member``.
"""
from __future__ import annotations
import json
import os
import re
import stat
import subprocess
import sys
import tempfile
from datetime import datetime, timezone
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "src"))
from ops_mason.reuse_surface_hub_writer import (
DATA,
METADATA,
MUST_DENY,
PARENT_DATA,
PARENT_METADATA,
POLICY,
ROLE,
SIBLING,
assess,
)
BAO_ADDR = os.environ.get("BAO_ADDR", "http://127.0.0.1:18200")
TOKEN_RE = re.compile(r"\b(?:hvs|hvb|hvr)\.[A-Za-z0-9_-]{8,}\b")
PATHS = [DATA, METADATA, PARENT_DATA, PARENT_METADATA, SIBLING]
def redact(text: str) -> str:
return TOKEN_RE.sub("[redacted-token]", text or "")
def receipts_dir() -> Path:
home = Path(os.environ.get("HOME", str(Path.home())))
path = home / ".local/state/railiance/receipts"
path.mkdir(parents=True, mode=0o700, exist_ok=True)
return path
def operator_token() -> str:
for name in ("BAO_TOKEN", "VAULT_TOKEN"):
value = os.environ.get(name, "").strip()
if value:
return value
helper = Path(os.environ.get("HOME", str(Path.home()))) / ".vault-token"
if helper.is_file():
return helper.read_text(encoding="utf-8").strip()
return ""
def run_bao(args: list[str], token: str, stdin: str | None = None) -> subprocess.CompletedProcess[str]:
env = os.environ.copy()
env["BAO_ADDR"] = BAO_ADDR
env["BAO_TOKEN"] = token
env.pop("VAULT_TOKEN", None)
return subprocess.run(
["bao", *args],
input=stdin,
text=True,
capture_output=True,
env=env,
check=False,
)
def login() -> str:
proc = run_bao(
["login", "-token-only", "-method=oidc", "-path=netkingdom", f"role={ROLE}"],
token="",
)
token = (proc.stdout or "").strip()
if proc.returncode != 0 or not token or TOKEN_RE.fullmatch(token) is None:
sys.stderr.write(redact(proc.stderr or "login refused\n"))
return ""
return token
def lookup(token: str) -> dict:
proc = run_bao(["token", "lookup", "-format=json"], token)
if proc.returncode != 0:
raise RuntimeError(redact(proc.stderr or "token lookup failed"))
payload = json.loads(proc.stdout)
return payload.get("data") or payload
def capabilities(operator: str, lane: str) -> dict[str, list[str]]:
if not operator:
raise RuntimeError(
"no operator token for sys/capabilities "
"(BAO_TOKEN, VAULT_TOKEN, or ~/.vault-token)"
)
body = json.dumps({"token": lane, "paths": PATHS})
tmp = tempfile.NamedTemporaryFile("w", prefix="rs-caps-", delete=False)
try:
os.fchmod(tmp.fileno(), stat.S_IRUSR | stat.S_IWUSR)
tmp.write(body)
tmp.close()
proc = run_bao(["write", "-format=json", "sys/capabilities", f"@{tmp.name}"], operator)
finally:
try:
os.remove(tmp.name)
except OSError:
pass
if proc.returncode != 0:
raise RuntimeError(redact(proc.stderr or "sys/capabilities failed"))
payload = json.loads(proc.stdout)
data = payload.get("data") or payload
found: dict[str, list[str]] = {}
for path in PATHS:
value = data.get(path)
if isinstance(value, list):
found[path] = value
return found
def revoke(token: str) -> bool:
proc = run_bao(["token", "revoke", "-self"], token)
return proc.returncode == 0
def write_receipt(name: str, lines: list[str]) -> Path:
path = receipts_dir() / name
path.write_text("\n".join(lines) + "\n", encoding="utf-8")
path.chmod(0o600)
return path
def main(argv: list[str]) -> int:
mode = argv[1] if len(argv) > 1 else ""
if mode not in {"member", "non-member"}:
sys.stderr.write("usage: verify-reuse-surface-hub-writer.py member|non-member\n")
return 2
sys.stderr.write(
f"Sign in as the {mode} identity in a private browser window.\n"
"A platform-admin session is the wrong principal for member.\n"
)
operator = operator_token()
now = datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ")
lane = login()
report: dict = {
"mode": mode,
"login": "ok" if lane else "refused",
"policies": [],
"identity_policies": [],
"entity_id": "",
"capabilities": {},
"revoked": None,
}
try:
if lane:
info = lookup(lane)
report["policies"] = list(info.get("policies") or [])
report["identity_policies"] = list(info.get("identity_policies") or [])
report["entity_id"] = str(info.get("entity_id") or "")
if mode == "member":
report["capabilities"] = capabilities(operator, lane)
except (RuntimeError, json.JSONDecodeError, OSError) as exc:
report["error"] = redact(str(exc))
finally:
if lane:
report["revoked"] = revoke(lane)
lane = ""
failures = assess(report)
if report.get("error"):
failures = [report["error"], *failures]
lines = [
f"mode={mode}",
f"at={now}",
f"addr={BAO_ADDR}",
f"role={ROLE}",
f"policy={POLICY}",
f"login={report['login']}",
f"entity_id={report['entity_id']}",
"policies=" + ",".join(report["policies"]),
"identity_policies=" + ",".join(report["identity_policies"]),
]
for path in PATHS:
caps = (report["capabilities"] or {}).get(path)
shown = ",".join(caps) if isinstance(caps, list) else "not-run"
lines.append(f"{path}: {shown}")
lines.append("revoked=" + ("yes" if report["revoked"] else "no" if report["revoked"] is False else "n/a"))
lines.append("result=" + ("pass" if not failures else "fail"))
for item in failures:
lines.append("failure=" + item)
receipt = write_receipt(f"reuse-surface-hub-writer-{mode}.txt", lines)
sys.stderr.write(f"receipt: {receipt}\n")
return 0 if not failures else 1
if __name__ == "__main__":
sys.exit(main(sys.argv))

View file

@ -0,0 +1,89 @@
"""Decide whether a reuse-surface hub-writer token is the dedicated caller.
The check is metadata only. It never accepts a secret value, a login token, or
a command that reads ``platform/data/*``.
"""
from __future__ import annotations
POLICY = "workload-kv-read-reuse-surface-runtime"
ROLE = "reuse-surface-hub-writer-workload-kv-read"
FORBIDDEN_ENTITY_ID = "4a1f663c-0621-0483-edd0-f852274f4b6b"
FORBIDDEN_POLICIES = frozenset(
{
"default",
"platform-admin",
"operator-custody",
"workload-kv-read-reuse-surface-runtime-eso",
}
)
DATA = "platform/data/workloads/reuse/reuse-surface/runtime-secrets"
METADATA = "platform/metadata/workloads/reuse/reuse-surface/runtime-secrets"
PARENT_DATA = "platform/data/workloads/reuse/reuse-surface"
PARENT_METADATA = "platform/metadata/workloads/reuse/reuse-surface"
SIBLING = "platform/data/workloads/issue-core/issue-core/issue-core-runtime"
EXACT_READ = (DATA, METADATA)
MUST_DENY = (PARENT_DATA, PARENT_METADATA, SIBLING)
def _caps(report: dict, path: str) -> list[str]:
raw = (report.get("capabilities") or {}).get(path)
if not isinstance(raw, list):
return []
return sorted(str(item) for item in raw)
def assess(report: dict) -> list[str]:
"""Return the reasons a login report fails. An empty list is a pass.
``non-member`` passes only when login was refused. ``member`` passes only
when the token's policy set is exactly the workload policy, the token is
not the platform-admin entity, the two exact paths are read-only, the
parent and a sibling workload are denied, and the token was revoked.
"""
mode = report.get("mode")
if mode not in {"member", "non-member"}:
return [f"unknown mode {mode!r}"]
login = report.get("login")
if mode == "non-member":
if login == "refused":
return []
return ["non-member login succeeded; the role accepted the wrong principal"]
failures: list[str] = []
if login != "ok":
failures.append(f"member login was {login!r}")
return failures
policies = set(report.get("policies") or [])
identity_policies = set(report.get("identity_policies") or [])
effective = policies | identity_policies
if effective != {POLICY}:
failures.append(
"token policies are not exactly "
f"{POLICY} (effective={sorted(effective)})"
)
overlap = effective & FORBIDDEN_POLICIES
if overlap:
failures.append(f"forbidden policies attached: {sorted(overlap)}")
entity_id = str(report.get("entity_id") or "")
if entity_id == FORBIDDEN_ENTITY_ID:
failures.append(
"token belongs to the platform-admin entity; do not attach this policy to it"
)
if not entity_id:
failures.append("token lookup did not report an entity id")
for path in EXACT_READ:
caps = _caps(report, path)
if caps != ["read"]:
failures.append(f"{path} capabilities {caps or ['<missing>']}, want ['read']")
for path in MUST_DENY:
caps = _caps(report, path)
if caps != ["deny"]:
failures.append(f"{path} capabilities {caps or ['<missing>']}, want ['deny']")
if report.get("revoked") is not True:
failures.append("token was not revoked")
return failures

View file

@ -0,0 +1,67 @@
from ops_mason.reuse_surface_hub_writer import (
DATA,
FORBIDDEN_ENTITY_ID,
METADATA,
PARENT_DATA,
POLICY,
SIBLING,
assess,
)
def member(**overrides):
report = {
"mode": "member",
"login": "ok",
"policies": [POLICY],
"identity_policies": [],
"entity_id": "11111111-1111-1111-1111-111111111111",
"capabilities": {
DATA: ["read"],
METADATA: ["read"],
PARENT_DATA: ["deny"],
"platform/metadata/workloads/reuse/reuse-surface": ["deny"],
SIBLING: ["deny"],
},
"revoked": True,
}
report.update(overrides)
return report
def test_member_exact_policy_passes():
assert assess(member()) == []
def test_admin_entity_and_broad_capabilities_fail():
failures = assess(
member(
policies=["default", "operator-custody", "platform-admin", POLICY],
identity_policies=["platform-admin"],
entity_id=FORBIDDEN_ENTITY_ID,
capabilities={
DATA: ["create", "delete", "list", "read", "update"],
METADATA: ["create", "delete", "list", "read", "update"],
PARENT_DATA: ["create", "delete", "list", "read", "update"],
"platform/metadata/workloads/reuse/reuse-surface": ["read"],
SIBLING: ["create", "delete", "list", "read", "update"],
},
)
)
assert any("platform-admin entity" in item for item in failures)
assert any("forbidden policies" in item for item in failures)
assert any(SIBLING in item for item in failures)
assert any("not exactly" in item for item in failures)
def test_missing_revoke_fails():
assert any("not revoked" in item for item in assess(member(revoked=False)))
def test_non_member_refusal_passes_and_unexpected_login_fails():
assert assess({"mode": "non-member", "login": "refused"}) == []
assert assess({"mode": "non-member", "login": "ok"})
def test_unknown_mode_fails():
assert assess({"mode": "other"})

View file

@ -9,7 +9,7 @@ flavor: planning
owner: codex
topic_slug: custodian
created: "2026-08-28"
updated: "2026-10-03"
updated: "2026-10-14"
related:
- MASON-WP-0003
- NK-WP-0033
@ -149,7 +149,7 @@ id: MASON-WP-0004-T03
status: wait
depends_on: [MASON-WP-0004-T01]
blocked_on: owners
blocking_reason: "Owners fill the gaps in manifests/custody-descriptions.yaml for the 9 draft entries (asked 2026-10-09)."
blocking_reason: "operators/nextcloud base entry removed 2026-10-14 after the founder retired it. Remaining draft gaps still need their owners."
priority: low
state_hub_task_id: "fff26914-d854-5854-b350-d7241812fb04"
```
@ -203,6 +203,18 @@ fluid-telegram four from the approved plan (draft until fluid-telegram confirms,
message `da7e711c`); asked email-connect for its new path (message
`acb3ff22`).
2026-10-10: railiance-platform (message `389906a5`) confirmed `operators/*`
metadata writes are refused on purpose. Descriptions for that mount stay in
this file and are not mirrored into OpenBao. `operators/nextcloud/backup`
keeps the file-backed fields.
2026-10-14: railiance-platform (message `f67d4dea`) said the founder deleted
`operators/nextcloud` on 2026-10-10. Removed that draft from
`manifests/custody-descriptions.yaml`. `operators/nextcloud/backup` stays.
Still open: `keycape-factor-issuer` rotation and `user-engine/runtime`
on_loss, plus any undescribed paths from the 2026-10-10 inventory whose
owners have not answered.
## Make an undescribed path visible before it accumulates
```task

View file

@ -9,7 +9,7 @@ flavor: planning
owner: codex
topic_slug: helix-forge
created: "2026-09-04"
updated: "2026-10-05"
updated: "2026-10-14"
state_hub_workstream_id: "483e56d6-6601-5377-9066-66225214c046"
---
@ -218,7 +218,7 @@ id: MASON-WP-0005-T05
status: progress
depends_on: [MASON-WP-0005-T04]
blocked_on: human
blocking_reason: "ops-mason checks and the non-member refusal pass (2026-10-09). tegwick has no MFA factor: it enrolls through user-engine self-service MFA (message ab89a591, USER-WP-0028-T03), then the founder runs scripts/verify-fluid-telegram-lane.sh member; fluid-telegram runs the salt create-once probe (FT-WP-0002)."
blocking_reason: "ops-mason checks and the non-member refusal pass. tegwick enrolled TOTP on 2026-10-11 (message 36b443ab). The founder still runs scripts/verify-fluid-telegram-lane.sh member via the 127.0.0.1:18200 tunnel. fluid-telegram runs the salt create-once probe (FT-WP-0002)."
priority: high
state_hub_task_id: "4c205be7-4f1f-5dd1-aafa-fc112fdd640e"
```
@ -266,6 +266,13 @@ deliver it (USER-WP-0028-T03 / USER-WP-0027-T04, decision cef97ccd), with
`tegwick` as the first attended real-user acceptance, and to reply when
`tegwick` has an active factor.
2026-10-14: user-engine reports the factor is active (message `36b443ab`).
`tegwick` enrolled TOTP at 22:22 on 2026-10-11 and passed the portal half of
U07 at 22:30. The OpenBao half is still the founder running
`scripts/verify-fluid-telegram-lane.sh member` through
`http://127.0.0.1:18200`. `coulomb-social` has `mfaRequired: false`, so it is
not the check. This session did not start that login.
## Hand off routing and keep the adapter lane separate
```task

View file

@ -0,0 +1,98 @@
---
id: MASON-WP-0011
type: workplan
title: "Name a dedicated caller for the reuse-surface hub writer token"
domain: infotech
repo: ops-mason
status: active
flavor: planning
owner: codex
topic_slug: custodian
created: "2026-10-14"
updated: "2026-10-14"
---
# Name a dedicated caller for the reuse-surface hub writer token
## Goal
Give CUST-WP-0081 an attended OpenBao caller whose token carries only
`workload-kv-read-reuse-surface-runtime` on the exact runtime-secrets data
and metadata paths, with parent and sibling paths denied. The platform-admin
entity `4a1f663c-0621-0483-edd0-f852274f4b6b` is not that caller.
Demand: State Hub message `08b254af-59d4-4d1a-9544-fed3dcaaf213` from
the-custodian, workplan CUST-WP-0081.
## Boundaries
- ops-mason writes the plan, the draft CCR, the role document, and the
verifier. It does not install a policy or a role, and it does not read
`REUSE_SURFACE_TOKEN`.
- railiance-platform owns the OpenBao apply. CCR-2026-0005 stays the
authority for the existing secret and the ESO lane.
- key-cape owns group `reuse-surface-hub-writers` and the member principal.
- ops-warden keeps catalog `reuse-surface-hub-write-token`. It does not
receive a secret value. It names the role only after both verifier modes
pass.
## Write the caller plan
```task
id: MASON-WP-0011-T01
status: done
priority: high
```
Record why the admin entity cannot carry the workload policy, reuse the
existing KV path and policy, and publish the draft role, CCR, and verifier.
Done 2026-10-14. Plan `plans/reuse-surface-hub-writer.md` (status draft).
Bundle `builds/reuse-surface-hub-writer/`. Verifier
`scripts/verify-reuse-surface-hub-writer.py`. No live login and no KV read.
## Confirm the group and the member entity
```task
id: MASON-WP-0011-T02
status: wait
depends_on: [MASON-WP-0011-T01]
blocked_on: message-from:key-cape
blocking_reason: "key-cape confirms group reuse-surface-hub-writers and a member entity that is not 4a1f663c-0621-0483-edd0-f852274f4b6b and has no platform-admin or operator-custody identity policy."
priority: high
```
Ask key-cape to create or confirm the group and to name the member entity
id without sending a credential. `bound_claims_confirmed` stays false until
that reply. railiance-platform's two approvers still have to accept the CCR.
## Apply the role without a KV write
```task
id: MASON-WP-0011-T03
status: wait
depends_on: [MASON-WP-0011-T02]
blocked_on: human
blocking_reason: "After T02. Founder applies the CCR through the delegated applier. No bao kv put. Do not attach the policy to the admin entity."
priority: high
```
railiance-platform assigns the real CCR id, copies the policy file over the
existing `workload-kv-read-reuse-surface-runtime` policy, and applies the
role. The KV value is already present under CCR-2026-0005.
## Record the sanitized receipt
```task
id: MASON-WP-0011-T04
status: wait
depends_on: [MASON-WP-0011-T03]
blocked_on: human
blocking_reason: "After T03. Founder runs scripts/verify-reuse-surface-hub-writer.py member and non-member. A live receipt does not exist yet."
priority: high
```
Both modes must pass. Copy the mode-0600 receipts into `docs/evidence/`
with no token and no field value, reply to message `08b254af`, and tell
ops-warden the role name for `auth_method`. Hub registration itself stays
with the-custodian.