feat(cli): open the browser on auth login - #1827
Conversation
Merge Protections🔴 2 of 6 protections blocking · waiting on 👀 reviews
🔴 👀 Review RequirementsWaiting for
This rule is failing.
🔴 🔎 ReviewsWaiting for
This rule is failing.
Show 4 satisfied protections🟢 🤖 Continuous Integration
🟢 Enforce conventional commitMake sure that we follow https://www.conventionalcommits.org/en/v1.0.0/
🟢 📕 PR description
🟢 🚦 Auto-queueWhen all merge protections are satisfied, this pull request will be queued automatically. |
Revision history
|
cd108df to
bf111ea
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Resolve the clippy failure and add parser/dispatch regression coverage.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
Adds automatic browser opening to auth login while preserving printed URLs and headless support.
Changes:
- Adds
--no-browserand updates CLI wiring. - Implements platform-specific browser launching.
- Updates login messaging, documentation, and CLI schema.
File summaries
| File | Summary |
|---|---|
README.md |
Documents browser-opening behavior. |
crates/mergify-cli/src/snapshots/mergify__tests__cli_schema_golden.snap |
Updates the CLI schema snapshot. |
crates/mergify-cli/src/main.rs |
Adds and dispatches --no-browser; missing parser/dispatch regression coverage (moderate, 2 votes). |
crates/mergify-auth/src/login.rs |
Opens and reports the verification URL. |
crates/mergify-auth/src/lib.rs |
Exposes the browser module. |
crates/mergify-auth/src/browser.rs |
Implements platform-specific launchers; unused JoinHandle causes the clippy lint gate to fail (critical, 1 vote). |
Review details
Suppressed comments (2)
crates/mergify-auth/src/browser.rs:143
std::thread::spawnpanics if the OS cannot create the reaper thread. That turns this browser convenience into a fatal login crash under thread/resource exhaustion, contradicting the documented non-fatal behavior and the no-panics command-path rule. Use a falliblethread::Builder::spawnand define a fallback that still handles the child if the reaper cannot be created.
std::thread::spawn(move || {
let mut child = child;
let _ = child.wait();
});
crates/mergify-auth/src/browser.rs:143
- The reaper discards the result of
wait, so an opener that launches successfully but exits non-zero (or cannot be waited on) produces nodebug!line andopenis reported as successful. Log non-success statuses and wait errors here so the promised best-effort failure path remains observable without failing login.
let mut child = child;
let _ = child.wait();
});
- Files reviewed: 6/6 changed files
- Comments generated: 2
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
bf111ea to
65c58ec
Compare
|
This pull request is part of a Mergify stack:
|
`auth login` printed a URL and left the user to click it. It now opens the approval page itself, which is the last bit of ceremony between running the command and approving the grant. Opening is a convenience and never a step in the flow: - The URL is still printed, always. A CI runner, a container and an SSH session have no browser to open, and a spawned opener is not a window on screen either — the terminal is the only place the user can be sure to find the address again. The instructions say "Opening your browser […] If nothing opens, go to:" only when an opener actually started, so the line never claims something that did not happen. - `--no-browser` skips it. - Every failure is a `debug!` line. The login proceeds either way. No crate for it: each platform is one spawn (`open`, `xdg-open`, `cmd /C start`), which is not worth a dependency under `deny.toml`. Three things that are not obvious in those twenty lines: - Nothing is spawned when the screen the opener would use is not the one the user is looking at. On Linux that is an unset `DISPLAY` and `WAYLAND_DISPLAY`, where `xdg-open` falls through to a terminal browser (`www-browser`, `w3m`, `lynx`) and takes over the very terminal the code is being read from; on macOS, which has no `DISPLAY` to consult, it is `SSH_CONNECTION` / `SSH_TTY`, where `open` reaches the screen of whoever is sitting at the machine and hands them a page carrying somebody else's user code. The SSH session is one of the reasons the device grant exists, so it gets the printed URL and nothing else. - On Windows, `start` is a `cmd` builtin, so the URL goes through a shell that re-parses it, where `&` separates commands and `%NAME%` is expanded — after any check we run, inside quotes as well as out, with no escape available on a command line. The URL is quoted, and one holding a `"` or a `%` is refused rather than opened: the quote because it would close the quoting, the `%` because the value spliced in is not held to the rule the check just applied, and because a substituted URL would open a different page than the one printed. The host that writes that URL is whatever `--api-url` names, the same threat `device::checked_uri` already guards. - The opener's child is reaped on a thread. `login` then sits in the poll loop for minutes, and a child nobody waits on is a zombie for all of it. That thread is asked for fallibly, because `thread::spawn` panics when the OS refuses one and a panic is the one way this convenience could still take the login down. A zombie until the process exits is the cheaper of the two. The browser is a trait so the suite can watch the URL go past without opening a window on whoever ran `cargo test`. Refs MRGFY-9262 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Change-Id: I90e2ca4c0ce90afa95b3700a3c0acd35c1b0a135
65c58ec to
15ef21b
Compare
auth loginprinted a URL and left the user to click it. It now opensthe approval page itself, which is the last bit of ceremony between
running the command and approving the grant.
Opening is a convenience and never a step in the flow:
SSH session have no browser to open, and a spawned opener is not a
window on screen either — the terminal is the only place the user
can be sure to find the address again. The instructions say
"Opening your browser […] If nothing opens, go to:" only when an
opener actually started, so the line never claims something that did
not happen.
--no-browserskips it.debug!line. The login proceeds either way.No crate for it: each platform is one spawn (
open,xdg-open,cmd /C start), which is not worth a dependency underdeny.toml.Three things that are not obvious in those twenty lines:
one the user is looking at. On Linux that is an unset
DISPLAYandWAYLAND_DISPLAY, wherexdg-openfalls through to a terminalbrowser (
www-browser,w3m,lynx) and takes over the veryterminal the code is being read from; on macOS, which has no
DISPLAYto consult, it isSSH_CONNECTION/SSH_TTY, whereopenreaches the screen of whoever is sitting at the machine andhands them a page carrying somebody else's user code. The SSH
session is one of the reasons the device grant exists, so it gets
the printed URL and nothing else.
startis acmdbuiltin, so the URL goes through ashell that re-parses it, where
&separates commands and%NAME%is expanded — after any check we run, inside quotes as well as out,
with no escape available on a command line. The URL is quoted, and
one holding a
"or a%is refused rather than opened: the quotebecause it would close the quoting, the
%because the valuespliced in is not held to the rule the check just applied, and
because a substituted URL would open a different page than the one
printed. The host that writes that URL is whatever
--api-urlnames, the same threat
device::checked_urialready guards.loginthen sits in thepoll loop for minutes, and a child nobody waits on is a zombie for
all of it. That thread is asked for fallibly, because
thread::spawnpanics when the OS refuses one and a panic is theone way this convenience could still take the login down. A zombie
until the process exits is the cheaper of the two.
The browser is a trait so the suite can watch the URL go past without
opening a window on whoever ran
cargo test.Refs MRGFY-9262
Co-Authored-By: Claude Opus 5 (1M context) noreply@anthropic.com