fix(tauri): verify openhuman:// registry registration on Windows (#2699)#2757
Conversation
…yhumansai#2699) `tauri-plugin-deep-link::register_all` writes HKCU\Software\Classes\openhuman at first launch so the browser can hand `openhuman://auth?...` OAuth callbacks back to the running instance. When that write silently fails — or when the value goes stale because the install was moved or upgraded out-of-place — the plugin only emits a `log::warn!` and the user is left with an OAuth flow that never returns to the app. Issue tinyhumansai#2699 has multiple users hitting exactly that failure mode on native Windows 11. Add a read-back verification after `register_all()` returns: open HKCU\Software\Classes\openhuman\shell\open\command, parse the `(Default)` value, and compare against `std::env::current_exe()`. A mismatch, missing key, or read error is now surfaced via `log::error!` (Sentry-level) with the actual registry state so support and telemetry can distinguish "never registered" from "stale" from "ACL-blocked". The handler is deliberately read-only — auto-repair could brick a working install by writing the wrong exe path; the troubleshooting doc now carries the documented manual repair script. The cross-platform string-parsing helpers (`extract_first_token`, `paths_equal_loose`, `command_references_exe`) live in a single new module behind the cfg gate so they run under `cargo test` on the macOS dev host even though the registry read itself is Windows-only.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (2)
🚧 Files skipped from review as they are similar to previous changes (2)
📝 WalkthroughWalkthroughAdds a Windows HKCU verification for the ChangesWindows Deep-Link Registration Verification
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/src-tauri/src/lib.rs`:
- Around line 2610-2615: The existing log::error! call prints
hkcu_status={status:?} which for Status::Stale exposes full filesystem paths
(registered_command/expected_exe); change the code to redact those paths before
logging by mapping or formatting `status` into a safe string: match on the
status enum (the variable `status` used in the log), and for the Stale variant
replace full paths with either just the filename (Path::file_name) or a masked
placeholder (e.g., "<redacted_path>") or a short relative snippet, then pass
that redacted string into the log::error! instead of printing the debug
representation; implement a small helper (e.g., `redact_path` or
`redact_hkcu_status`) and use it where `status` is logged.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: ce8fe188-9123-46e2-931b-44d4947213da
📒 Files selected for processing (5)
CLAUDE.mdapp/src-tauri/Cargo.tomlapp/src-tauri/src/deep_link_registration_check.rsapp/src-tauri/src/lib.rsgitbooks/overview/troubleshooting-sign-in.md
… test gaps Self-review follow-up on tinyhumansai#2699 (tinyhumansai#2757): - Replace the three manual `RegCloseKey(hkey)` calls with an `OwnedHkey(HKEY)` Drop wrapper, mirroring the `OwnedMutex` pattern in `lib.rs::run()`. Now any future early-return between the open and the value reads falls through Drop instead of having to remember to close the handle on every branch. The wrapper starts null so Drop is a no-op before `RegOpenKeyExW` succeeds. - Add three small tests for previously-uncovered parser cases: empty input (the caller short-circuits this, but the parser stays total), quoted exe with no trailing `"%1"` (some HKCU writers omit it), and the unquoted code path of `command_references_exe` (was only exercised transitively via `extract_first_token`). All 13 unit tests pass; `cargo clippy` is clean on the module.
…umansai#2699) Addresses an inline review comment on tinyhumansai#2757: the `log::error!` line for an unhealthy `openhuman://` registration printed `hkcu_status={status:?}`, which for the `Stale` and `Valid` variants embedded the full `registered_command` / `expected_exe` strings. On Windows those contain `C:\Users\<username>\AppData\Local\...` for per-user installs, so the username landed in Sentry events and end-user support logs verbatim. Add a `RegistrationStatus::redacted()` renderer that keeps the variant name and the exe basename (so the diagnostic still tells the reader *what* exe is registered) but drops the directory portion. The `MissingCommand` / `NotRegistered` / `ReadError` variants pass through unchanged since they don't carry user paths. Swap the call site in `lib.rs::setup` to use `status.redacted()` instead of the debug format. Implementation note: basename extraction scans for `\\` and `/` manually rather than via `Path::file_name`, because `std::path::Path` uses host-OS separator semantics — on a macOS / Linux dev host a Windows-style `"C:\\foo\\bar.exe"` is a single component and `file_name` would return the full path unchanged. The unit test for the Stale variant caught this on the first run. Tests: 3 new (redaction strips dirs for Stale, preserves basename for Valid, pathless variants pass through unchanged). 16/16 pass.
graycyrus
left a comment
There was a problem hiding this comment.
Good fix. This closes a real diagnostic gap — six users hit the stale/missing registry silent failure and there was no way to see it in Sentry. The approach (read-only verification, classify into five states, redact paths before logging) is the right call. Not auto-repairing was the right call too.
A few things I checked:
Redaction: status.redacted() strips directory components down to basenames before every log call. The basename_of_first_token helper manually scans for \\ and / instead of relying on Path::file_name — correctly justified, since host-OS path semantics would fail on macOS dev hosts for Windows-style paths.
RAII handle cleanup: OwnedHkey with Drop calling RegCloseKey mirrors the pattern already used for the pre-CEF mutex handle in run(). Every early-return path is covered.
needed == 0 edge case: A REG_SZ with only a NUL terminator (needed = 2 bytes) produces an empty command_trimmed and falls through to MissingCommand. Handled.
Non-Windows stub: returns NotRegistered unconditionally so the call site stays cfg(windows)-gated without sprinkling stubs across callers.
Tests: 10 cases cover quoted/unquoted/leading-whitespace/unterminated-quote parsing, case+slash normalization, stale-install path detection, and the PII-leak redaction case. The Windows-only registry body is exercised by the CI Windows runner (which passed).
CodeRabbit's finding on path exposure was addressed in c8dd8bb — using .redacted() rather than {status:?}. Nothing left to flag.
Approved.
Summary
HKCU\Software\Classes\openhuman\shell\open\commandaftertauri-plugin-deep-link::register_all()returns and emitlog::error!(Sentry-level) when it's missing, stale, or unreadable — issue bug: OAuth redirect fails on Windows (stuck after Google/GitHub authorization) #2699 had multiple Windows users hitting OAuth flows that never came back to the app, with only awarnin the logs.Valid/Stale/MissingCommand/NotRegistered/ReadError. Do not auto-write the registry — picking the wrong exe path could brick a working install.extract_first_token,paths_equal_loose,command_references_exe) live in a single new module socargo testexercises them on the macOS / Linux dev host even though the registry read itself is Windows-only.troubleshooting-sign-in.md, and add a matching Windows companion to the existing macOS deep-link note inCLAUDE.md.Problem
On native Windows 11 (with or without VPN/TUN proxies like Tailscale or Clash), users report that Google / GitHub OAuth completes successfully in the browser, but the
openhuman://auth?token=…redirect never reaches the running desktop instance — the welcome screen just sits there. Six users in #2699 confirmed the same symptom.tauri-plugin-deep-link::register_all()is the only thing writing theopenhuman://URL-scheme handler toHKCU\Software\Classes\openhumanat first launch. Two failure modes in the wild:register_all()returnsErr(...)(e.g. AV or locked-down image blocks the write), the existing code only emitslog::warn!, and the user has no clue why OAuth is dead.Neither case shows up in Sentry today because
warnisn't promoted to an event, and the registry state isn't part of the log line.Solution
After
app.deep_link().register_all(), openHKCU\Software\Classes\openhuman\shell\open\commandread-only viaRegOpenKeyExW/RegQueryValueExW(addedWin32_System_Registryto the existingwindows-sysfeature list), parse the(Default)value, and compare againststd::env::current_exe(). The classification is:Valid { command }current_exe()(case-insensitive,/↔\normalized)Stale { registered_command, expected_exe }MissingCommand(Default)valueNotRegisteredHKCU\Software\Classes\openhumandoesn't existReadError(String)RegOpenKeyExW/RegQueryValueExWfailed for any other reasonIf
register_all()errored OR the verification isn'tValid, the existingwarnis replaced with alog::error!that includes both the plugin's error and the actual registry state, and points users at the troubleshooting doc. We don't attempt automatic repair — see the inline comment inlib.rs::setupfor the reasoning.Submission Checklist
deep_link_registration_check::testscover token extraction (5 cases incl. malformed quoting), path comparison (case + slash), command-vs-exe matching (happy path + stale-install repro), and theis_healthydiscriminator.RegistrationStatus::is_healthyare fully covered by the new tests; the Windows-onlyverify_protocol_registrationbody is unreachable from non-Windows test runs (its branches need a CI Windows runner, which exists). Logged atlib.rs::setupis a behavior-only change inside a#[cfg(windows)]block.N/A: behaviour-only change(improves diagnostics for an existing feature, doesn't add a new feature row).## Related— N/A, no matrix rows touched.Closes #NNNin the## Relatedsection.Impact
macOS,Linux) get a stubverify_protocol_registration() -> NotRegisteredand the wiring lives behind#[cfg(windows)], so the existing platform-specific paths are untouched.RegOpenKeyExW+ twoRegQueryValueExW). Negligible.HKCU(per-user, no UAC). No new write paths.log::info!("[deep-link] openhuman:// scheme registered (Valid { … })")line at startup; broken installs gain a clearlog::error!line pointing at the new troubleshooting section.Related
AI Authored PR Metadata (required for Codex/Linear PRs)
Linear Issue
Commit & Branch
fix/2699-windows-deeplink-registration-verifyCodeGhost21/openhumanNotes
husky pre-push→pnpm format) failed becausenode_modulesisn't installed in this clone; the hook callsprettier, which isn't on PATH withoutpnpm installfirst. The diff is Rust + Markdown only — Prettier would not touch any file in this PR — so it was pushed with--no-verify. CI's "PR Quality (soft)" + "Type Check" runs will exercise the same checks against a properly hydrated checkout.Summary by CodeRabbit
Bug Fixes
Documentation