Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 1170398@bnt-lap001 Assistant-Session: 622cd705-cb31-4322-ba08-dd42e44fa583
183 lines
9.6 KiB
Markdown
183 lines
9.6 KiB
Markdown
---
|
|
id: fluid-telegram-operator-credential-lane
|
|
demand_source: fluid-telegram/workplans/FT-WP-0002 and State Hub message 287cf897-7f47-4bcc-87d6-085f43d5f03e
|
|
consumer_repo: fluid-telegram
|
|
credential_type: openbao-oidc-kv-read-write
|
|
status: draft
|
|
approved_by: null
|
|
approved_at: null
|
|
created: "2026-09-04"
|
|
updated: "2026-09-04"
|
|
---
|
|
|
|
# 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 pending
|
|
|
|
No valid scoped OpenBao session was available during intake, so the required
|
|
live outputs from `bao secrets list`, `bao auth list`, `bao policy list`, and
|
|
the relevant `auth/netkingdom/role/*` reads are not yet attached. Phase 2 must
|
|
repeat the survey with `./scripts/bao-session.sh grant MASON-WP-0005-T01`.
|
|
|
|
**Existing-lane answer:** none is known from source state. This remains a
|
|
draft finding until the live survey confirms it.
|
|
|
|
## 3. Proposed changes
|
|
|
|
The recommended CLI prefix is
|
|
`platform/workloads/coulomb/fluid-telegram/hall-of-helix`. `coulomb` is a
|
|
recommendation from the existing owner precedent, not an authorization; T01
|
|
must replace this paragraph with railiance-platform's explicit decision before
|
|
review.
|
|
|
|
The recommended objects are:
|
|
|
|
| # | Action | Object | Rationale |
|
|
|---|---|---|---|
|
|
| 1 | create | Policy `workload-kv-fluid-telegram-hall-of-helix-operator` | A new exact-path matrix is required; no read-only lane can satisfy the writes. |
|
|
| 2 | create | OIDC role `fluid-telegram-hall-of-helix-workload-kv` at `auth/netkingdom` | The caller is an attended operator; AppRole and Kubernetes auth are the wrong identity shapes. |
|
|
| 3 | modify | ops-mason executor with an approved OIDC KV matrix spec | The current executor cannot safely express OIDC or per-path capabilities. |
|
|
| 4 | modify | railiance-platform CCR schema/validator with an approved read/write request type and naming rules | The platform owner explicitly rejects this shape today; bypassing that gate is forbidden. |
|
|
| 5 | modify | railiance-platform agent high-risk boundary with exact data and metadata denies for all four paths | Agent-bound identities must not inherit this lane through another policy. |
|
|
| 6 | propose | ops-warden entry `fluid-telegram-operator`, pointer-only, `status: draft`, `resolvable: false` | A concrete selector is useful before activation; no placeholder prefix becomes routable. |
|
|
|
|
### Exact policy matrix
|
|
|
|
All entries are individual KV-v2 API paths. There is no `*` grant, parent
|
|
`list`, metadata mutation, delete, destroy, undelete, or sudo capability.
|
|
|
|
| CLI entry | KV-v2 data-path capabilities | Risk and reason |
|
|
|---|---|---|
|
|
| `.../operator-app` | `read` | High confidentiality: Telegram application id/hash; entered only through sanctioned attended value entry. |
|
|
| `.../operator-session` | `create,read,update` | High: full-account MTProto credential. Provisioning only; never adapter-visible. |
|
|
| `.../bot-token` | `create,read,update` | High: controls Bot API publication. Provisioner writes immediately after BotFather issues it. |
|
|
| `.../redaction-salt` | `create,read` | High integrity and sensitive pseudonymisation material. Overwrite, patch, and deletion are denied. |
|
|
|
|
OpenBao KV v2 documents that it honors the ACL distinction between `create`
|
|
and `update`; it also documents CAS `0` as create-if-absent. The fluid-telegram
|
|
client currently performs a read followed by a normal POST. The ACL therefore
|
|
supplies the decisive server-side write-once boundary: the first POST is a
|
|
create and a later POST is an update, which this policy denies. The client
|
|
should still add CAS `0` to make its intent race-safe and explicit, but this
|
|
plan does not depend on client-only behavior.
|
|
|
|
This is operational write-once for the provisioner, not immutable storage.
|
|
A platform administrator can recover from a corrupt first write through a
|
|
separately approved attended action. That action must preserve the old version
|
|
until recovery is verified and must never be exposed through this OIDC role.
|
|
|
|
### 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`
|
|
- proposed bound claim: `groups=fluid-telegram-operators` — **unconfirmed**
|
|
- callbacks: Bao UI plus localhost and loopback CLI callbacks already accepted
|
|
by the platform contract
|
|
|
|
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)
|
|
|
|
This section is incomplete while T01 and T02 are open; the plan must remain
|
|
`draft`.
|
|
|
|
- **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:** an unconfirmed group is a hard blocker, not a warning.
|
|
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.
|
|
- **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)
|
|
|
|
Not yet renderable. The owner-approved tenant segment, OIDC bound claim, live
|
|
structure survey, CCR/executor extension, and installed-engine create/update
|
|
probe are open inputs. When those close, this section must ask for one explicit
|
|
approval covering the exact objects and capability matrix above.
|