Skip to content

(feat) restart UI process after automatic update#2155

Merged
stenya merged 3 commits intodevelopmentfrom
feature/s40-restart_ui_on_upgrade
Apr 10, 2026
Merged

(feat) restart UI process after automatic update#2155
stenya merged 3 commits intodevelopmentfrom
feature/s40-restart_ui_on_upgrade

Conversation

@stenya
Copy link
Copy Markdown
Contributor

@stenya stenya commented Apr 10, 2026

Overview

This PR implements automatic UI process (Tauri) restart after successful system updates, improving user experience by ensuring the latest UI version is running without requiring manual restart.

Changes

Main Features

Bug Fixes

  • Additionally, fixed variable shadowing in copyAndCheckSHA256Sum function in update validation logic

Files Changed

  • desktop/tauri/src-tauri/src/main.rs - Integration of relaunch trigger on update completion
  • desktop/tauri/src-tauri/src/relaunch.rs - Core relaunch logic with hardened path resolution
  • desktop/tauri/src-tauri/src/portmaster/mod.rs - Update event handling
  • desktop/tauri/src-tauri/src/traymenu.rs - Tray menu integration
  • service/core/api.go - Backend API changes for update completion signaling
  • service/updates/module.go - Update module integration
  • service/updates/index.go - SHA256 validation fix

Breaking Changes

None

Commits Included

  1. 14a8df4 - Restart UI process (Tauri) after automatic update
  2. fab4d3e - fix: fix variable shadowing in copyAndCheckSHA256Sum
  3. ce67af8 - fix(tauri): harden UI process restart path resolution and avoid exit on relaunch failure

Summary by CodeRabbit

  • New Features
    • The UI now automatically relaunches when a service restart occurs, particularly during upgrades, to ensure the application remains synchronized with backend changes.

stenya and others added 3 commits April 10, 2026 13:12
Separate variable declaration from assignment in the SHA256 validation
logic to prevent variable shadowing and ensure proper error handling
scope.
…on relaunch failure

This fixes Linux-related issue when UI process do not start automatically after upgrade.

- replace direct current_exe relaunch usage with verified launch program resolution
- consider both current_exe and argv0, but only accept verified launchable file paths
- fail relaunch with explicit error when no safe executable path is available
- in reconnect flow, exit current UI only if relaunch spawn succeeds
- if relaunch request fails, keep current UI process running and continue normal startup

https://github.com/safing/portmaster-shadow/issues/40
@stenya stenya self-assigned this Apr 10, 2026
@CLAassistant
Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
1 out of 2 committers have signed the CLA.

✅ stenya
❌ Alexandr Stelnykovych


Alexandr Stelnykovych seems not to be a GitHub user. You need a GitHub account to be able to sign the CLA. If you have already a GitHub account, please add the email address used for this commit to your account.
You have signed the CLA already but the status is still pending? Let us recheck it.

@stenya stenya added this to the v2.1.9 milestone Apr 10, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 10, 2026

📝 Walkthrough

Walkthrough

This pull request implements a UI relaunch mechanism triggered during service upgrades. When an upgrade requires a restart, the service sends a restart-ui-process event. The UI receives this event, marks a restart request in the portmaster interface, and upon reconnection spawns a helper process to perform the actual UI relaunch before exiting.

Changes

Cohort / File(s) Summary
Relaunch Infrastructure
desktop/tauri/src-tauri/src/relaunch.rs
New module implementing UI process relaunch via spawning. Includes executable resolution with platform-specific validation (Unix permissions), argument filtering (removes --background/-b), and retry logic with configurable attempts and delays.
Portmaster Interface & Main Integration
desktop/tauri/src-tauri/src/portmaster/mod.rs, desktop/tauri/src-tauri/src/main.rs
Added pending_restart atomic flag to PortmasterInterface with getter/setter methods. Integrated relaunch helper invocation at startup and WebSocket reconnection to spawn helper process on restart request.
Event Subscription Handler
desktop/tauri/src-tauri/src/traymenu.rs
Added async subscription to runtime:modules/core/event/restart-ui-process event with handler that calls mark_restart_ui_proc_requested() on positive responses.
Service Upgrade Trigger
service/core/api.go
Modified restart handler to accept request parameter and conditionally emit core/restart-ui-process event when source=upgrade query parameter is present.
Updates Service Adjustments
service/updates/index.go, service/updates/module.go
Fixed SHA256 variable declaration scope in copyAndCheckSHA256Sum. Updated restart webhook URL to include source=upgrade query parameter for upgrade-triggered restarts.

Sequence Diagram

sequenceDiagram
    participant UpdateService as Upgrade Service
    participant CoreAPI as Core API
    participant EventSys as Event System
    participant TrayUI as UI (Tray Handler)
    participant PortmasterIF as PortmasterInterface
    participant WSHandler as WebSocket Handler
    participant Relaunch as Relaunch Process

    UpdateService->>CoreAPI: POST /core/restart?source=upgrade
    CoreAPI->>EventSys: pushModuleEvent("core", "restart-ui-process")
    EventSys->>TrayUI: emit restart-ui-process event
    TrayUI->>PortmasterIF: mark_restart_ui_proc_requested()
    PortmasterIF->>PortmasterIF: pending_restart = true
    
    Note over TrayUI,PortmasterIF: UI continues, eventually reconnects
    
    WSHandler->>PortmasterIF: consume_restart_ui_proc_requested()
    PortmasterIF-->>WSHandler: true (clears flag)
    WSHandler->>Relaunch: request_ui_relaunch()
    Relaunch->>Relaunch: Spawn helper with PORTMASTER_UI_RELAUNCH_HELPER=1
    Relaunch-->>WSHandler: Ok
    WSHandler->>WSHandler: exit(0)
    Relaunch->>Relaunch: Retry helper with current exe + filtered args
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 26.32% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main objective: implementing automatic restart of the UI process after system updates, which is reflected across all changes in the Tauri desktop code and backend update handling.

✏️ 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 feature/s40-restart_ui_on_upgrade

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.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
service/updates/index.go (1)

385-387: ⚠️ Potential issue | 🟡 Minor

Incorrect error wrapping: err is nil here.

At line 386, err is guaranteed to be nil because the check at line 382 would have returned early otherwise. Wrapping a nil error with %w is semantically incorrect—the size validation failure is unrelated to the hex decoding result.

Note: This same bug exists at lines 332 and 362 in CheckSHA256SumFile and CheckSHA256Sum.

🐛 Proposed fix
 		if len(expectedDigest) != sha256.Size {
-			return fmt.Errorf("invalid size for expected hash %s: %w", sha256sum, err)
+			return fmt.Errorf("invalid size for expected hash %s (got %d bytes, expected %d)", sha256sum, len(expectedDigest), sha256.Size)
 		}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@service/updates/index.go` around lines 385 - 387, The error formatting wraps
a nil err (using %w) when validating expectedDigest length in functions
CheckSHA256SumFile and CheckSHA256Sum (code around the if checking
len(expectedDigest) != sha256.Size), which is incorrect; change the fmt.Errorf
call to not wrap err and instead return a clear error that states the expected
and actual sizes (e.g., use fmt.Errorf("invalid size for expected hash %s:
expected %d, got %d", sha256sum, sha256.Size, len(expectedDigest))) so the
message is accurate and does not reference a nil error.
service/updates/module.go (1)

436-438: ⚠️ Potential issue | 🟠 Major

Auto-restart still bypasses the new UI relaunch flow.

This branch calls u.instance.Restart() directly, so it never reaches the source=upgrade handling in service/core/api.go that emits restart-ui-process. Manual “Restart Now” works, but automatic/no-notify upgrades will still restart the core without telling the Tauri UI to relaunch. Route this branch through the same upgrade-aware restart helper, or emit the UI-restart event before calling Restart().

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@service/updates/module.go` around lines 436 - 438, This branch directly calls
u.instance.Restart(), bypassing the upgrade-aware flow that emits the
restart-ui-process event in service/core/api.go; change this to use the same
upgrade-aware restart helper (the function used by the manual “Restart Now”
path) or explicitly emit the restart-ui-process event before calling
u.instance.Restart() so the Tauri UI receives the source=upgrade relaunch
signal; locate references to u.instance.Restart() in module.go and replace the
direct call with the helper invocation (or add the event emission) so the
automatic/no-notify upgrade path follows the same upgrade-aware behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@desktop/tauri/src-tauri/src/main.rs`:
- Around line 67-78: The restart-request flag is being cleared by
consume_restart_ui_proc_requested() before calling
relaunch::request_ui_relaunch(), so on Err the request is lost; fix by either
re-marking the flag in the Err branch via the portmaster API (i.e. call the
inverse setter on self.handle.portmaster() to re-set the restart-ui-process
request) or change the flow to check the flag without consuming it and only call
consume_restart_ui_proc_requested() after relaunch::request_ui_relaunch()
returns Ok; keep existing logging and exit behavior (self.handle.exit(0)) on
success.

---

Outside diff comments:
In `@service/updates/index.go`:
- Around line 385-387: The error formatting wraps a nil err (using %w) when
validating expectedDigest length in functions CheckSHA256SumFile and
CheckSHA256Sum (code around the if checking len(expectedDigest) != sha256.Size),
which is incorrect; change the fmt.Errorf call to not wrap err and instead
return a clear error that states the expected and actual sizes (e.g., use
fmt.Errorf("invalid size for expected hash %s: expected %d, got %d", sha256sum,
sha256.Size, len(expectedDigest))) so the message is accurate and does not
reference a nil error.

In `@service/updates/module.go`:
- Around line 436-438: This branch directly calls u.instance.Restart(),
bypassing the upgrade-aware flow that emits the restart-ui-process event in
service/core/api.go; change this to use the same upgrade-aware restart helper
(the function used by the manual “Restart Now” path) or explicitly emit the
restart-ui-process event before calling u.instance.Restart() so the Tauri UI
receives the source=upgrade relaunch signal; locate references to
u.instance.Restart() in module.go and replace the direct call with the helper
invocation (or add the event emission) so the automatic/no-notify upgrade path
follows the same upgrade-aware behavior.
🪄 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: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 42dd42ec-2b5a-4b72-a09b-eddd31092038

📥 Commits

Reviewing files that changed from the base of the PR and between 67802f5 and ce67af8.

📒 Files selected for processing (7)
  • desktop/tauri/src-tauri/src/main.rs
  • desktop/tauri/src-tauri/src/portmaster/mod.rs
  • desktop/tauri/src-tauri/src/relaunch.rs
  • desktop/tauri/src-tauri/src/traymenu.rs
  • service/core/api.go
  • service/updates/index.go
  • service/updates/module.go

Comment thread desktop/tauri/src-tauri/src/main.rs
@stenya stenya merged commit e54f2a2 into development Apr 10, 2026
3 of 8 checks passed
@stenya stenya deleted the feature/s40-restart_ui_on_upgrade branch April 10, 2026 13:54
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.

2 participants