From a92eda210efce55e906a64e479a3a0a3f686ef5f Mon Sep 17 00:00:00 2001 From: Stephen Waits Date: Thu, 5 Nov 2026 10:17:50 -0700 Subject: [PATCH] fix(host): gate the update module's callers for non-unix builds The update module is `#[cfg(unix)]` (self-update replaces the running program's file, which Windows forbids), but three commands in `ledger-host` used `crate::update` unconditionally, so the server-only Windows build could not resolve the module. GitHub's portable-windows job failed on main 3aa1206a with nine E0433 errors in `ledger-host`. Gate `update_waiting`, `check_for_updates` and `apply_update` with `#[cfg(unix)]`, leaving their Unix bodies unchanged, and give non-unix builds a stub of each: nothing is waiting, and checking for or accepting an update is refused with "self-update isn't available on this platform" (the same `Err` path a refused update takes). `UPDATE_WAIT` is gated with the Unix `apply_update` it serves. --- crates/ledger-host/src/commands.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/crates/ledger-host/src/commands.rs b/crates/ledger-host/src/commands.rs index 72cb68f..6b75b6b 100644 --- a/crates/ledger-host/src/commands.rs +++ b/crates/ledger-host/src/commands.rs @@ -1042,6 +1042,7 @@ pub struct UpdateWaiting { } /// The update waiting for the owner's accept, if there is one. +#[cfg(unix)] pub fn update_waiting(common: &Common) -> Option { let found = ledger_store::root::Root::find(common.root.as_deref()).ok()?; let u = found.staged_update()?; @@ -1058,9 +1059,16 @@ pub fn update_waiting(common: &Common) -> Option { }) } +/// Nothing waits on a platform the self-update isn't built for. +#[cfg(not(unix))] +pub fn update_waiting(_common: &Common) -> Option { + None +} + /// "Check for updates": look at the feed now, whatever the daily look /// last did, and stage a newer release if there is one (it never swaps /// the program: accepting is [`apply_update`]). What came of it. +#[cfg(unix)] pub fn check_for_updates(common: &Common) -> Result { let found = ledger_store::root::Root::find(common.root.as_deref()).map_err(|e| e.to_string())?; @@ -1085,10 +1093,18 @@ pub fn check_for_updates(common: &Common) -> Result { } } +/// Checking for updates isn't built for this platform: say so, and +/// change nothing. +#[cfg(not(unix))] +pub fn check_for_updates(_common: &Common) -> Result { + Err(NO_SELF_UPDATE.into()) +} + /// Accept the staged update: the books' host installs it and restarts /// onto it once no call is running, the books staying open meanwhile /// (the lease socket's apply_update). With no host running, it is /// installed here, since no call can be cut off. What came of it. +#[cfg(unix)] pub fn apply_update(common: &Common) -> Result { let found = ledger_store::root::Root::find(common.root.as_deref()).map_err(|e| e.to_string())?; @@ -1111,10 +1127,23 @@ pub fn apply_update(common: &Common) -> Result { } } +/// Accepting an update isn't built for this platform: say so, and change +/// nothing. +#[cfg(not(unix))] +pub fn apply_update(_common: &Common) -> Result { + Err(NO_SELF_UPDATE.into()) +} + /// The longest the host may take to install an accepted update (a copy /// and a health check of the new program). +#[cfg(unix)] const UPDATE_WAIT: Duration = Duration::from_secs(90); +/// What the app says when the self-update is asked for on a platform it +/// isn't built for (Windows, today). +#[cfg(not(unix))] +const NO_SELF_UPDATE: &str = "self-update isn't available on this platform"; + /// The longest an agent's own command may take to add the books. const CONNECT_WAIT: Duration = Duration::from_secs(60);