Skip to content

fix(update): make remote-update flow usable for portable builds#22

Merged
OpenSource-For-Freedom merged 2 commits into
mainfrom
patch
May 26, 2026
Merged

fix(update): make remote-update flow usable for portable builds#22
OpenSource-For-Freedom merged 2 commits into
mainfrom
patch

Conversation

@OpenSource-For-Freedom
Copy link
Copy Markdown
Owner

No description provided.

Velopack-based auto-update only works for users who installed via
WRAITH-Setup.exe; the README only documented the portable zip path,
so most users hit a silent-fail flow where CheckForUpdatesAsync
threw, the exception was swallowed, and nothing surfaced in the UI.

- UpdateService: log IsInstalled, skip DownloadUpdatesAsync on
  portable builds (saves ~50 MB), still raise UpdateDownloaded so
  the dialog can offer a manual path.
- UpdateAvailableWindow: when canApply is false, repurpose the
  primary button as "Open Release Page" instead of leaving it
  disabled with a tooltip nobody reads.
- deploy.yml: pass --releaseNotes (extracted from CHANGELOG.md's
  top section) to vpk pack so TargetFullRelease.NotesMarkdown is
  populated and the dialog shows real notes.
- README: split Installation into Installer vs Portable, call out
  which path enables auto-update, fix YOUR_USERNAME placeholder.
Copilot AI review requested due to automatic review settings May 26, 2026 05:05
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adjusts WRAITH’s update UX and update-check behavior so “portable” (ZIP/START.bat) builds can still guide users to update manually, while avoiding wasted bandwidth/storage by skipping Velopack payload downloads when updates can’t be applied in-place.

Changes:

  • Repurposes the update dialog’s primary action for portable builds to open the GitHub releases page.
  • Skips downloading Velopack update payloads when IsInstalled=false (portable builds).
  • Updates documentation/workflow to better surface release notes and clarify install paths.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 4 comments.

File Description
WRAITH/UpdateAvailableWindow.xaml.cs Changes update dialog behavior for non-installable builds to open the release page instead of applying.
WRAITH/Services/UpdateService.cs Avoids downloading update payloads when running as a portable build; adds a public releases URL.
README.md Documents installer vs portable installation paths and auto-update availability.
.github/workflows/deploy.yml Adds a step to generate release-notes.md for Velopack packaging.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +39 to +44
// Portable (zip + START.bat) build — Velopack can't apply in-place.
// Repurpose the primary action to send the user to the download page.
UpdateBtn.Content = "🌐 Open Release Page";
UpdateBtn.ToolTip = "This is a portable build — download the new release manually.";
SubtitleBlock.Text = "A new version of WRAITH is available. This is a portable build, " +
"so updates can't be applied in-place — open the release page to download.";
UseShellExecute = true,
});
}
catch { /* best-effort — never block close */ }
Comment on lines +19 to +20
/// <summary>Public link to the latest release — surfaced when auto-apply is unavailable.</summary>
public const string ReleasesUrl = RepoUrl + "/releases/latest";
Comment on lines +403 to +412
$notes = ""
if (Test-Path CHANGELOG.md) {
$lines = Get-Content CHANGELOG.md
$start = ($lines | Select-String -Pattern '^##\s' | Select-Object -First 1).LineNumber
if ($start) {
$tail = $lines[$start..($lines.Length - 1)]
$stop = ($tail | Select-String -Pattern '^##\s' | Select-Object -First 1).LineNumber
$notes = if ($stop) { $tail[0..($stop - 2)] -join "`n" } else { $tail -join "`n" }
}
}
Five bugs in the quarantine + delete pipeline:

- Restore only handled the first selected row even though the grid
  is multi-select. Now iterates the selection like Delete does, with
  a per-item try/catch and an accurate counter.
- Delete's try/catch wrapped the whole loop, so one locked vault
  file (AV holding a handle, common case) aborted the rest of the
  batch and the user got "Delete failed" instead of partial counts.
  Moved the catch inside the loop and surface the last error.
- DeleteFromVault returned true for no-op deletes on already
  restored/deleted records. UI then reported "Deleted N item(s)"
  for work that didn't happen. Now returns false for no-ops.
- Restored records had no state in the model — QuarantinedPath was
  cleared, Deleted stayed false, the row sat in the grid with empty
  fields forever. Added Restored + PendingRebootDelete + a State
  computed property; XAML now shows a "State" column instead of
  the boolean "Deleted".
- SaveIndex used File.WriteAllText with no atomicity — a crash
  mid-write truncated the index and made the whole vault appear
  empty. Now writes to .tmp and File.Replace into place.

Also adds a locked-source fallback in QuarantineFile: when File.Move
throws IOException because the original is mapped into a running
process (the exact case that matters most for malware), the bytes
are copied into the vault and the source is scheduled for deletion
at next boot via MoveFileEx(MOVEFILE_DELAY_UNTIL_REBOOT). The record
is tagged PendingRebootDelete so the UI can show that.
@OpenSource-For-Freedom OpenSource-For-Freedom merged commit 7c2239a into main May 26, 2026
7 checks passed
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