Live-validate the open-registration auth path end-to-end (post-#71) + management-bot e2e actor #76

Closed
opened 2026-07-10 23:51:24 +00:00 by robocub · 3 comments
Collaborator

The self-serve link/approve flow is the critical path for open registration, and it needs an end-to-end live test with the auth knobs on before it can be turned on for strangers.

Why now

open_registration requires require_room_authority + require_discord_approval (config validation enforces this). All three are shipped and deployed to prod but off. The flow was last live-tested in the #47 staging pass (2026-07-06, auth 5/5) — but #71 has since rewritten the management command gating (the new DM-only is_command_room gate fronts every command path). That change is currently only unit-tested, so the exact path open registration depends on has not been exercised live since it changed.

What to validate (all three knobs ON)

  • A non-operator Matrix user DMs the bot → link <name> <room> <guild> <channel>
  • room-authority probe (must be room moderator) + MatrixRTC/PL-0 prereq checks
  • link held pending → one-time code issued
  • Manage-Server user runs /bridge approve code:<code> on Discord within the timeout → bridge created, both sides notified
  • unlink / list scoped to bridges the user created; operator commands remain allowlist-only
  • max_tenants_per_owner cap enforced; deny-listed owner/guild/room refused
  • Commands sent from a shared/bridged room (not a DM) are ignored (the #71 gate)

Harness gap

The nvb-e2e framework has no management-bot actor yet (the unbuilt part of #38 D3). Two paths:

  • (a, preferred) build a management-bot actor + a self-serve link/approve scenario in nvb-e2e — becomes a permanent regression guard for the whole auth flow.
  • (b, interim) a documented manual staging protocol.

Gate: this must pass before open_registration is enabled in prod. Related: #71, #47, #43, #38.

The self-serve link/approve flow is the critical path for open registration, and it needs an **end-to-end live test with the auth knobs on** before it can be turned on for strangers. ## Why now `open_registration` requires `require_room_authority` + `require_discord_approval` (config validation enforces this). All three are shipped and deployed to prod but **off**. The flow was last live-tested in the #47 staging pass (2026-07-06, auth 5/5) — but **#71 has since rewritten the management command gating** (the new DM-only `is_command_room` gate fronts every command path). That change is currently only unit-tested, so the exact path open registration depends on has not been exercised live since it changed. ## What to validate (all three knobs ON) - A **non-operator** Matrix user DMs the bot → `link <name> <room> <guild> <channel>` - room-authority probe (must be room moderator) + MatrixRTC/PL-0 prereq checks - link held **pending** → one-time code issued - Manage-Server user runs `/bridge approve code:<code>` on Discord within the timeout → bridge created, both sides notified - `unlink` / `list` scoped to bridges the user created; operator commands remain allowlist-only - `max_tenants_per_owner` cap enforced; deny-listed owner/guild/room refused - Commands sent from a **shared/bridged room** (not a DM) are ignored (the #71 gate) ## Harness gap The `nvb-e2e` framework has **no management-bot actor** yet (the unbuilt part of #38 D3). Two paths: - **(a, preferred)** build a management-bot actor + a self-serve link/approve scenario in `nvb-e2e` — becomes a permanent regression guard for the whole auth flow. - **(b, interim)** a documented manual staging protocol. **Gate:** this must pass before `open_registration` is enabled in prod. Related: #71, #47, #43, #38.
Author
Collaborator

Implementation plan (design notes)

Traced the approval seam to scope automation feasibility. /bridge approve code:<code> is a Discord slash command (handle_approve_command, crates/discord/src/puppet.rs:2424) that checks the invoking user's Manage Server permission, then sends a DiscordApproval over an mpsc channel to the Matrix side (handle_discord_approval, crates/matrix-rtc/src/mgmt.rs:1539, consumed via approval_rx at mgmt.rs:91). A bot cannot invoke a slash command, and the harness mod_token is a bot — so the /bridge approve click itself is not bot-automatable.

Decomposition:

  1. Matrix half — fully automatable (the bulk of what #71 changed). New nvb-e2e management-client actor: a nvbtest_* user (as_token masquerade) opens a DM with the bridge bot, sends link <name> <room> <guild> <channel>, scrapes the reply. Scenario asserts: room-authority probe (sender must be room moderator — needs one-time PL setup for a test user in an Auto Test room), PL-0/RTC prereq checks, pending-code issuance, unlink/list scoping to own bridges, max_tenants_per_owner, deny-list refusal, and the #71 DM-gate (a command sent from a non-DM/shared room must be ignored — the specific regression this issue exists to guard).
  2. Approval redemption — via internal seam. Inject a DiscordApproval directly into approval_rx (small test seam needed) to exercise handle_discord_approval end-to-end: code match, approval_timeout_secs, guild-match, bridge creation + both-sides notification. Bypasses Discord's UI but covers the whole redemption→creation path.
  3. Discord slash-command + Manage-Server gate — irreducible remainder. Not bot-automatable. Covered by unit tests of handle_approve_command's permission logic + one manual staging confirmation (a human runs /bridge approve once with all knobs on).

Config: run with require_room_authority + require_discord_approval + open_registration all ON. Prereq: build the management-client actor (this is also the missing #38 D3 "mod actor" piece). Manual-only interim (option b) if the actor is deferred.

See also: the harness cannot drive real Discord slash commands (design constraint worth recording for any future approval-flow test work).

## Implementation plan (design notes) Traced the approval seam to scope automation feasibility. `/bridge approve code:<code>` is a Discord **slash command** (`handle_approve_command`, `crates/discord/src/puppet.rs:2424`) that checks the *invoking user's* Manage Server permission, then sends a `DiscordApproval` over an mpsc channel to the Matrix side (`handle_discord_approval`, `crates/matrix-rtc/src/mgmt.rs:1539`, consumed via `approval_rx` at `mgmt.rs:91`). **A bot cannot invoke a slash command**, and the harness `mod_token` is a bot — so the `/bridge approve` click itself is not bot-automatable. Decomposition: 1. **Matrix half — fully automatable (the bulk of what #71 changed).** New `nvb-e2e` **management-client actor**: a `nvbtest_*` user (as_token masquerade) opens a DM with the bridge bot, sends `link <name> <room> <guild> <channel>`, scrapes the reply. Scenario asserts: room-authority probe (sender must be room moderator — needs one-time PL setup for a test user in an Auto Test room), PL-0/RTC prereq checks, pending-code issuance, `unlink`/`list` scoping to own bridges, `max_tenants_per_owner`, deny-list refusal, and the **#71 DM-gate** (a command sent from a non-DM/shared room must be ignored — the specific regression this issue exists to guard). 2. **Approval redemption — via internal seam.** Inject a `DiscordApproval` directly into `approval_rx` (small test seam needed) to exercise `handle_discord_approval` end-to-end: code match, `approval_timeout_secs`, guild-match, bridge creation + both-sides notification. Bypasses Discord's UI but covers the whole redemption→creation path. 3. **Discord slash-command + Manage-Server gate — irreducible remainder.** Not bot-automatable. Covered by unit tests of `handle_approve_command`'s permission logic + **one manual staging confirmation** (a human runs `/bridge approve` once with all knobs on). Config: run with `require_room_authority` + `require_discord_approval` + `open_registration` all ON. Prereq: build the management-client actor (this is also the missing #38 D3 "mod actor" piece). Manual-only interim (option b) if the actor is deferred. See also: the harness cannot drive real Discord slash commands (design constraint worth recording for any future approval-flow test work).
Author
Collaborator

Correction to the plan above: the management-client actor (part 1) is not the #38 D3 "mod actor" — I conflated them. Two different actors:

  • #76's management client is a Matrix actor: an existing nvbtest_* appservice user driven via as_token masquerade (same mechanism as the MatrixSpeaker/MatrixListener actors), which DMs the bridge bot to run link/unlink/list. No new bot is needed — only a one-time moderator-PL grant to a test user in an Auto Test room so the require_room_authority probe passes.
  • The #38 D3 "mod actor" is a separate Discord bot (the provisioned nvb-test-mod application, already wired as mod_token in the staging e2e.toml) for force-move / moderation scenarios (#62). It is unrelated to #76.

So #76 reuses existing test identities; it does not require creating or provisioning any new bot or account.

**Correction to the plan above:** the management-client actor (part 1) is **not** the #38 D3 "mod actor" — I conflated them. Two different actors: - **#76's management client** is a **Matrix** actor: an existing `nvbtest_*` appservice user driven via `as_token` masquerade (same mechanism as the `MatrixSpeaker`/`MatrixListener` actors), which DMs the bridge bot to run `link`/`unlink`/`list`. **No new bot is needed** — only a one-time moderator-PL grant to a test user in an Auto Test room so the `require_room_authority` probe passes. - The **#38 D3 "mod actor"** is a separate **Discord** bot (the provisioned `nvb-test-mod` application, already wired as `mod_token` in the staging `e2e.toml`) for force-move / moderation scenarios (#62). It is unrelated to #76. So #76 reuses existing test identities; it does not require creating or provisioning any new bot or account.
Author
Collaborator

Done. The open-registration auth path was live-validated end-to-end via the new MatrixManagementClient e2e actor + mgmt_self_serve_link scenario (self-serve reachability, #71 DM-gate, invite gate, room-authority neg+pos → pending code, caps, deny-list, list/unlink scoping), plus in-crate approval-redemption tests and the can_approve unit test; the manual /bridge approve Discord-UI check also passed. Merged (master 8f23abf), shipped in v0.3.0-alpha.16, deployed to prod 2026-07-11.

Done. The open-registration auth path was live-validated end-to-end via the new `MatrixManagementClient` e2e actor + `mgmt_self_serve_link` scenario (self-serve reachability, #71 DM-gate, invite gate, room-authority neg+pos → pending code, caps, deny-list, list/unlink scoping), plus in-crate approval-redemption tests and the `can_approve` unit test; the manual `/bridge approve` Discord-UI check also passed. Merged (master `8f23abf`), shipped in v0.3.0-alpha.16, deployed to prod 2026-07-11.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
dark/nether-voicebridge#76
No description provided.