ops-mason/plans/fluid-telegram-operator-credential-lane.md
tegwick 21bce610b5 MASON-WP-0005-T03 done: founder approved the fluid-telegram operator lane
Plan status approved (Bernd Worsch, 2026-10-09) with build_spec and
approved_spec_sha256 41a0ca27; the executor's approval gate accepts it.
T04 now waits on the founder-run applier (RPF-WP-0035-T03, decision 62aa95e4).

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 327203@bnt-lap001
Assistant-Session: 55028ae3-4914-4bd1-8f5c-815f3527aef0
2026-10-09 00:45:03 +02:00

14 KiB

id demand_source consumer_repo credential_type status approved_by approved_at approved_spec_sha256 created updated build_spec
fluid-telegram-operator-credential-lane fluid-telegram/workplans/FT-WP-0002 and State Hub message 287cf897-7f47-4bcc-87d6-085f43d5f03e fluid-telegram openbao-oidc-kv-read-write approved Bernd Worsch 2026-10-09 41a0ca2746aa93b6ee9d1ca631517d680ade95c56e7a38b75a55209ef2316b73 2026-09-04 2026-10-09
engine policy_name role_name campaign_path bound_group allowed_redirect_uris identity_confirmation_ref platform_matrix_review_ref auth_mount token_ttl token_max_ttl bao_bin audit_log_path
openbao-oidc-kv-read-write workload-kv-fluid-telegram-hall-of-helix-operator fluid-telegram-hall-of-helix-workload-kv platform/workloads/coulomb/fluid-telegram/hall-of-helix fluid-telegram-operators
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
key-cape message b2ed890f (key-cape e0b5fae); LLDAP group fluid-telegram-operators exists, member tegwick (founder 2026-10-09) railiance-platform docs/credential-lane-designs/fluid-telegram-operator-kv.md (matrix identical, checked 2026-10-09) netkingdom 15m 30m bao /home/worsch/ops-mason/audit/build-log.jsonl

Construction plan: fluid-telegram operator credential lane

1. Demand

fluid-telegram has an attended provisioner that creates a Telegram bot and channels from a declared campaign specification. The provisioner needs an operator OIDC token that reads four campaign-specific KV entries, writes the MTProto session and bot token, and creates the redaction salt once. The MTProto session is a full-account credential, so this is a high-risk operator lane, never an autonomous agent or adapter lane. ops-mason constructs only the OpenBao structure and never handles Telegram values.

The first consumer is campaign hall-of-helix. A future adapter has a different, narrower need and is intentionally excluded from this plan.

2. Existing-structure survey

Disk survey completed 2026-09-04

  • railiance-platform/docs/workload-kv-access-lanes.md documents attended OIDC through auth/netkingdom, exact group-bound roles, three callback URIs, and 15-minute tokens.
  • The nearest concrete tenant-shaped path is platform/workloads/coulomb/whynot-design/npm-publish. Its CCR history says the owner corrected the first segment to the organisation/tenant, not the State Hub domain.
  • Existing policy files contain no fluid-telegram lane.
  • ops-warden/registry/routing/catalog.yaml contains only the generic openbao-api-key template for this need, and its login string omits -path=netkingdom. No concrete Telegram lane exists.
  • ops-mason/src/ops_mason/executor.py supports AppRole and Kubernetes KV lanes. It has no OIDC role writer and its generic policy helper emits the same capabilities for one data and metadata path, which cannot express this four-path matrix.
  • railiance-platform/schemas/credential-change-request.schema.yaml permits only request_type: workload-kv-read; its validator also requires the workload-kv-read- policy prefix and -workload-kv-read OIDC role suffix.

Live survey (2026-10-08)

Generated by scripts/plan-survey.py at 2026-10-08T21:53:55Z against BAO_ADDR=http://127.0.0.1:18200, token display_name token-claude-MASON-WP-0005-T01 (policies: default, ops-mason-survey). Metadata only: no kv get and no */data/* read was issued; policy bodies were read with bao policy read for name-matched candidates only.

Demand: KV path platform/workloads/coulomb/fluid-telegram/hall-of-helix, proposed policy workload-kv-fluid-telegram-hall-of-helix-operator, AppRole -, Kubernetes role -, consumer fluid-telegram. Match terms: fluid-telegram, hall-of-helix, telegram, coulomb.

bao secrets list (10 mounts, 1 relevant)

platform/                kv         version=2

bao auth list (5 auth mounts, 2 relevant)

approle/                 approle
kubernetes/              kubernetes

bao policy list (81 policies, 0 relevant)

(no relevant entries)

bao list auth/approle/role (approle) (14 roles, 0 relevant)

(no relevant entries)

bao list auth/kubernetes/role (kubernetes) (27 roles, 0 relevant)

(no relevant entries)

bao policy read of name-matched candidates (target platform/data/workloads/coulomb/fluid-telegram/hall-of-helix)

(no relevant entries)

bao kv metadata get / bao kv list (metadata only)

platform/workloads/coulomb/fluid-telegram/hall-of-helix: no metadata (path unused)
platform/workloads/coulomb/fluid-telegram/: request failed (output suppressed)

ops-warden routing catalog /home/worsch/ops-warden/registry/routing/catalog.yaml (42 entries, 4 relevant)

whynot-design-npm-publish  owner=railiance-platform  status=active  matches: coulomb
    path_template: platform/workloads/coulomb/whynot-design/npm-publish
    policy_ref: flex-auth check secret.read:whynot-design
    auth_method: bao login -method=oidc -path=netkingdom role=whynot-design-workload-kv-read
reuse-surface-hub-write-token  owner=railiance-platform  status=active  matches: coulomb
    path_template: platform/workloads/reuse/reuse-surface/runtime-secrets
    policy_ref: flex-auth check secret.read:reuse
    auth_method: caller's own OpenBao token (operator OIDC via key-cape, or a token carrying workload-kv-read-reuse-surface-runtime)
inbound-library-imap-approle  owner=ops-mason  status=active  matches: coulomb
    path_template: platform/workloads/inbound-library/imap
    auth_method: AppRole login role=inbound-library (role_id+secret_id in ~/.local/inbound-library/approle, config/library.json credential.approle_dir)
coulomb-social-runtime-env  owner=railiance-platform  status=active  matches: coulomb
    path_template: k8s:coulomb-social/coulomb-social-env
    auth_method: kubectl as platform operator (or bao OIDC when OpenBao lane is provisioned)

Does an existing lane already satisfy this demand?

Draft answer: no. Review before committing; this is generated, not a decision.

  • no surveyed policy grants platform/data/workloads/coulomb/fluid-telegram/hall-of-helix, the proposed names are free, the KV path is unused and no catalog entry routes it
  • policy grants were checked only for name-matched candidates; a policy with an unrelated name that covers platform/data/workloads/coulomb/fluid-telegram/hall-of-helix is not detected

Additions by hand (same grant)

  • bao list auth/netkingdom/role (12 roles): no fluid-telegram* role; the proposed fluid-telegram-hall-of-helix-workload-kv is free. The generator did not flag the netkingdom OIDC mount as relevant; it is the one this lane reuses.
  • All 81 policy bodies scanned (closing the generator's name-match gap): only platform-admin (platform/*) covers the target. No workload policy does.
  • Live reference role keycape-secrets-engine-openbao-operator-workload-kv-read has exactly the binding this plan renders: bound_claims_type=string, bound_claims={groups:[net-kingdom-admins], /assurance/level: aal2}, groups_claim=groups, token_no_default_policy=true. The executor's role document matches that shape.
  • Naming: live OIDC roles end -workload-kv-read and their policies start workload-kv-read-. This lane writes, so it drops -read (workload-kv-fluid-telegram-hall-of-helix-operator); that is why the CCR schema extension (T02) is needed.

Existing-lane answer: none. Confirmed live: path unused, names free, no covering workload policy, no catalog route.

OIDC role shape

  • auth mount: netkingdom
  • role: fluid-telegram-hall-of-helix-workload-kv
  • token policies: exactly workload-kv-fluid-telegram-hall-of-helix-operator; set token_no_default_policy=true
  • role type: oidc
  • token TTL: 15m, maximum TTL 30m
  • user claim: sub; groups claim: groups
  • scopes: openid,profile,email,groups
  • bound claims (bound_claims_type=string): groups=[fluid-telegram-operators] and /assurance/level=aal2 — confirmed by key-cape 2026-10-08 (message b2ed890f-a05a-4b96-95eb-2cd9d8b32caa, key-cape e0b5fae). Human ID tokens always carry groups (LLDAP group names); aal2 is set only after a verified privacyIDEA factor, the same pin as CCR-2026-0034.
  • precondition met: LLDAP group fluid-telegram-operators exists with the single member tegwick (founder report 2026-10-09, created in the LLDAP admin UI; names only).
  • callbacks (subset of the openbao-admin client registration): 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. Never the retired https://bao.coulomb.social/... (2026-09-15).

The role is campaign-specific because its policy is campaign-specific. A second campaign receives a second policy and role after its own review; it is not added below this prefix.

Value flow

  • An attended operator enters operator-app with the existing sanctioned paste-once/value-entry mechanism.
  • The provisioner creates or updates operator-session and bot-token.
  • The provisioner creates redaction-salt once.
  • ops-mason records paths, policy/auth metadata, capabilities, versions, timestamps, and audit references only. It never requests or reads a value.

4. Review notes (phase 2)

Complete as of 2026-10-09 (T01 and T02 done); plan moved to reviewed.

  • Reuse: reuse the existing netkingdom auth mount, callback set, group claim pattern, 15-minute TTL, and KV-v2 mount. Create only the policy and role that do not exist.
  • Least privilege: exact entry paths are safer than one campaign-prefix wildcard and are necessary for the salt's create-only rule. The role has no access to KV metadata because the provisioner uses data GETs to detect absence; metadata evidence comes from the separately scoped builder/operator verification path.
  • Identity binding: group and assurance claims confirmed by key-cape; the group exists with one member. Membership is the whole access decision, so adding a member later is a change to this lane's reach. The role must not be readable by every OIDC user.
  • Write-once semantics: KV-v2 create/update distinction is documented, but activation also requires an owner-run non-secret probe proving the installed engine behaves as expected. The resulting evidence contains no probe value.
  • Agent boundary: explicit denies must cover all four data paths and their metadata paths. The operator-session path is the decisive negative check.
  • Adapter separation: MASON-IN-0003 tracks a later runtime lane that reads only bot-token and redaction-salt; no role or policy in this plan is reused by the adapter.
  • Reversal: disable/delete the OIDC role first, then retire the policy. KV entries remain in operator custody for an explicit retention/recovery decision; teardown does not silently delete values.
  • Platform matrix: railiance-platform's docs/credential-lane-designs/fluid-telegram-operator-kv.md carries the same four paths and capabilities as _OPERATOR_MATRIX in src/ops_mason/executor.py (checked 2026-10-09).
  • Implementation gates: both ops-mason and railiance-platform must extend their current read-lane tooling before construction. Direct bao policy write/bao write auth/netkingdom/role/... commands outside those approved surfaces are not an alternative.

Verification required before routing activation

  1. Positive capabilities on each exact path match the matrix above.
  2. Parent, sibling workload, and sibling campaign paths report deny.
  3. A non-member OIDC identity cannot obtain the role's policy.
  4. Agent-bound identities report deny on all four data and metadata paths.
  5. An owner-run disposable KV-v2 probe proves create succeeds and a second write with the same policy is denied; only timestamps, versions, path, and pass/fail are returned.
  6. The value-entry/provisioner flow confirms all required entries exist using metadata/version evidence only.
  7. ops-warden keeps fluid-telegram-operator non-resolvable until all checks pass and the exact built pointers are returned.

5. Executive summary (phase 3)

What this creates. One OpenBao policy and one sign-in role, nothing else:

  • policy workload-kv-fluid-telegram-hall-of-helix-operator: on platform/data/workloads/coulomb/fluid-telegram/hall-of-helix/ operator-app read; operator-session and bot-token create, read, update; redaction-salt create, read (write-once); plus revoke-self. No metadata, list, parent or sibling access.
  • OIDC role fluid-telegram-hall-of-helix-workload-kv on the existing auth/netkingdom mount: only members of fluid-telegram-operators (today: tegwick) with a verified second factor (aal2); 15-minute token, 30 minutes at most; no default policy; the two loopback CLI callbacks and the operator-tunnel UI callback.

Why it is safe. The MTProto session is a full-account Telegram credential, so the lane is attended only: a person with MFA, never an agent or the future adapter. The path is unused and no workload policy reaches it today (live survey 2026-10-08). ops-mason writes only the policy and role; no value passes through it, and the salt cannot be overwritten.

What approval also accepts. The tenant segment coulomb (replacing the consumer's infotech assumption), and the exact matrix above, which railiance-platform's lane design already matches.

What happens after approval. The structure is applied through the approved surfaces only (railiance-platform's per-path applier, RPF-WP-0035-T03, under the attended provisioning decision 62aa95e4; ops-mason's build_oidc_kv_lane), never by direct bao writes. ops-warden's fluid-telegram-operator entry stays non-resolvable until the seven checks above pass, including the owner-run write-once probe.

Undo. Delete the role, then the policy. Stored values stay in operator custody until someone decides their retention explicitly.

To approve, the founder says "APPROVE fluid-telegram-operator-credential-lane"; ops-mason then sets status: approved, approved_by and approved_at.