Originally created by: adityaharishch
Summary
- Closing the OAuth browser tab mid-flow left the tray's in-flight guard held for the full 5-minute
CONSENT_TIMEOUT, so "Try again" (a pure UI no-op) just re-hit "already in progress"
- Switches the spawned OAuth task to
tokio::spawn, stores its JoinHandle, and adds a cancel_oauth command that aborts it + clears the flag immediately
- Wires this into "Try again", unmount-while-waiting, and a new "Not going through? Cancel" link for the case where Atlassian's own consent screen blocks (e.g. no Jira site access) and never redirects back at all
Stacked on prior PRs in this chain.
Test plan
- [x]
cargo fmt --check, cargo build -p meridian-tray, cargo clippy -p meridian-tray -- -D warnings, cargo test -p meridian-tray -p meridian-oauth
Originally posted by: coderabbitai[bot]
✨ Finishing Touches
🧪 Generate unit tests (beta)
- [ ] Create PR with unit tests - [ ] Commit unit tests in branch `fix/jira-oauth-stuck-cancel`Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
❤️ Share
- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai) - [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai) - [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai) - [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)Comment
@coderabbitai helpto get the list of available commands.Originally posted by: Akarsh-Hegde
Review — cancel a stuck jira/trello browser OAuth attempt
Summary: Switches the spawned jira/trello OAuth task to a
tokio::spawnwhoseJoinHandleis stored, so a newcancel_oauthcommand can.abort()it and clear the in-flight guard immediately; wired into "Try again", unmount-while-waiting, and a new manual "Cancel" link.Blocking / correctness issues
1.
cancel_oauth's argument shape doesn't match howmutateinvokes it — the command always fails silently, so the fix never actually runs.mutateinvokes commands asinvoke(command, { body })— it wraps the payload under abodykey (ui/lib/bridge.ts:105, and the doc comment right below it). That's why every sibling write command takes a struct:start_oauth(body: StartOAuthBody),disconnect_integration(body: DisconnectBody),save_integration_token(body: SaveTokenBody).But the new command is
pub async fn cancel_oauth(provider: String), called viamutate('/api/auth/oauth/cancel', 'cancel_oauth', { provider })→invoke('cancel_oauth', { body: { provider } }). Tauri looks for a top-levelproviderkey, finds onlybody, and rejects with a missing-argument error.Failure scenario: user closes the OAuth tab → clicks "Try again" →
cancelAndResetfirescancelOAuth(fire-and-forget,.catch(() => {})), so the rejection is swallowed. The backendcancel_oauthnever executes →JIRA_OAUTH_IN_FLIGHTstaystruefor the full 5-minCONSENT_TIMEOUT. The UI resets to idle, the user clicks Connect, andstart_oauthreturns "jira OAuth is already in progress" — i.e. the exact bug this PR set out to fix, now hidden behind a UI that looks reset. Rust tests +cargo clippycan't catch it (JS↔Tauri arg-shape mismatch, no TS tests).Fix: give it a
body: CancelOAuthBody { provider: String }struct like the othermutate-invoked commands (preferred), or invoke it via a rawinvoke('cancel_oauth', { provider })the wayget_oauth_status(provider: String)is called. Please exercise the real cancel→retry flow in a packaged/dev build before merge.Suggestions / nits
in_flightis alreadyfalseand a completedJoinHandlestill sits in the slot.cancelAndResetfirescancelOAuthfire-and-forget, then Connect spawns a fresh task and overwrites the slot. If the earliercancel_oauthlands after that store, it.take()s and.abort()s the brand-new live task. Narrow, but real — either skipcancelOAuthwhen already inerrorstate (nothing to free), or key the abort to a generation/id.CONSENT_TIMEOUTisDuration::from_secs(300)= 5 min (meridian-oauth/src/flow.rs:52), andcancel_oauth's own doc comment correctly says 5 min. Align them.Mutexslot until the next start/cancel — harmless (.abort()on a finished task is a no-op); could*handle_slot.lock().unwrap() = Noneon completion for tidiness.handle_slot.lock().unwrap()usesunwrap()(discouraged outside tests); critical sections are trivial so poisoning is effectively impossible — just noting it against the convention.Verified correct
cancel_oauthregistered inlib.rs'sinvoke_handler!; custom app commands aren't ACL-gated in Tauri 2, so nocapabilities/default.jsonchange needed (consistent withstart_oauth/get_oauth_status).#[tracing::instrument]+ structuredtracing::info!(provider = …).cancel_oauth(take+abort handle, then clearin_flight) correctly prevents a normal Try-again→Connect from aborting the retry task.statusRefmirror to dodge the stale-closure in the[tracker.id]cleanup is sound.Verdict: Needs changes — blocking issue [#1] defeats the PR's entire purpose at runtime while compiling and passing all listed checks. Small fix, but must be corrected and manually verified end-to-end before merge.
🤖 Automated review via Claude Code
Related
Tickets:
#1Ticket changed by: adityaharishch