generated from eblume/project-template
fix: self-update poll uses ureq (reqwest has no TLS backend)
All checks were successful
Build / validate (push) Successful in 4m31s
All checks were successful
Build / validate (push) Successful in 4m31s
hephd's reqwest client is built default-features=false with no TLS
feature, so the self-update release poll's HTTPS GET always failed
('release check failed: requesting forge releases/latest') — the bug
never surfaced before because nothing in production used reqwest over
HTTPS (hub sync is plain http://). Switch the poll to ureq, which is
already a dependency and ships a rustls/ring TLS stack needing no system
libs (notably no cmake/aws-lc-sys, which would break the rust:bookworm CI
image). Verified end-to-end: a 0.0.0 build now detects v1.1.0, installs,
and restarts.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
854d25c68b
commit
fac39386d0
3 changed files with 26 additions and 19 deletions
|
|
@ -70,19 +70,17 @@ pub fn parse_latest_tag(body: &str) -> Result<String> {
|
|||
Ok(rel.tag_name)
|
||||
}
|
||||
|
||||
/// Fetch the latest release tag from the forge over HTTP (reusing the daemon's
|
||||
/// shared `reqwest::Client`). Network/HTTP/JSON failures surface as `Err` for
|
||||
/// the caller to log-and-continue.
|
||||
pub async fn fetch_latest_tag(http: &reqwest::Client, url: &str) -> Result<String> {
|
||||
let body = http
|
||||
.get(url)
|
||||
.send()
|
||||
.await
|
||||
/// Fetch the latest release tag from the forge over HTTPS, blocking. Uses
|
||||
/// `ureq` (already a dependency, with a rustls/ring TLS backend that needs no
|
||||
/// system libs) rather than the daemon's `reqwest` client, which is built
|
||||
/// without TLS — the forge poll is the only production HTTPS-over-HTTP-client
|
||||
/// path (hub sync is plain HTTP). Network/HTTP/JSON failures surface as `Err`.
|
||||
pub fn fetch_latest_tag(url: &str) -> Result<String> {
|
||||
let body = ureq::get(url)
|
||||
.call()
|
||||
.context("requesting forge releases/latest")?
|
||||
.error_for_status()
|
||||
.context("forge releases/latest returned an error status")?
|
||||
.text()
|
||||
.await
|
||||
.body_mut()
|
||||
.read_to_string()
|
||||
.context("reading forge releases/latest body")?;
|
||||
parse_latest_tag(&body)
|
||||
}
|
||||
|
|
@ -93,25 +91,33 @@ pub trait ReleaseSource: Send + Sync + 'static {
|
|||
fn latest_tag(&self) -> impl std::future::Future<Output = Result<String>> + Send;
|
||||
}
|
||||
|
||||
/// The production source: the forge's `releases/latest` over HTTP.
|
||||
/// The production source: the forge's `releases/latest` over HTTPS (via `ureq`).
|
||||
pub struct ForgeReleaseSource {
|
||||
http: reqwest::Client,
|
||||
url: String,
|
||||
}
|
||||
|
||||
impl ForgeReleaseSource {
|
||||
/// Source backed by the daemon's shared client, hitting [`RELEASES_LATEST_URL`].
|
||||
pub fn new(http: reqwest::Client) -> Self {
|
||||
/// Source hitting [`RELEASES_LATEST_URL`].
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
http,
|
||||
url: RELEASES_LATEST_URL.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ForgeReleaseSource {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl ReleaseSource for ForgeReleaseSource {
|
||||
async fn latest_tag(&self) -> Result<String> {
|
||||
fetch_latest_tag(&self.http, &self.url).await
|
||||
// `ureq` is blocking; keep it off the async runtime.
|
||||
let url = self.url.clone();
|
||||
tokio::task::spawn_blocking(move || fetch_latest_tag(&url))
|
||||
.await
|
||||
.context("release-fetch task panicked")?
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ impl Daemon {
|
|||
let Some(cfg) = self.ctx.self_update.clone() else {
|
||||
return;
|
||||
};
|
||||
let source = selfupdate::ForgeReleaseSource::new(self.ctx.http.clone());
|
||||
let source = selfupdate::ForgeReleaseSource::new();
|
||||
let installer: std::sync::Arc<dyn selfupdate::Installer> =
|
||||
std::sync::Arc::new(selfupdate::CargoInstaller);
|
||||
let restarter: std::sync::Arc<dyn selfupdate::Restarter> =
|
||||
|
|
|
|||
1
docs/changelog.d/+selfupdate-poll-tls.bugfix.md
Normal file
1
docs/changelog.d/+selfupdate-poll-tls.bugfix.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
Fix `hephd --self-update` never detecting releases: the release poll used the daemon's `reqwest` client, which is built without a TLS backend (`default-features = false`), so every HTTPS request to the forge failed (`release check failed: requesting forge releases/latest`). The poll now uses `ureq` — already a dependency, with a rustls/ring TLS stack that needs no system libraries (and no cmake/`aws-lc-sys`). Hub sync is unaffected (it is plain HTTP).
|
||||
Loading…
Add table
Add a link
Reference in a new issue