feat(discord): add /auth slash command for device-flow auth#1185
Open
chaodu-agent wants to merge 9 commits into
Open
feat(discord): add /auth slash command for device-flow auth#1185chaodu-agent wants to merge 9 commits into
chaodu-agent wants to merge 9 commits into
Conversation
Implements a new /auth Discord slash command that executes the OPENAB_AGENT_AUTH_COMMAND env var, captures the device flow URL and code from stdout/stderr, and relays them to the user as an ephemeral Discord message. Flow: 1. User runs /auth 2. OAB execs $OPENAB_AGENT_AUTH_COMMAND (e.g. 'codex login --device-auth') 3. Captures URL+code from stdout within 30s 4. Sends ephemeral followup with auth instructions 5. Waits up to 15min for process to exit (user authorizes in browser) 6. Reports success/failure/timeout Also updates docs/slash-commands.md with /auth documentation.
added 3 commits
June 24, 2026 00:23
- Add is_denied_user access control gate (🔴 #1) - Kill orphaned child process on empty-output early return (🔴 #2) - Add single-flight AtomicBool guard to prevent concurrent /auth (🟡 #4) - Truncate output to fit Discord 2000-char limit (🟡 #5) - Scope readers in a block to drop cleanly before wait (🟡 #6)
Address 擺渡法師 and 口渡法師 review feedback: - Spawn independent tokio tasks for stdout/stderr draining (run to EOF) - Fixes SIGPIPE: pipes stay open while child waits for browser auth - Fixes cancellation safety: no more tokio::select! on next_line() - Fixes asymmetric drain: both streams captured independently - Use tokio::sync::Notify for URL detection signaling - tokio::join! drain tasks before exiting to ensure clean shutdown - Kill + join on empty-output and timeout paths
- /auth now only works in DMs (rejects guild channels with guidance) - Truncation uses chars().take() instead of byte slicing (no panic on multi-byte UTF-8) - Budget calculated with chars().count() for prefix/suffix (correct for Discord's character-based limit) - Updated docs to document DM-only requirement
This comment has been minimized.
This comment has been minimized.
added 2 commits
June 24, 2026 00:56
- child.wait() timeout reduced from 15min to 14min so the final success/failure followup can still be delivered within Discord's 15min interaction token TTL - Docs: added 30s URL-collection window, allowed_users requirement, and single-flight behavior notes
- Replace to_channel() API call with cmd.guild_id.is_some() for DM check (F1) - Add AuthGuard Drop impl to reset AUTH_IN_PROGRESS on task panic (F2) - Add tracing::info/warn at key lifecycle points in spawned task (F3) - Remove redundant manual store(false) calls now covered by Drop guard
This comment has been minimized.
This comment has been minimized.
- Add child.wait() arm to URL-collection select! so a fast-failing auth command reports immediately instead of stalling the full 30s window (#1) - Reject bot users in /auth, consistent with /remind (#8) - Record invoking user_id in the auth start audit log (#7) - Truncate output by UTF-16 code units to match Discord's 2000-char limit, preventing rejection on non-BMP-heavy output (#5) - Handle std::sync::Mutex poison in drain/collect paths to avoid panic cascade and silent output loss (#9) - Clarify the 'no output' error message with cause and remedy (#6) - Fix docs intro contradicting /auth DM-only and mark it DM-only in the command table (#3)
Collaborator
Author
|
CHANGES REQUESTED What This PR DoesAdds a How It Works
Findings
Prior-round resolution detail (head
|
| Prior finding | Status |
|---|---|
🟠 Fast-fail: no child.wait() arm in URL window |
✅ Fixed — res = child.wait() arm sets early_exit |
| 🟠 / 🟡 Doc header contradicts DM-only | ✅ Fixed — opening line now calls out the /auth exception |
| 🟡 UTF-16 vs scalar truncation | ✅ Fixed — encode_utf16().count() + len_utf16() budgeting |
| 🟡 Ambiguous "no output" error | ✅ Fixed — message now states cause + remedy |
| 🟡 Audit log missing invoking user | ✅ Fixed — info!(user_id, ...) |
| 🟡 No bot rejection (inconsistent w/ other handlers) | ✅ Fixed — cmd.user.bot reject added |
🟡 std::sync::Mutex poison cascade |
✅ Fixed — unwrap_or_else(|e| e.into_inner()) |
| 🟡 Timeout path doesn't join drain tasks | ✅ Fixed — tokio::join! runs after the match for all paths |
| 🟡 Process-wide single-flight | ✅ Documented as intended behavior |
| 🟡 500ms trailing-capture heuristic | ⏳ Outstanding (F1 above) |
| 🟡 No regression tests | ⏳ Outstanding (F2 above) |
CI status
check(Rust build/clippy) and thechangesgate: pass.- 14 of 15 smoke-test matrix variants: pass (built in ~6 min each from identical Rust).
- 1 smoke-test variant (
Dockerfile, kiro-cli) failed at the Build image step in ~25s — a transient/infra failure (image pull/build), not a code defect: the same Rust source compiled and ran across every other variant. Recommend a re-run.
Baseline Check
- PR opened: 2026-06-24.
- Main has no
/authcommand orOPENAB_AGENT_AUTH_COMMANDhandling. - Net-new value: a gated, DM-only, ephemeral relay of an agent device-flow login — entirely additive (one new command registration + handler + docs).
added 2 commits
June 24, 2026 01:34
…ht flag Addresses review nit: the AUTH_IN_PROGRESS flag carries no dependent data, so SeqCst is stronger than necessary. Acquire on the guard acquire (swap) and Release on each clear (store) is sufficient and clearer in intent.
Round-2 review feedback: - F1: when the auth command exits 0 during the URL-collection window without producing a login URL, show a warning + retry prompt instead of '✅ Auth command completed.' (avoids false confidence that auth succeeded) - F2: document the early-exit-without-URL error case in slash-commands.md - F3: document bot-user rejection (and DM-only) in the /auth error cases
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
/authDiscord slash command that executes$OPENAB_AGENT_AUTH_COMMANDand relays the device-flow URL + code back to the user via ephemeral DM.Flow Diagram
Security Controls
Architecture
tokio::spawnfor stdout/stderr → run to EOF (no SIGPIPE)tokio::sync::Notify(cancellation-safe)static AtomicBool+Dropguard (panic-safe)cmd.guild_id.is_some()(local field, no API call)chars().take()(UTF-8-safe, Discord 2000-char limit)Changes
crates/openab-core/src/discord.rs— Register + implement/authdocs/slash-commands.md— Full documentationReview History
6 commits, 5 review rounds, 3 reviewers (擺渡/口渡/覺渡/普渡), all LGTM ✅