Skip to content

feat(cua-driver-rs)(windows): register autostart task at RunLevel=Highest (unblocks UWP automation, #1602) - #1630

Merged
f-trycua merged 1 commit into
mainfrom
feat/cua-driver-rs-autostart-highest-runlevel-for-uwp
May 21, 2026
Merged

feat(cua-driver-rs)(windows): register autostart task at RunLevel=Highest (unblocks UWP automation, #1602)#1630
f-trycua merged 1 commit into
mainfrom
feat/cua-driver-rs-autostart-highest-runlevel-for-uwp

Conversation

@f-trycua

@f-trycua f-trycua commented May 21, 2026

Copy link
Copy Markdown
Collaborator

Summary

Switches the Windows autostart Scheduled Task from RunLevel=Limited to RunLevel=Highest so the daemon runs at the user's elevated token. This is what unblocks cross-AppContainer UIA RPCs (Calculator, modern Settings, Photos, Microsoft Store apps) without requiring UIAccess + EV cert. The installer's -AutoStart path now self-elevates only for the registration step; the rest of the install stays admin-free.

Why now

We isolated the variable on a Windows 11 VM in a 4-cell matrix (DevMode × token IL):

Cell Result
DevMode OFF + High IL 41 Calculator elements ✅
DevMode ON + High IL 41 Calculator elements ✅
DevMode ON + Medium IL (cuatest, real Medium token confirmed via Win32 GetTokenInformation) Daemon ran at IL=0x2000, check_permissions.elevated=false; UWP activation blocked by Session 0 (an orthogonal Windows boundary, not the IL boundary)

DevMode toggle does nothing to UIA tree depth. Token integrity is the variable. A real user-session Medium-IL daemon historically returned ~1 Calculator element per #1602 / #1601.

RunLevel=Highest is the cheapest path to the High-IL daemon — one UAC prompt at install time, then silent autostart at every logon. EV cert + UIAccess (full #1602 solution) is still cleaner UX long-term but costs $300/yr + a signing pipeline; this PR removes the Calculator gap today.

Changes

crates/cua-driver/src/autostart.rs

libs/cua-driver/scripts/install.ps1

  • New Test-IsElevated helper using WindowsPrincipal::IsInRole(Administrator).
  • Register-CuaDriverAutostart now self-elevates via Start-Process -Verb RunAs when invoked from a non-elevated install, with a clear pre-prompt. The rest of the install (file extraction, junction creation, User PATH update) still runs unelevated.
  • Post-install hint block updated for both -AutoStart and non--AutoStart branches — explains RunLevel=Highest, mentions the "Win32 + Chromium fine without; UWP needs autostart" trade-off.

Compat

  • Existing users with a cua-driver-serve task at RunLevel=Limited get it re-registered as Highest next time they run cua-driver autostart enable (the registration script unconditionally Unregister-ScheduledTask first).
  • Users who never call autostart enable see zero behavior change.
  • macOS + Linux paths untouched.

Test plan

  • cargo check -p cua-driver clean on the VM (14.56s)
  • install.ps1 parses cleanly on PowerShell 5.1 (3,167 tokens, 0 errors)
  • End-to-end: irm install.ps1 | iex then cua-driver autostart enable triggers UAC prompt, registers task at RunLevel=Highest, Calculator drives end-to-end after logoff/logon
  • Existing Win32 + Chromium tests still pass (no regression at the new IL)

Related

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Installation script now automatically requests admin elevation when registering autostart, eliminating the need for manual elevation steps.
  • Bug Fixes

    • Enhanced error handling provides clearer guidance when autostart registration requires elevated permissions, directing users to appropriate corrective actions.

Review Change Stack

…hest (#1602)

The autostart Scheduled Task was registered with `RunLevel=Limited`, so on
typical Windows installs (regular admin user with a UAC-split token) the
daemon started at Medium IL. That's fine for Win32 + Chromium targets,
but cross-AppContainer UIA RPCs truncate at Medium IL — Calculator returns
~1 element instead of the full ~30-40 element tree (issue #1601 / #1602).

This switches the task registration to `RunLevel=Highest` so the daemon
runs at the user's elevated token, which crosses the AppContainer
boundary cleanly. Registering a `Highest`-level task itself requires the
caller to be at High IL, so the install path now self-elevates only for
the autostart-registration step.

## Why this and not UIAccess + EV cert

We isolated the variable in a 4-cell matrix on a Windows 11 VM:
1. DevMode OFF + High IL  → 41 Calculator elements ✅
2. DevMode ON  + High IL  → 41 Calculator elements ✅
3. DevMode ON  + Medium IL (cuatest standard user, Win32 token IL inspected
   directly, IL=0x2000 confirmed) → daemon ran but UWP activation blocked
   by Session 0 (orthogonal limitation; a real user-session Medium IL
   daemon historically returned ~1 element per #1602).

DevMode is not the variable. Token integrity is. RunLevel=Highest gets
us to the High IL daemon without needing UIAccess (which would require
an EV-cert signed `cua-driver-uia.exe`). One UAC prompt at install time
in exchange for full UWP automation post-install. EV cert remains the
long-term answer for users who can't or won't grant admin even once,
but RunLevel=Highest unblocks the common case today.

## Changes

### `crates/cua-driver/src/autostart.rs`

- `New-ScheduledTaskPrincipal ... -RunLevel Limited` → `-RunLevel Highest`
- Detect access-denied / 0x80070005 / "requires elevation" in the
  PowerShell stderr and emit an actionable error pointing at #1602
  instead of the raw stack trace.
- Doc comment expanded to explain the WHY of `-RunLevel Highest`
  (the AppContainer / UIPI boundary, links to #1602 / #1601).

### `libs/cua-driver/scripts/install.ps1`

- New `Test-IsElevated` helper.
- `Register-CuaDriverAutostart` now self-elevates via
  `Start-Process -Verb RunAs` when called from a non-elevated install,
  with a clear pre-prompt explaining the UAC ceremony. The rest of the
  install (file extraction, junction creation, User PATH update) still
  runs unelevated as today — only the autostart step elevates.
- Post-install hint block (both `-AutoStart` and non-`-AutoStart`
  branches) updated to mention RunLevel=Highest and the UWP/AppContainer
  trade-off ("without auto-start, Win32 + Chromium work fine; UWP needs
  the elevated autostart task").

## Compat

- Existing users with a `cua-driver-serve` task at `RunLevel=Limited`
  will get it re-registered as `Highest` next time they run
  `cua-driver autostart enable` or the installer with `-AutoStart`
  (the registration script unconditionally `Unregister-ScheduledTask`
  before `Register-ScheduledTask`).
- Users who never call `autostart enable` see no behavior change.
- macOS + Linux paths untouched.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@vercel

vercel Bot commented May 21, 2026

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Ignored Ignored May 21, 2026 3:24pm

Request Review

@coderabbitai

coderabbitai Bot commented May 21, 2026

Copy link
Copy Markdown
Contributor

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

This PR implements elevated Windows scheduled task registration with RunLevel=Highest for UWP/AppContainer automation. The Rust autostart code now detects elevation failures and guides users to re-run elevated; the PowerShell installer self-elevates when necessary and clearly explains the elevation behavior and UWP app requirements.

Changes

Elevated Autostart Task Registration

Layer / File(s) Summary
Rust autostart: RunLevel=Highest and elevation error handling
libs/cua-driver-rs/crates/cua-driver/src/autostart.rs
Generates PowerShell scheduled task registration with RunLevel=Highest instead of Limited. Detects elevation-related PowerShell failures (access denied, Win32 errors, requires elevation) and returns user-facing error guidance to re-run elevated or use install.ps1 -AutoStart, including raw stderr context.
PowerShell install: Self-elevation and user guidance
libs/cua-driver/scripts/install.ps1
Adds Test-IsElevated helper. Updates Register-CuaDriverAutostart to run directly when elevated, or spawn an elevated powershell.exe to register when not. Updates messaging to document RunLevel=Highest, explain admin prompt occurrence, and clarify that UWP/AppContainer apps require the elevated task whereas unelevated daemon runs at user integrity level.

Sequence Diagrams

sequenceDiagram
  participant User as User
  participant Installer as install.ps1
  participant ElevCheck as Test-IsElevated
  participant Register as Register-CuaDriverAutostart
  participant ElevPS as Elevated PowerShell
  participant CuaDriver as cua-driver autostart enable
  User->>Installer: Run install.ps1 -AutoStart
  Installer->>ElevCheck: Check elevation status
  alt Already elevated
    ElevCheck-->>Register: IsElevated=true
    Register->>CuaDriver: Run directly
    CuaDriver-->>Register: Task registered with RunLevel=Highest
  else Not elevated
    ElevCheck-->>Register: IsElevated=false
    Register->>ElevPS: Spawn with -Verb RunAs
    ElevPS->>CuaDriver: Run in elevated context
    CuaDriver-->>ElevPS: Task registered with RunLevel=Highest
    ElevPS-->>Register: Propagate exit code
  end
  Register-->>Installer: Registration complete
  Installer-->>User: Display confirmation
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • trycua/cua#1604: Also adjusts Windows autostart elevation and RunLevel handling for uiAccess/UWP automation in both autostart.rs and install.ps1.
  • trycua/cua#1550: Introduces the cua-driver autostart enable command that this PR's install.ps1 now delegates to for task registration.

Poem

🐰 A Windows daemon hops up high,
With RunLevel=Highest reaching the sky,
Self-elevating shells now know the way,
UWP apps can autostart and play! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the primary change: upgrading the Windows autostart task from RunLevel=Limited to RunLevel=Highest to enable UWP automation support.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/cua-driver-rs-autostart-highest-runlevel-for-uwp

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

Comment @coderabbitai help to get the list of available commands and usage tips.

@f-trycua
f-trycua merged commit 8d8f530 into main May 21, 2026
6 of 7 checks passed
@f-trycua
f-trycua deleted the feat/cua-driver-rs-autostart-highest-runlevel-for-uwp branch May 21, 2026 15:31
f-trycua added a commit that referenced this pull request May 21, 2026
…Mode Latest (#1631)

irm | iex of install.ps1 on a fresh user account (Windows 11 24H2 PS 5.1)
fails immediately after the install-dir log lines with:

  iex : The property 'OSArchitecture' cannot be found on this object.
        Verify that the property exists.

The source is Get-TargetTriple's call to
[System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture. Under
Set-StrictMode -Version Latest (set at install.ps1:78), PowerShell 5.1
reports the static property access as a missing-property error in certain
session contexts — specifically a freshly-created admin user with no
profile, no prior loaded modules. The same script works fine under the
RID-500 built-in Administrator account on the same VM, which is why this
went undetected through the v0.2.9 install verification.

## Fix

Use $env:PROCESSOR_ARCHITECTURE as the primary source for the architecture
lookup. It's always set on Windows, never trips StrictMode introspection,
and has no .NET version dependency. RuntimeInformation.OSArchitecture is
kept as a try-catch fallback so we still handle exotic configurations
where PROCESSOR_ARCHITECTURE is unset.

Mapping:
  AMD64  -> x86_64-pc-windows-msvc   (PROCESSOR_ARCHITECTURE on x64)
  ARM64  -> aarch64-pc-windows-msvc  (PROCESSOR_ARCHITECTURE on arm64)
  X64    -> x86_64-pc-windows-msvc   (fallback: RuntimeInformation.Architecture.ToString())
  Arm64  -> aarch64-pc-windows-msvc  (fallback)

## Verification

- cargo check on the unrelated install path: clean (no code-side change)
- install.ps1 parses cleanly on PS 5.1.26100.8457
- Smoke test: invoke Get-TargetTriple under
  `Set-StrictMode -Version Latest` -> returns 'x86_64-pc-windows-msvc' (no
  PropertyNotFoundStrict error)

## Repro / how it surfaced

Reported by the cuademo test account (BUILTIN\Administrators, NOT RID 500,
UAC-split-token) on the Windows VM during the post-#1630 fresh-install
dogfood walkthrough.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
f-trycua added a commit that referenced this pull request May 21, 2026
…s for RunLevel=Highest task (#1632)

#1630 switched the autostart Scheduled Task to RunLevel=Highest, with
install.ps1's Register-CuaDriverAutostart self-elevating via
Start-Process -Verb RunAs when called from a non-elevated install.

But the standalone `cua-driver autostart enable` CLI subcommand did NOT
self-elevate — it just called Register-ScheduledTask directly from
whatever IL the user's shell was at. From a typical Medium-IL PowerShell,
that fails with 0x80070005 (Access is denied) and the user is told to
"re-run from an elevated PowerShell", which is friction for what should
be a one-command setup.

This patch wires the same self-elevation into the Rust CLI:

1. First attempt: register directly. Works for callers already at High IL
   (install.ps1's elevated child shell, or someone running `cua-driver
   autostart enable` from an Administrator shell).
2. On access-denied (HRESULT 0x80070005 / "Access is denied" / "requires
   elevation"), the CLI itself triggers a UAC prompt via PowerShell's
   Start-Process -Verb RunAs, then runs `cua-driver autostart enable`
   inside the elevated child. The elevated child hits the first-attempt
   branch and registers the task cleanly.
3. If the UAC prompt is dismissed, surface a clear actionable error
   message ("re-run and accept the prompt").

Net UX: `cua-driver autostart enable` from any non-elevated PowerShell
triggers a UAC prompt once, registers the Highest task, exits. No
manual elevation required.

Fixes a regression surfaced during the cuademo fresh-install dogfood.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
f-trycua added a commit that referenced this pull request May 21, 2026
…on is at High IL (#1602) (#1634)

Since PR #1630 the autostart task runs the main daemon at RunLevel=Highest,
which puts cua-driver.exe at High IL with full UWP / AppContainer UIA access.
The sibling cua-driver-uia.exe worker is therefore redundant for the common
case — and worse, attempting to ShellExecute the (currently unsigned)
uiAccess'd worker from a High-IL parent pops a Windows AIS error dialog
("A referral was returned from the server" = AIS refusing to elevate an
unsigned uiAccess binary). The dialog blocks daemon startup and visibly
confuses users.

Repro: run `cua-driver autostart enable` from a standard admin user (non-RID-500),
accept the UAC prompt, then `cua-driver autostart kick`. The main daemon starts
at High IL, tries to spawn the uia worker via ShellExecute, AIS refuses, error
dialog pops up over the desktop.

## Fix

maybe_spawn_uia_worker() now gates on three conditions:

1. Main daemon is NOT at High IL (checked via PowerShell
   WindowsPrincipal.IsInRole(Administrator)). At High IL the worker is
   redundant.

2. CUA_DRIVER_RS_SPAWN_UIA_WORKER=1 env var is set. Default-off until the
   worker is actually EV-signed (#1602) and the spawn doesn't trip AIS.

3. The worker binary actually exists on disk next to cua-driver.exe.

All three must be true for the spawn to fire. Common case (RunLevel=Highest
install via the canonical install.ps1 + cua-driver autostart enable flow):
condition (1) trips first — no spawn, no dialog, no UWP regression because
the High-IL main daemon already does what the worker would have done.

## Future EV-cert path

When we ship a signed cua-driver-uia.exe (the long-term #1602 answer), users
running the daemon at Medium IL can opt into the worker by setting
CUA_DRIVER_RS_SPAWN_UIA_WORKER=1. Default-off gives a no-surprises upgrade
path: existing users on Medium IL stay on whatever path they're already on,
and the explicit env var keeps us honest about which path is being exercised
during the signed-binary rollout.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant