fix(cua-driver): keep Windows autostart on the junction path - #2809
Conversation
There was a problem hiding this comment.
Pull request overview
Updates Windows autostart registration so the Scheduled Task stores the junction path to cua-driver.exe (rather than a canonicalized, version-pinned release path), ensuring upgrades that flip current are picked up automatically. This aligns the implementation with the intended Windows upgrade behavior described in #2137.
Changes:
- On Windows, stop canonicalizing
std::env::current_exe()when computing the autostart executable path (preserves the junction chain). - Keep canonicalization on non-Windows platforms to resolve symlink chains.
- Expand/update documentation around why Windows must not canonicalize this path.
Suppressed comments (1)
libs/cua-driver/rust/crates/cua-driver/src/autostart.rs:163
- On Windows, stripping the
\\?\extended-length prefix unconditionally can change semantics for UNC paths (\\?\UNC\server\share\...) and can break long paths where the prefix is required to exceed MAX_PATH. Since the comment says this is for readability, it should only strip in the safe\\?\C:\...case (and ideally only when the unprefixed path is short enough).
#[cfg(target_os = "windows")]
let path = path
.strip_prefix(r"\\?\")
.map(str::to_owned)
.unwrap_or(path);
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
abb4328 to
5a2ba38
Compare
`current_exe_for_autostart` canonicalised the executable path before baking it
into the Scheduled Task. On Windows that resolves the
`bin -> current -> releases/<version>` junction chain down to a versioned
release path, so flipping `current` during an upgrade has no effect: the task
keeps launching the previous build — the opposite of what the doc comment
promises.
Since the 0.15 action-result contract change this is no longer a silent version
skew. On a machine upgraded to 0.17.0 while the task still pointed at the
0.14.1 release, every call fails:
Cua Driver daemon on \.\pipe\cua-driver is incompatible: invalid daemon
response: incompatible daemon: contract version 0.2.0 does not match SDK 0.6.0
Re-running `autostart enable` does not repair it for a normal user: the task is
registered with RunLevel=HighestAvailable, so from a non-elevated shell the
rewrite silently does nothing while reporting success.
Windows now stores the path as invoked; other platforms keep canonicalize for
symlink resolution.
Verified with `cargo check -p cua-driver` on the pinned 1.97.1 toolchain.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…aths Two review nits on the surrounding code: - the doc comment claimed non-Windows paths are canonicalised, while the implementation falls back to the non-canonical path on error — say "best-effort" so the doc matches the code - the `\?\` strip was unconditional, which mangles the UNC namespace (`\?\UNC\server\share` -> `UNC\server\share`) and would break paths that need the prefix to exceed MAX_PATH. Restrict it to `\?\<drive>:\...` under 260 chars.
`cargo fmt --all -- --check` (the pinned 1.97.1 toolchain the CI job uses) reflowed the inline byte checks. Pull them into a small named helper instead, which reads better than the wrapped chain.
5a2ba38 to
0cc94db
Compare
f-trycua
left a comment
There was a problem hiding this comment.
Reviewed final two-file diff at 0cc94db. Exact Windows installer/Scheduled Task run 30969836896 passed the invoked-junction premise, real current-retarget launch, released migration, and source-provenance smoke; all repository checks pass and contributor attribution is preserved.
Summary
bin -> current -> releases/<version>junction path so upgrades can retargetcurrentwithout rewriting the Scheduled TaskAddresses #2137.
Why
The Windows installer exposes
cua-driver.exethrough two directory junctions:Canonicalising the executable path before registration resolves that chain to a versioned release path. The Scheduled Task is then pinned to the old release when an upgrade retargets
current.On Windows this change stores the executable path returned for the invoked junction path without calling
canonicalize. Directly invoking a versioned executable still registers that exact versioned path.Native Windows result
Windows preserves the invoked path here. A test executable launched through the production-shaped two-junction chain reported the visible
binpath from the samecurrent_exe_for_autostart()function used for task registration; it did not report the canonical release path.The end-to-end Scheduled Task regression then:
cua-driver.exebehindbin -> current -> probe-v1;autostart enablethroughbinand verified the task action retained that visible path;currentto a separately builtprobe-v2executable without modifying the task;probe-v2executed and reported its version marker.This proves both the Windows
current_exe()premise and the actual Task Scheduler upgrade behavior. The next-version fixture is synthetic so the regression is deterministic; the same run separately passed the released installer/reinstall migration smoke and the source-built local install/daemon smoke.Validation
Final head:
0cc94db92bab723e929a8428c486a17ab76f339aBase:
32f0ef8537c503918116ab7d4cc4c1c262c508700cc94db92bab723e929a8428c486a17ab76f339a: passedcurrent_exe_for_autostart()caseget_config: passed;source_shawas0cc94db92bab723e929a8428c486a17ab76f339a, version0.17.0rust-windows-install-localartifact8916283387:d22e3bd98c6ec45fc7d3077301b30cb628c602f941e9291ead0c63f6c270f4064bd6213fdbfebac8985b2e541b0dd0bc52a823c9b71a4db88dcae2e9db4942e405c732d9cceacfaac027a2c7dce72b99354f70a1cb9419e9aeae306611cfd58cba6f86b65206c63124369c928b024b84044f3b3734ca4ce877d8a0f6173897fbContributor attribution is preserved across the rebase: Roman Syuzyov remains author of all three contributed commits.