Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions .github/scripts/test-install-bootstrap.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,24 @@ Assert ($LASTEXITCODE -eq 0) 'Could not create fixture'
$env:TEMP = "$testRoot/tmp"

function Invoke-RestMethod {
param($Uri)
param($Uri, $Headers)
$script:Requests.Add("GET $Uri")
return @{ version = '0.2.9' }
if ($Uri -eq 'https://custom.example/vite-plus/latest') {
return @{ version = '0.2.9' }
}
if ([System.Uri]::UnescapeDataString($Uri) -like 'https://custom.example/@voidzero-dev/vite-plus-cli-*/0.2.9') {
# Release payloads must pass the real provenance gate before handoff.
return @{
version = '0.2.9'
dist = @{
tarball = 'https://custom.example/platform.tgz'
attestations = @{
provenance = @{ predicateType = 'https://slsa.dev/provenance/v1' }
}
}
}
}
throw "Unexpected metadata request: $Uri"
}
function Invoke-WebRequest {
param($Uri, $Method, $OutFile, [switch]$UseBasicParsing, $ErrorAction)
Expand Down
3 changes: 3 additions & 0 deletions .github/scripts/test-install-bootstrap.sh
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ curl() {
*file://*) command curl "$@" ;;
*-fsSIL*) printf 'x-commit-key: voidzero-dev:vite-plus:%s\r\n' "$fixture_sha" ;;
*'https://custom.example/vite-plus/'*) printf '{"version":"0.2.9"}\n' ;;
*'https://custom.example/@voidzero-dev%2Fvite-plus-cli-'*)
# Release payloads must pass the real provenance gate before handoff.
printf '{"version":"0.2.9","dist":{"tarball":"https://custom.example/platform.tgz","attestations":{"provenance":{"predicateType":"https://slsa.dev/provenance/v1"}}}}\n' ;;
*) cp "$test_root/payload.tgz" "${@: -1}" ;;
esac
}
Expand Down
141 changes: 141 additions & 0 deletions .github/scripts/test-install-provenance.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# Run from the repository root with RUNNER_TEMP and TEST_VERSION set.
$ErrorActionPreference = "Stop"

function Invoke-ProvenanceCase {
param(
[string]$Mode,
[bool]$ExpectRejection,
[bool]$RawContentType = $false
)

$caseDir = Join-Path $env:RUNNER_TEMP "vite-plus-provenance-ps1-$Mode"
$homeDir = Join-Path $caseDir "home"
$vpHome = Join-Path $caseDir "vp-home"
$portFile = Join-Path $caseDir "port"
$logFile = Join-Path $caseDir "requests.jsonl"
$stdoutFile = Join-Path $caseDir "registry.stdout.log"
$stderrFile = Join-Path $caseDir "registry.stderr.log"
$installerStdoutFile = Join-Path $caseDir "installer.stdout.log"
$installerStderrFile = Join-Path $caseDir "installer.stderr.log"

Remove-Item -Path $caseDir -Recurse -Force -ErrorAction SilentlyContinue
New-Item -ItemType Directory -Path $homeDir, $vpHome -Force | Out-Null

$fixture = Join-Path (Get-Location) "packages/cli/tests/fixtures/provenance-registry.mjs"
$serverArgs = @(
$fixture,
"--port-file", $portFile,
"--log-file", $logFile,
"--mode", $Mode,
"--version", $env:TEST_VERSION
)
if ($RawContentType) {
$serverArgs += @("--raw-content-type", "true")
}

$server = Start-Process -FilePath "node" -ArgumentList $serverArgs -PassThru -RedirectStandardOutput $stdoutFile -RedirectStandardError $stderrFile

try {
for ($attempt = 0; $attempt -lt 100 -and -not (Test-Path $portFile); $attempt++) {
Start-Sleep -Milliseconds 100
}
if (-not (Test-Path $portFile)) {
throw "Mock registry did not start: $(Get-Content $stderrFile -Raw -ErrorAction SilentlyContinue)"
}

$registry = "http://127.0.0.1:$(Get-Content $portFile -Raw)"
$env:CI = "true"
$env:USERPROFILE = $homeDir
$env:VP_HOME = $vpHome
$env:VP_NODE_MANAGER = "no"
$env:VP_VERSION = $env:TEST_VERSION
$env:NPM_CONFIG_REGISTRY = $registry

# Windows PowerShell 5.1 turns redirected native stderr into a
# NativeCommandError. Capture each stream separately so the
# expected tarball failure cannot stop this parent test script.
$installerArgs = @(
"-NoProfile",
"-ExecutionPolicy", "Bypass",
"-File", ".\packages\cli\install.ps1"
)
$installer = Start-Process -FilePath "powershell.exe" -ArgumentList $installerArgs -PassThru -Wait -RedirectStandardOutput $installerStdoutFile -RedirectStandardError $installerStderrFile
$exitCode = $installer.ExitCode
$text = @(
Get-Content -Path $installerStdoutFile -Raw -ErrorAction SilentlyContinue
Get-Content -Path $installerStderrFile -Raw -ErrorAction SilentlyContinue
) -join "`n"
} finally {
if (-not $server.HasExited) {
Stop-Process -Id $server.Id -Force
$server.WaitForExit()
}
}

Write-Host $text
if ($exitCode -eq 0) {
throw "Expected the fixture tarball endpoint to prevent installation"
}

$requests = Get-Content -Path $logFile -Raw
$tarballRequested = $requests.Contains('"path":"/platform.tgz"')
$provenanceError = "does not contain supported npm provenance metadata"

if ($ExpectRejection) {
if (-not $text.Contains($provenanceError)) {
throw "Expected provenance rejection for $Mode"
}
if (-not $text.Contains("@voidzero-dev/vite-plus-cli-") -or
-not $text.Contains($env:TEST_VERSION)) {
throw "Expected rejected package name and version in installer output"
}
if ($tarballRequested) {
throw "Platform tarball was requested before provenance validation"
}
if ((Test-Path (Join-Path $vpHome "current")) -or
(Test-Path (Join-Path $vpHome "$($env:TEST_VERSION)\bin\vp.exe"))) {
throw "Rejected package left an active or executable installation"
}
} else {
if ($text.Contains($provenanceError)) {
throw "Supported provenance metadata was rejected"
}
if (-not $tarballRequested) {
throw "Supported provenance metadata did not reach the tarball endpoint"
}
}

# The child installer and the deliberate tarball failure are expected.
$global:LASTEXITCODE = 0
}

Invoke-ProvenanceCase -Mode "missing" -ExpectRejection $true
Invoke-ProvenanceCase -Mode "malformed" -ExpectRejection $true
Invoke-ProvenanceCase -Mode "top-level-only" -ExpectRejection $true -RawContentType $true
Invoke-ProvenanceCase -Mode "dotted-top-level-key" -ExpectRejection $true
Invoke-ProvenanceCase -Mode "unsupported" -ExpectRejection $true
Invoke-ProvenanceCase -Mode "valid-v1" -ExpectRejection $false
Invoke-ProvenanceCase -Mode "valid-v0.2" -ExpectRejection $false

# Match the version policy in Rust and install.sh on a custom registry.
$env:TEST_VERSION = "0.0.0-commit.0123456789abcdef0123456789abcdef01234567"
Invoke-ProvenanceCase -Mode "missing" -ExpectRejection $false
Invoke-ProvenanceCase -Mode "unsupported" -ExpectRejection $false
$env:TEST_VERSION = "0.0.0-commit.0123456789ABCDEF0123456789ABCDEF01234567"
Invoke-ProvenanceCase -Mode "missing" -ExpectRejection $false
foreach ($version in @(
"1.2.3-beta.1",
"0.0.0",
"0.0.0-beta.1",
# PowerShell 5.1 strips trailing dots from URL paths. Use a bare
# commit label to test a missing SHA through the registry fixture.
"0.0.0-commit",
"0.0.0-commit.abc1234",
"0.0.0-commit.0123456789abcdef0123456789abcdef012345678",
"0.0.0-commit.0123456789abcdef0123456789abcdef0123456g",
"0.0.0-COMMIT.0123456789abcdef0123456789abcdef01234567",
"0.0.0-commit.0123456789abcdef0123456789abcdef01234567.extra"
)) {
$env:TEST_VERSION = $version
Invoke-ProvenanceCase -Mode "missing" -ExpectRejection $true
}
106 changes: 106 additions & 0 deletions .github/scripts/test-install-provenance.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#!/bin/bash
# Run from the repository root with RUNNER_TEMP and TEST_VERSION set.
set -eo pipefail

run_case() {
mode="$1"
expected="$2"
case_dir="$RUNNER_TEMP/vite-plus-provenance-sh-$mode"
port_file="$case_dir/port"
log_file="$case_dir/requests.jsonl"
vp_home="$case_dir/vp-home"

rm -rf "$case_dir"
mkdir -p "$case_dir/home" "$vp_home"
node packages/cli/tests/fixtures/provenance-registry.mjs \
--port-file "$port_file" \
--log-file "$log_file" \
--mode "$mode" \
--version "$TEST_VERSION" &
server_pid=$!

for _ in $(seq 1 100); do
[ -s "$port_file" ] && break
sleep 0.1
done
if [ ! -s "$port_file" ]; then
kill "$server_pid" 2>/dev/null || true
wait "$server_pid" 2>/dev/null || true
echo "Mock registry did not start"
return 1
fi

registry="http://127.0.0.1:$(cat "$port_file")"
set +e
output=$(env \
CI=true \
HOME="$case_dir/home" \
VP_HOME="$vp_home" \
VP_NODE_MANAGER=no \
VP_VERSION="$TEST_VERSION" \
NPM_CONFIG_REGISTRY="$registry" \
bash packages/cli/install.sh 2>&1)
status=$?
set -e

kill "$server_pid" 2>/dev/null || true
wait "$server_pid" 2>/dev/null || true
printf '%s\n' "$output"

if [ "$status" -eq 0 ]; then
echo "Expected the fixture tarball endpoint to prevent installation"
return 1
fi

if [ "$expected" = reject ]; then
printf '%s\n' "$output" | grep -F \
"does not contain supported npm provenance metadata"
printf '%s\n' "$output" | grep -F \
"@voidzero-dev/vite-plus-cli-"
printf '%s\n' "$output" | grep -F "$TEST_VERSION"

if grep -F '"path":"/platform.tgz"' "$log_file"; then
echo "Platform tarball was requested before provenance validation"
return 1
fi
if [ -e "$vp_home/current" ] || [ -e "$vp_home/$TEST_VERSION/bin/vp" ]; then
echo "Rejected package left an active or executable installation"
return 1
fi
else
if printf '%s\n' "$output" | grep -F \
"does not contain supported npm provenance metadata"; then
echo "Supported provenance metadata was rejected"
return 1
fi
grep -F '"path":"/platform.tgz"' "$log_file"
fi
}

run_case missing reject
run_case malformed reject
run_case top-level-only reject
run_case dotted-top-level-key reject
run_case unsupported reject
run_case valid-v1 allow
run_case valid-v0.2 allow

# Commit previews can omit provenance on any registry. Other
# prereleases and malformed commit versions must still be rejected.
TEST_VERSION=0.0.0-commit.0123456789abcdef0123456789abcdef01234567
run_case missing allow
run_case unsupported allow
TEST_VERSION=0.0.0-commit.0123456789ABCDEF0123456789ABCDEF01234567
run_case missing allow
for TEST_VERSION in \
1.2.3-beta.1 \
0.0.0 \
0.0.0-beta.1 \
0.0.0-commit. \
0.0.0-commit.abc1234 \
0.0.0-commit.0123456789abcdef0123456789abcdef012345678 \
0.0.0-commit.0123456789abcdef0123456789abcdef0123456g \
0.0.0-COMMIT.0123456789abcdef0123456789abcdef01234567 \
0.0.0-commit.0123456789abcdef0123456789abcdef01234567.extra; do
run_case missing reject
done
Loading
Loading