Addressed to ops-warden as the front door, and explicit that the lane itself is railiance-platform's to create -- ops-warden routes this row rather than executing it. States the two things that are easy to get wrong. The lane needs write and not only read: apply's critical write happens immediately after BotFather issues the bot token, and a denial there leaves a registered bot whose only credential is a chat message, with a re-run creating a second bot. And the redaction salt must never be rotated, so write-once on that path would be welcome if the lane tooling can express it. Leaves the <domain> segment open rather than assuming infotech: the only concrete lane we can read uses "coulomb", which looks like a tenant rather than a sector, and the segment belongs to its owner. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0172sgCZEEDJcnQmr4SGDvKa Assistant: claude-code Assistant-Model: opus Assistant-Process: 1361245@bnt-lap001 Assistant-Session: b3b428ef-f3e6-4688-b091-01f71461d66a
140 lines
6.2 KiB
Markdown
140 lines
6.2 KiB
Markdown
---
|
|
to: ops-warden
|
|
from: fluid-telegram
|
|
date: "2026-09-04"
|
|
subject: "Credential lane for the Telegram operator (workplan FT-WP-0002)"
|
|
routes_to: railiance-platform (OpenBao)
|
|
---
|
|
|
|
# Request — credential lane for the Telegram operator
|
|
|
|
`fluid-telegram` provisions HelixForge's Telegram presence from a declared
|
|
specification (`FT-WP-0002`, `docs/provisioning.md`). The tooling is built,
|
|
tested and ready; the only thing blocking the first run is that it has nowhere
|
|
sanctioned to keep four secrets and no role that can reach them.
|
|
|
|
Per `wiki/AccessRouting.md` this is the "API key / DB credential" row, so
|
|
ops-warden **routes** rather than executes it. We are asking ops-warden for the
|
|
routing artifacts, and asking it to point us at railiance-platform for the lane
|
|
itself.
|
|
|
|
## What the workload is
|
|
|
|
A provisioning tool, run by an operator on demand. It is **not** on any request
|
|
path, and it is not the adapter — the adapter that publishes to Telegram holds
|
|
only a bot token and never sees the rest.
|
|
|
|
It runs `plan` and `apply` against a declared spec: registering the bot through
|
|
BotFather over MTProto, creating channels, and granting the bot `post_messages`
|
|
and nothing wider.
|
|
|
|
## The four secrets
|
|
|
|
All under one bundle prefix, one KV entry each:
|
|
|
|
| Bundle | Contents | Written by | Read by |
|
|
|---|---|---|---|
|
|
| `operator-app` | `api_id`, `api_hash` from my.telegram.org | operator, by hand | provisioner |
|
|
| `operator-session` | MTProto session string | provisioner (`session bootstrap`) | provisioner |
|
|
| `bot-token` | Telegram bot token | provisioner (`apply`) | provisioner, adapter |
|
|
| `redaction-salt` | 32 random bytes | provisioner, **once, never rotated** | adapter |
|
|
|
|
Two of these deserve a note.
|
|
|
|
**`operator-session` is a full-account credential.** It can do anything the
|
|
operator's Telegram account can do. It is held only because the Bot API cannot
|
|
create a bot or a channel — both are client capabilities reachable only through
|
|
MTProto (Canon INT-03). The account is a dedicated operator account, never a
|
|
person's own, and the session is used for provisioning only: all ordinary
|
|
publishing goes through the bot token on the supported Bot API surface. We would
|
|
grade this lane **high risk**.
|
|
|
|
**`redaction-salt` must never be rotated.** Rotating it silently invalidates
|
|
every longitudinal comparison the interface has made, with no visible failure —
|
|
the numbers keep arriving and quietly stop meaning what they used to. The tool
|
|
has no code path that overwrites it (create-if-absent only). If your lane
|
|
tooling can enforce write-once on that one path, we would welcome it.
|
|
|
|
## What we need
|
|
|
|
### 1. From railiance-platform — a workload KV lane
|
|
|
|
Following `railiance-platform/docs/workload-kv-access-lanes.md`:
|
|
|
|
- A role, by your naming convention presumably `fluid-telegram-workload-kv`
|
|
- Policy over `platform/workloads/<domain>/fluid-telegram/<campaign>/*`
|
|
- OIDC through `auth/netkingdom`, as the existing lanes use
|
|
|
|
**This lane needs write, not only read.** Every documented lane we found is
|
|
`-workload-kv-read`, and read-only would fail badly here rather than merely
|
|
being inconvenient: `apply` writes three of the four paths, and the write that
|
|
matters happens *immediately after BotFather issues the bot token*. A denial at
|
|
that moment leaves a registered bot whose only surviving credential is a chat
|
|
message, and re-running creates a second bot. If a split is preferred, the
|
|
minimum is write on `operator-session`, `bot-token` and `redaction-salt`, and
|
|
read on all four.
|
|
|
|
### 2. From ops-warden — a catalog entry
|
|
|
|
So that `warden access 'telegram operator credentials'` resolves to something
|
|
concrete rather than the generic `openbao-api-key` template. Proposed, in the
|
|
shape of `whynot-design-npm-publish`:
|
|
|
|
```yaml
|
|
id: fluid-telegram-operator
|
|
title: "fluid-telegram Telegram operator credentials (MTProto session, bot token, salt)"
|
|
risk: high
|
|
workload_ref:
|
|
applicability: applicable
|
|
need_keywords: [telegram, mtproto, botfather, bot, token, session, fluid-telegram,
|
|
helix-forge, hall-of-helix, provisioning]
|
|
owner_repo: railiance-platform
|
|
subsystem: OpenBao
|
|
warden_executes: false
|
|
auth_method: bao login -method=oidc -path=netkingdom role=fluid-telegram-workload-kv
|
|
path_template: platform/workloads/<domain>/fluid-telegram/<campaign>
|
|
policy_ref: flex-auth check secret.read:fluid-telegram
|
|
wiki_ref: fluid-telegram/docs/seeding-runbook.md
|
|
```
|
|
|
|
Corrections welcome — we have modelled this on your existing entries rather than
|
|
inventing a shape.
|
|
|
|
## One open question — the `<domain>` segment
|
|
|
|
We had assumed `infotech`, this repository's State Hub domain. But the only
|
|
concrete lane we can read uses `platform/workloads/**coulomb**/whynot-design/…`,
|
|
where the segment looks like a tenant rather than a sector.
|
|
|
|
We do not want to guess: the segment is yours to define, and a workload that
|
|
picks its own path in someone else's store is how a policy ends up written
|
|
around a mistake. Tell us which is correct and we will take it.
|
|
|
|
The provisioner reads `BAO_MOUNT` and `FLUID_BAO_PREFIX`, so whatever you
|
|
confirm is configuration on our side, not a code change.
|
|
|
|
## What is already done
|
|
|
|
- Paths, mount and prefix are configurable; nothing is hardcoded.
|
|
- The tool reads `~/.vault-token` and `BAO_TOKEN`/`VAULT_TOKEN`; it never writes
|
|
a credential to disk or logs one, and error messages name paths, never values.
|
|
- `provision preflight` checks the whole chain without contacting Telegram, and
|
|
currently reports everything green except OpenBao access.
|
|
|
|
## Note on a diagnosis that cost us time
|
|
|
|
`warden access` renders `bao login -method=oidc role=<domain>` for this need.
|
|
The working form is `-path=netkingdom`, which we found in railiance-platform's
|
|
runbook. Because OpenBao answers `403 permission denied` for paths that do not
|
|
exist as well as for those you may not reach, the wrong mount is
|
|
indistinguishable from an expired token from the outside — we spent a while
|
|
renewing a token that was not the problem.
|
|
|
|
If `auth_method` in the generic `openbao-api-key` entry carried `-path=netkingdom`,
|
|
the next person would not repeat this. Offered as an observation, not a defect
|
|
report: the entry is explicitly a template with owner-confirmed placeholders.
|
|
|
|
## Contact
|
|
|
|
Repository `fluid-telegram`, workplan `FT-WP-0002`, State Hub topic
|
|
`helix-forge`, domain `infotech`.
|