DM creation regression in --auth-mode=dev: 'Authentication required' from PR #32 #40

Closed
opened 2026-04-29 22:07:03 +00:00 by sameh-farouk · 0 comments
Member

Symptom

In --auth-mode=dev, every startDm click in the chat-app logs:

Error: Authentication required
    at rpc (chat-app.js:382)
    at async startDm (chat-app.js:3349)
    at async pickDmUser (chat-app.js:3299)

DM never gets created. Reproduced on the dev box (--auth-mode=dev, accessed over the Mycelium overlay → hero_router on :9988).

Root cause

PR #32 (DM permission gate split) replaced the previous check_permission("channel.create", ...) call for DMs with a manual:

let caller = input.caller_id.ok_or(RpcError::Unauthenticated)?;
if !super::permissions::is_dev_mode() {
    // workspace-membership probe
}

The dev-mode bypass on the membership probe is correct, but it sits after the ok_or(Unauthenticated) line. In the typical dev-mode flow:

  1. main.rs::handle_rpc lines 491-501 force-drop X-Hero-User so the picker can drive identity. caller_id is never resolved into params.
  2. chat-app.js::startDm doesn't pass caller_id in params either (only created_by).
  3. channel.rs::create: input.caller_id.ok_or(...) short-circuits → Authentication required. The dev bypass is never reached.

Pre-PR-#32, the gate went through check_permission which has if is_dev_mode() { return Ok(()); } at the very top, so dev-mode flows passed through cleanly.

The auth-mode regression check in PR #32 verified the dev-mode case only by passing caller_id explicitly in a hand-crafted curl — which the chat-app does not.

Truth table

Auth mode Network path caller_id reaches handler Pre-fix After fix
dev router-only :9988 None "Authentication required" creates
dev via proxy :9997 None (dev shim drops X-Hero-User) "Authentication required" creates
proxy via proxy :9997 Some(N) membership check membership check
proxy router-only :9988 None Unauthenticated (fail closed) Unauthenticated (fail closed)

Fix in

PR linked below — uses require_caller (the canonical helper already used by channel.rs::member_add) which folds the dev-bypass / proxy-fail-closed / authenticated-caller logic into one match.

### Symptom In `--auth-mode=dev`, every `startDm` click in the chat-app logs: ``` Error: Authentication required at rpc (chat-app.js:382) at async startDm (chat-app.js:3349) at async pickDmUser (chat-app.js:3299) ``` DM never gets created. Reproduced on the dev box (`--auth-mode=dev`, accessed over the Mycelium overlay → `hero_router` on `:9988`). ### Root cause PR #32 (DM permission gate split) replaced the previous `check_permission("channel.create", ...)` call for DMs with a manual: ```rust let caller = input.caller_id.ok_or(RpcError::Unauthenticated)?; if !super::permissions::is_dev_mode() { // workspace-membership probe } ``` The dev-mode bypass on the membership probe is correct, but it sits *after* the `ok_or(Unauthenticated)` line. In the typical dev-mode flow: 1. `main.rs::handle_rpc` lines 491-501 force-drop `X-Hero-User` so the picker can drive identity. caller_id is never resolved into params. 2. `chat-app.js::startDm` doesn't pass `caller_id` in params either (only `created_by`). 3. `channel.rs::create`: `input.caller_id.ok_or(...)` short-circuits → `Authentication required`. The dev bypass is never reached. Pre-PR-#32, the gate went through `check_permission` which has `if is_dev_mode() { return Ok(()); }` at the very top, so dev-mode flows passed through cleanly. The auth-mode regression check in PR #32 verified the dev-mode case only by passing `caller_id` explicitly in a hand-crafted curl — which the chat-app does not. ### Truth table | Auth mode | Network path | caller_id reaches handler | Pre-fix | After fix | |---|---|---|---|---| | dev | router-only `:9988` | None | ❌ "Authentication required" | ✅ creates | | dev | via proxy `:9997` | None (dev shim drops X-Hero-User) | ❌ "Authentication required" | ✅ creates | | proxy | via proxy `:9997` | Some(N) | ✅ membership check | ✅ membership check | | proxy | router-only `:9988` | None | ✅ Unauthenticated (fail closed) | ✅ Unauthenticated (fail closed) | ### Fix in PR linked below — uses `require_caller` (the canonical helper already used by `channel.rs::member_add`) which folds the dev-bypass / proxy-fail-closed / authenticated-caller logic into one match.
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
lhumina_code/hero_collab#40
No description provided.