From 4ddec743416b4470f8404cd33eee47259e018624 Mon Sep 17 00:00:00 2001 From: wuyangfan Date: Thu, 18 Jun 2026 10:59:47 +0800 Subject: [PATCH 1/4] fix(setup): reject cli packages without provenance --- crates/vite_setup/src/registry.rs | 66 +++++++++++++++++++++++++++++++ packages/cli/install.ps1 | 31 +++++++++++++++ packages/cli/install.sh | 25 ++++++++++++ 3 files changed, 122 insertions(+) diff --git a/crates/vite_setup/src/registry.rs b/crates/vite_setup/src/registry.rs index 6540690ef9..a659202b89 100644 --- a/crates/vite_setup/src/registry.rs +++ b/crates/vite_setup/src/registry.rs @@ -20,6 +20,24 @@ pub struct PackageVersionMetadata { pub struct DistInfo { pub tarball: String, pub integrity: String, + #[serde(default)] + pub attestations: Option, +} + +/// npm attestation metadata from `dist.attestations`. +#[derive(Debug, Deserialize)] +pub struct DistAttestations { + #[serde(default)] + pub provenance: Option, +} + +impl DistInfo { + fn has_provenance(&self) -> bool { + self.attestations + .as_ref() + .and_then(|attestations| attestations.provenance.as_ref()) + .is_some() + } } /// Resolved version info with URLs and integrity for the platform package. @@ -86,6 +104,17 @@ pub async fn resolve_platform_package( ) })?; + if !cli_meta.dist.has_provenance() { + return Err(Error::Setup( + format!( + "Refusing to install {cli_package_name}@{} because its npm package metadata \ + does not include provenance attestation.", + cli_meta.version + ) + .into(), + )); + } + Ok(ResolvedVersion { version: version.to_owned(), platform_tarball_url: cli_meta.dist.tarball, @@ -118,6 +147,43 @@ mod tests { assert_eq!(name, "@voidzero-dev/vite-plus-cli-darwin-arm64"); } + #[test] + fn test_dist_info_detects_provenance() { + let meta: PackageVersionMetadata = serde_json::from_value(serde_json::json!({ + "version": "0.2.0", + "dist": { + "tarball": "https://registry.npmjs.org/package.tgz", + "integrity": "sha512-test", + "attestations": { + "url": "https://registry.npmjs.org/-/npm/v1/attestations/pkg@0.2.0", + "provenance": { + "predicateType": "https://slsa.dev/provenance/v1" + } + } + } + })) + .unwrap(); + + assert!(meta.dist.has_provenance()); + } + + #[test] + fn test_dist_info_rejects_missing_provenance() { + let meta: PackageVersionMetadata = serde_json::from_value(serde_json::json!({ + "version": "0.2.0", + "dist": { + "tarball": "https://registry.npmjs.org/package.tgz", + "integrity": "sha512-test", + "attestations": { + "url": "https://registry.npmjs.org/-/npm/v1/attestations/pkg@0.2.0" + } + } + })) + .unwrap(); + + assert!(!meta.dist.has_provenance()); + } + #[test] fn test_all_platform_suffixes_match_published_cli_packages() { // These are the actual published CLI package suffixes diff --git a/packages/cli/install.ps1 b/packages/cli/install.ps1 index 6adc7ed2ec..074eecb2d4 100644 --- a/packages/cli/install.ps1 +++ b/packages/cli/install.ps1 @@ -198,6 +198,36 @@ function Get-VersionFromMetadata { return $metadata.version } +function Assert-PlatformPackageProvenance { + param( + [string]$PackageName, + [string]$Version + ) + + $encodedPackageName = [System.Uri]::EscapeDataString($PackageName) + $metadataUrl = "$NpmRegistry/$encodedPackageName/$Version" + try { + $metadata = Invoke-RestMethod -Uri $metadataUrl -Headers @{ Accept = "application/json" } + } catch { + $errorMsg = $_.ErrorDetails.Message + if ($errorMsg) { + try { + $errorJson = $errorMsg | ConvertFrom-Json + if ($errorJson.error) { + Write-Error-Exit "Failed to fetch CLI package metadata '${PackageName}@${Version}': $($errorJson.error)`n URL: $metadataUrl" + } + } catch { + # JSON parsing failed, fall through to generic error + } + } + Write-Error-Exit "Failed to fetch CLI package metadata from: $metadataUrl`nError: $_" + } + + if (-not $metadata.dist -or -not $metadata.dist.attestations -or -not $metadata.dist.attestations.provenance) { + Write-Error-Exit "Refusing to install ${PackageName}@${Version} because its npm package metadata does not include provenance attestation." + } +} + function Get-PlatformSuffix { param([string]$Platform) # Windows needs -msvc suffix, other platforms map directly @@ -516,6 +546,7 @@ function Main { $platformUrl = "$PkgPrNewBase/@voidzero-dev/vite-plus-cli-$platformSuffix@$PrVersion" } else { $packageName = "@voidzero-dev/vite-plus-cli-$platformSuffix" + Assert-PlatformPackageProvenance -PackageName $packageName -Version $ViteVersion $platformUrl = "$NpmRegistry/$packageName/-/vite-plus-cli-$platformSuffix-$ViteVersion.tgz" } diff --git a/packages/cli/install.sh b/packages/cli/install.sh index 57756ff7b3..662fafe5a2 100644 --- a/packages/cli/install.sh +++ b/packages/cli/install.sh @@ -359,6 +359,30 @@ get_version_from_metadata() { fi } +verify_platform_package_provenance() { + local package_name="$1" + local package_version="$2" + local encoded_package_name="${package_name/\//%2F}" + local metadata_url="${NPM_REGISTRY}/${encoded_package_name}/${package_version}" + local metadata + + metadata=$(curl_with_error_handling -s "$metadata_url") + if [ -z "$metadata" ]; then + error "Failed to fetch CLI package metadata from: $metadata_url" + fi + + if echo "$metadata" | grep -q '"error"'; then + local error_msg + error_msg=$(echo "$metadata" | grep -o '"error" *: *"[^"]*"' | cut -d'"' -f4) + error "Failed to fetch CLI package metadata '${package_name}@${package_version}': ${error_msg:-unknown error}\n URL: $metadata_url" + fi + + if ! echo "$metadata" | grep -Eq '"attestations" *: *\{' || + ! echo "$metadata" | grep -Eq '"provenance" *: *\{'; then + error "Refusing to install ${package_name}@${package_version} because its npm package metadata does not include provenance attestation." + fi +} + # Get platform suffix for CLI package download # Sets PLATFORM_SUFFIX global variable # Platform format from detect_platform(): darwin-arm64, darwin-x64, linux-x64-gnu, linux-arm64-gnu, win32-x64, etc. @@ -921,6 +945,7 @@ main() { platform_url="${PKG_PR_NEW_BASE}/@voidzero-dev/vite-plus-cli-${PLATFORM_SUFFIX}@${PR_VERSION}" else local package_name="@voidzero-dev/vite-plus-cli-${PLATFORM_SUFFIX}" + verify_platform_package_provenance "$package_name" "$VP_VERSION" platform_url="${NPM_REGISTRY}/${package_name}/-/vite-plus-cli-${PLATFORM_SUFFIX}-${VP_VERSION}.tgz" fi From 60980b28b1c4250cf8532141ec65a74cf35d7d1b Mon Sep 17 00:00:00 2001 From: wuyangfan Date: Thu, 18 Jun 2026 17:06:45 +0800 Subject: [PATCH 2/4] fix(cli): scope provenance metadata checks --- packages/cli/install.ps1 | 12 ++++++++++++ packages/cli/install.sh | 5 +++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/packages/cli/install.ps1 b/packages/cli/install.ps1 index 074eecb2d4..841b861f4a 100644 --- a/packages/cli/install.ps1 +++ b/packages/cli/install.ps1 @@ -223,6 +223,18 @@ function Assert-PlatformPackageProvenance { Write-Error-Exit "Failed to fetch CLI package metadata from: $metadataUrl`nError: $_" } + if ($metadata -is [string]) { + try { + $metadata = $metadata | ConvertFrom-Json + } catch { + Write-Error-Exit "Failed to parse CLI package metadata '${PackageName}@${Version}'`n URL: $metadataUrl" + } + } + + if ($metadata.error) { + Write-Error-Exit "Failed to fetch CLI package metadata '${PackageName}@${Version}': $($metadata.error)`n URL: $metadataUrl" + } + if (-not $metadata.dist -or -not $metadata.dist.attestations -or -not $metadata.dist.attestations.provenance) { Write-Error-Exit "Refusing to install ${PackageName}@${Version} because its npm package metadata does not include provenance attestation." } diff --git a/packages/cli/install.sh b/packages/cli/install.sh index 662fafe5a2..c774653281 100644 --- a/packages/cli/install.sh +++ b/packages/cli/install.sh @@ -377,8 +377,9 @@ verify_platform_package_provenance() { error "Failed to fetch CLI package metadata '${package_name}@${package_version}': ${error_msg:-unknown error}\n URL: $metadata_url" fi - if ! echo "$metadata" | grep -Eq '"attestations" *: *\{' || - ! echo "$metadata" | grep -Eq '"provenance" *: *\{'; then + local provenance_pattern + provenance_pattern='"dist"[[:space:]]*:[[:space:]]*\{[^}]*"attestations"[[:space:]]*:[[:space:]]*\{[^}]*"provenance"[[:space:]]*:[[:space:]]*\{' + if ! printf '%s' "$metadata" | tr -d '\n' | grep -Eq "$provenance_pattern"; then error "Refusing to install ${package_name}@${package_version} because its npm package metadata does not include provenance attestation." fi } From f1f2b62a369e297b07195a58ec459d57b0a56f6a Mon Sep 17 00:00:00 2001 From: wuyangfan Date: Thu, 18 Jun 2026 17:13:15 +0800 Subject: [PATCH 3/4] fix(installer): parse dist provenance in shell --- packages/cli/install.sh | 38 +++++++++++++++++++++++++++++++++++--- 1 file changed, 35 insertions(+), 3 deletions(-) diff --git a/packages/cli/install.sh b/packages/cli/install.sh index c774653281..53adab5962 100644 --- a/packages/cli/install.sh +++ b/packages/cli/install.sh @@ -377,9 +377,41 @@ verify_platform_package_provenance() { error "Failed to fetch CLI package metadata '${package_name}@${package_version}': ${error_msg:-unknown error}\n URL: $metadata_url" fi - local provenance_pattern - provenance_pattern='"dist"[[:space:]]*:[[:space:]]*\{[^}]*"attestations"[[:space:]]*:[[:space:]]*\{[^}]*"provenance"[[:space:]]*:[[:space:]]*\{' - if ! printf '%s' "$metadata" | tr -d '\n' | grep -Eq "$provenance_pattern"; then + if ! printf '%s' "$metadata" | awk ' + BEGIN { depth = 0; in_str = 0; esc = 0; in_dist = 0; in_attestations = 0; found = 0 } + { + for (i = 1; i <= length($0); i++) { + c = substr($0, i, 1) + if (in_str) { + if (esc) { esc = 0 } + else if (c == "\\") { esc = 1 } + else if (c == "\"") { in_str = 0; last_string = token } + else { token = token c } + continue + } + if (c == "\"") { in_str = 1; token = ""; continue } + if (c == ":" && last_string != "") { + if (!in_dist && last_string == "dist") { expect_object = "dist" } + else if (in_dist && last_string == "attestations") { expect_object = "attestations" } + else if (in_attestations && last_string == "provenance") { found = 1 } + last_string = "" + continue + } + if (c == "{") { + depth++ + if (expect_object == "dist") { in_dist = 1; dist_depth = depth; expect_object = "" } + else if (expect_object == "attestations") { in_attestations = 1; attestations_depth = depth; expect_object = "" } + continue + } + if (c == "}") { + if (in_attestations && depth == attestations_depth) { in_attestations = 0 } + if (in_dist && depth == dist_depth) { in_dist = 0 } + depth-- + } + } + } + END { exit found ? 0 : 1 } + '; then error "Refusing to install ${package_name}@${package_version} because its npm package metadata does not include provenance attestation." fi } From f6601a3b53d974eb750548ed09cc4c6b47464957 Mon Sep 17 00:00:00 2001 From: wuyangfan Date: Thu, 18 Jun 2026 18:10:21 +0800 Subject: [PATCH 4/4] fix(cli): include napi build tool in package deps --- packages/cli/package.json | 2 +- pnpm-lock.yaml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index 81ecda4596..cc3caa2163 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -361,6 +361,7 @@ "test": "vitest run" }, "dependencies": { + "@napi-rs/cli": "catalog:", "@oxc-project/types": "catalog:", "@oxlint/plugins": "catalog:", "@vitest/browser": "catalog:", @@ -379,7 +380,6 @@ "vitest": "catalog:" }, "devDependencies": { - "@napi-rs/cli": "catalog:", "@nkzw/safe-word-list": "catalog:", "@oxc-node/core": "catalog:", "@types/cross-spawn": "catalog:", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9958a548b6..abaedf3ce6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -359,6 +359,9 @@ importers: packages/cli: dependencies: + '@napi-rs/cli': + specifier: 'catalog:' + version: 3.7.2(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@24.12.4)(node-addon-api@7.1.1) '@oxc-project/types': specifier: 'catalog:' version: 0.136.0 @@ -408,9 +411,6 @@ importers: specifier: 'catalog:' version: 4.1.9(@edge-runtime/vm@5.0.0)(@opentelemetry/api@1.9.0)(@types/node@24.12.4)(@vitest/browser-playwright@4.1.9)(@vitest/browser-preview@4.1.9)(@vitest/browser-webdriverio@4.1.9)(happy-dom@20.0.10)(jsdom@27.2.0)(vite@packages+core) devDependencies: - '@napi-rs/cli': - specifier: 'catalog:' - version: 3.7.2(@emnapi/core@1.11.1)(@emnapi/runtime@1.11.1)(@types/node@24.12.4)(node-addon-api@7.1.1) '@nkzw/safe-word-list': specifier: 'catalog:' version: 3.1.0