From b35eb2bfbaf7e30e17a7a5458244a36ff09aa239 Mon Sep 17 00:00:00 2001 From: "voidzero-bot[bot]" <348775505+voidzero-bot[bot]@users.noreply.github.com> Date: Fri, 30 Oct 2026 13:18:54 +0000 Subject: [PATCH] fix(js-runtime): report missing platform archive instead of hash-not-found --- crates/vp_js_runtime/src/error.rs | 12 +++++ crates/vp_js_runtime/src/runtime.rs | 78 ++++++++++++++++++++++++++++- 2 files changed, 88 insertions(+), 2 deletions(-) diff --git a/crates/vp_js_runtime/src/error.rs b/crates/vp_js_runtime/src/error.rs index cf56762115..ca7f28dfbe 100644 --- a/crates/vp_js_runtime/src/error.rs +++ b/crates/vp_js_runtime/src/error.rs @@ -13,6 +13,18 @@ pub enum Error { #[error("Platform {platform} is not supported for {runtime}")] UnsupportedPlatform { platform: Str, runtime: Str }, + /// The runtime version exists, but no archive is available for this platform. + #[error( + "{runtime} v{version} does not provide a {platform} archive ({filename}); \ + this version may not be available for your platform" + )] + MissingPlatformArchive { + runtime: Str, + version: Str, + platform: Str, + filename: Str, + }, + /// Download failed after retries #[error("Failed to download from {url}: {reason}")] DownloadFailed { url: Str, reason: Str }, diff --git a/crates/vp_js_runtime/src/runtime.rs b/crates/vp_js_runtime/src/runtime.rs index e9618cad49..c2298d08ee 100644 --- a/crates/vp_js_runtime/src/runtime.rs +++ b/crates/vp_js_runtime/src/runtime.rs @@ -232,7 +232,18 @@ pub async fn download_runtime_with_provider( let shasums_content = resolve_shasums_content(url, signature.as_ref(), &download_info.archive_filename) .await?; - Some(provider.parse_shasums(&shasums_content, &download_info.archive_filename)?) + match provider.parse_shasums(&shasums_content, &download_info.archive_filename) { + Ok(hash) => Some(hash), + Err(Error::HashNotFound { filename }) => { + return Err(Error::MissingPlatformArchive { + runtime: provider.name().into(), + version: version.into(), + platform: provider.platform_string(platform), + filename, + }); + } + Err(error) => return Err(error), + } } HashVerification::None => None, }; @@ -680,6 +691,7 @@ mod tests { use vp_shared::env_vars; use super::*; + use crate::{NodeProvider, Platform}; /// A fixed version index, so resolved versions don't move with new Node.js releases. const NODE_INDEX: &str = r#"[ @@ -1215,7 +1227,8 @@ mod tests { ) .await .unwrap(); - assert!(matches!(result, Err(Error::HashNotFound { .. }))); + // An empty SHASUMS file means the expected platform archive is not listed. + assert!(matches!(result, Err(Error::MissingPlatformArchive { .. }))); } checksums.assert_hits_async(2).await; }, @@ -1580,6 +1593,67 @@ mod tests { .await; } + /// A release may exist for other platforms but omit the tarball for the host + /// platform. In that case the SHASUMS file downloads successfully but does + /// not contain the expected archive filename. The error must describe the + /// missing platform archive instead of the generic "Hash not found" message. + #[tokio::test] + async fn test_download_runtime_missing_platform_archive() { + use httpmock::prelude::*; + + let vp_home = TempDir::new().unwrap(); + let server = MockServer::start_async().await; + let provider = NodeProvider::new(); + let platform = Platform::current(); + let version = "27.0.0-alpha.0.0.0"; + let info = provider.get_download_info(version, platform); + + vp_shared::EnvConfig::with_vars_async( + [ + (env_vars::VP_HOME, vp_home.path().as_os_str()), + (env_vars::VP_NODE_DIST_MIRROR, std::ffi::OsStr::new(&server.base_url())), + (env_vars::VP_NODE_SKIP_SIGNATURE_VERIFY, std::ffi::OsStr::new("1")), + ], + |_| async { + server + .mock_async(|when, then| { + when.method(GET).path("/index.json"); + then.status(200).body(format!( + "[{{\"version\":\"v{version}\",\"lts\":false}}]" + )); + }) + .await; + server + .mock_async(|when, then| { + when.method(GET).path(format!("/v{version}/SHASUMS256.txt")); + // Only list a different platform so the host platform tarball is missing. + then.status(200).body( + "deadbeef node-v27.0.0-alpha.0.0.0-darwin-arm64.tar.gz\n", + ); + }) + .await; + + let error = download_runtime(JsRuntimeType::Node, version).await.unwrap_err(); + assert!( + matches!( + error, + Error::MissingPlatformArchive { + ref runtime, + version: ref v, + platform: ref p, + ref filename, + } if AsRef::::as_ref(runtime) == "node" + && AsRef::::as_ref(v) == version + && filename == &info.archive_filename + && p == &provider.platform_string(platform) + ), + "expected MissingPlatformArchive error, got {error}" + ); + }, + ) + .await; + } + // ========================================== // resolve_node_version tests // ==========================================