fix: production quality improvements

- Add PowerShell 4.0+ version check at startup
- Add disk space check (100MB minimum) before install
- Add try/finally cleanup for download temp files (handles Ctrl+C)
- Fix PATH duplicate semicolons by trimming before append
- Update header with requirements documentation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
unknown 2026-02-01 00:54:45 +11:00
parent 1248758d46
commit 05bd711219
No known key found for this signature in database
GPG key ID: FE478DD75EE21194

View file

@ -1,6 +1,11 @@
# Install the Core CLI (Windows) # Install the Core CLI (Windows)
# Run: .\scripts\install-core.ps1 # Run: .\scripts\install-core.ps1
# #
# REQUIREMENTS:
# - PowerShell 4.0 or later
# - Windows 10/11 or Windows Server 2016+
# - 100MB free disk space
#
# SECURITY CONTROLS: # SECURITY CONTROLS:
# - Version pinning prevents supply chain attacks via tag manipulation # - Version pinning prevents supply chain attacks via tag manipulation
# - SHA256 hash verification ensures binary integrity # - SHA256 hash verification ensures binary integrity
@ -15,8 +20,15 @@
$ErrorActionPreference = "Stop" $ErrorActionPreference = "Stop"
# Check PowerShell version (4.0+ required for Get-FileHash and other features)
if ($PSVersionTable.PSVersion.Major -lt 4) {
Write-Host "[ERROR] PowerShell 4.0 or later is required. Current version: $($PSVersionTable.PSVersion)" -ForegroundColor Red
exit 1
}
$Repo = "host-uk/core" $Repo = "host-uk/core"
$Version = "v0.1.0" # Pinned version - update when releasing new versions $Version = "v0.1.0" # Pinned version - update when releasing new versions
$MinDiskSpaceMB = 100 # Minimum required disk space in MB
function Write-Info { Write-Host "[INFO] $args" -ForegroundColor Green } function Write-Info { Write-Host "[INFO] $args" -ForegroundColor Green }
function Write-Warn { Write-Host "[WARN] $args" -ForegroundColor Yellow } function Write-Warn { Write-Host "[WARN] $args" -ForegroundColor Yellow }
@ -26,6 +38,32 @@ function Test-Command($cmd) {
return [bool](Get-Command $cmd -ErrorAction SilentlyContinue) return [bool](Get-Command $cmd -ErrorAction SilentlyContinue)
} }
# Check available disk space
function Test-DiskSpace {
param([string]$Path)
try {
# Get the drive from the path
$drive = [System.IO.Path]::GetPathRoot($Path)
if ([string]::IsNullOrEmpty($drive)) {
$drive = [System.IO.Path]::GetPathRoot($env:LOCALAPPDATA)
}
$driveInfo = Get-PSDrive -Name $drive.Substring(0, 1) -ErrorAction Stop
$freeSpaceMB = [math]::Round($driveInfo.Free / 1MB, 2)
if ($freeSpaceMB -lt $MinDiskSpaceMB) {
Write-Err "Insufficient disk space. Need at least ${MinDiskSpaceMB}MB, but only ${freeSpaceMB}MB available on drive $drive"
}
Write-Info "Disk space check passed (${freeSpaceMB}MB available)"
return $true
} catch {
Write-Warn "Could not verify disk space: $($_.Exception.Message)"
return $true # Continue anyway if check fails
}
}
# Validate and get secure install directory # Validate and get secure install directory
function Get-SecureInstallDir { function Get-SecureInstallDir {
# Validate LOCALAPPDATA is within user profile # Validate LOCALAPPDATA is within user profile
@ -179,6 +217,9 @@ function Download-Binary {
Write-Info "Attempting to download pre-built binary (version $Version)..." Write-Info "Attempting to download pre-built binary (version $Version)..."
Write-Info "URL: $binaryUrl" Write-Info "URL: $binaryUrl"
# Track temp file for cleanup
$tempExe = $null
try { try {
# Create and verify install directory # Create and verify install directory
New-SecureDirectory -Path $InstallDir New-SecureDirectory -Path $InstallDir
@ -204,7 +245,6 @@ function Download-Binary {
} }
if ([string]::IsNullOrEmpty($expectedHash)) { if ([string]::IsNullOrEmpty($expectedHash)) {
Remove-Item -Path $tempExe -Force -ErrorAction SilentlyContinue
Write-Err "Could not find checksum for core-windows-$arch.exe in checksums.txt" Write-Err "Could not find checksum for core-windows-$arch.exe in checksums.txt"
} }
@ -217,6 +257,7 @@ function Download-Binary {
# Atomic move to final location (same filesystem) # Atomic move to final location (same filesystem)
$finalPath = Join-Path $InstallDir "core.exe" $finalPath = Join-Path $InstallDir "core.exe"
Move-Item -Path $tempExe -Destination $finalPath -Force Move-Item -Path $tempExe -Destination $finalPath -Force
$tempExe = $null # Clear so finally block doesn't try to delete
Write-Info "Downloaded and verified: $finalPath" Write-Info "Downloaded and verified: $finalPath"
return $true return $true
@ -232,6 +273,11 @@ function Download-Binary {
Write-Warn "Download failed: $($_.Exception.Message)" Write-Warn "Download failed: $($_.Exception.Message)"
Write-Warn "Will attempt to build from source" Write-Warn "Will attempt to build from source"
return $false return $false
} finally {
# Clean up temp file if it exists (handles Ctrl+C and other interruptions)
if ($tempExe -and (Test-Path $tempExe -ErrorAction SilentlyContinue)) {
Remove-Item -Path $tempExe -Force -ErrorAction SilentlyContinue
}
} }
} }
@ -352,7 +398,9 @@ function Setup-Path {
if (-not $alreadyInPath) { if (-not $alreadyInPath) {
Write-Info "Adding $InstallDir to PATH..." Write-Info "Adding $InstallDir to PATH..."
[Environment]::SetEnvironmentVariable("PATH", "$userPath;$InstallDir", "User") # Trim trailing semicolons to prevent duplicates
$cleanPath = $userPath.TrimEnd(';')
[Environment]::SetEnvironmentVariable("PATH", "$cleanPath;$InstallDir", "User")
$env:PATH = "$env:PATH;$InstallDir" $env:PATH = "$env:PATH;$InstallDir"
} }
} }
@ -378,6 +426,9 @@ function Verify {
function Main { function Main {
Write-Info "Installing Core CLI (version $Version)..." Write-Info "Installing Core CLI (version $Version)..."
# Check disk space before starting
Test-DiskSpace -Path $InstallDir
# Try download first, fallback to build # Try download first, fallback to build
if (-not (Download-Binary)) { if (-not (Download-Binary)) {
Build-FromSource Build-FromSource