diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 356aaa9..3db2229 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,9 +54,42 @@ jobs: - name: Cross-compile the release targets run: | set -euo pipefail - for target in linux/amd64 linux/arm64 darwin/amd64 darwin/arm64; do + for target in linux/amd64 linux/arm64 darwin/amd64 darwin/arm64 windows/amd64 windows/arm64; do os="${target%/*}" arch="${target#*/}" echo "building $os/$arch" CGO_ENABLED=0 GOOS="$os" GOARCH="$arch" go build -o /dev/null . done + + # The installers are the one thing here that is not Go and is not tested + # by anything: they only run on a member's machine, and both times this + # one broke it broke at runtime with nothing to catch it. Neither rule + # below would have found the Byte[] bug - only running it did - but each + # is a mechanical rule for a mistake that already cost a release. + - name: Check the PowerShell installer + shell: pwsh + run: | + $script = Get-Content -Raw scripts/install.ps1 + + # Parse it, so a syntax error is not discovered by the first person + # to pipe it into iex. + $errors = $null + [System.Management.Automation.Language.Parser]::ParseInput($script, [ref]$null, [ref]$errors) | Out-Null + if ($errors.Count -gt 0) { + $errors | ForEach-Object { Write-Host "::error::$($_.Message)" } + exit 1 + } + + # Every Invoke-WebRequest needs -UseBasicParsing. Without it, + # PowerShell 5.1 hands the body to the Internet Explorer engine, and + # where that is absent or has never run its first-run setup the call + # throws a NullReferenceException. It is the default from 6 up, so + # this never shows on a modern pwsh and always shows on Windows 10. + $lines = $script -split "`n" + for ($i = 0; $i -lt $lines.Count; $i++) { + if ($lines[$i] -match 'Invoke-WebRequest' -and $lines[$i] -notmatch '-UseBasicParsing' -and $lines[$i] -notmatch '^\s*#') { + Write-Host "::error file=scripts/install.ps1,line=$($i + 1)::Invoke-WebRequest without -UseBasicParsing" + exit 1 + } + } + Write-Host "installer parses, and every web request is basic-parsed" diff --git a/internal/tui/tui.go b/internal/tui/tui.go index c124cf1..c0cca47 100644 --- a/internal/tui/tui.go +++ b/internal/tui/tui.go @@ -2114,7 +2114,7 @@ func (m model) renderSetup(l layout) string { // ── about renderer ─────────────────────────────────────────────────────────── -const Version = "0.1.3" +const Version = "0.1.4" func renderAbout(l layout) string { var b strings.Builder diff --git a/scripts/install.ps1 b/scripts/install.ps1 index fe391b5..47bbabb 100644 --- a/scripts/install.ps1 +++ b/scripts/install.ps1 @@ -28,7 +28,7 @@ irm https://nan.builders/install.ps1 | iex .EXAMPLE - & ([scriptblock]::Create((irm https://nan.builders/install.ps1))) -Version v0.1.3 + & ([scriptblock]::Create((irm https://nan.builders/install.ps1))) -Version v0.1.4 #> [CmdletBinding()] param( @@ -79,7 +79,7 @@ function Get-LatestVersion { Write-Fail 'could not work out the latest version from the GitHub API' Write-Fail 'it rate limits unauthenticated requests, so this is usually temporary' Write-Fail 'wait a few minutes, or pick a version yourself:' - Write-Host ' & ([scriptblock]::Create((irm https://nan.builders/install.ps1))) -Version v0.1.3' + Write-Host ' & ([scriptblock]::Create((irm https://nan.builders/install.ps1))) -Version v0.1.4' Write-Fail "the releases are at https://github.com/$Repo/releases" exit 1 } @@ -131,7 +131,12 @@ New-Item -ItemType Directory -Path $tmp -Force | Out-Null try { Write-Step "downloading $archive..." try { - Invoke-WebRequest -Uri "$base/$archive" -OutFile (Join-Path $tmp $archive) + # -UseBasicParsing on every request here. Without it, PowerShell 5.1 hands + # the body to the Internet Explorer engine to build a DOM, and where that + # engine is absent or has never been through its first-run setup the call + # throws a NullReferenceException - which is what "Object reference not set + # to an instance of an object" means coming out of Invoke-WebRequest. + Invoke-WebRequest -Uri "$base/$archive" -OutFile (Join-Path $tmp $archive) -UseBasicParsing } catch { Write-Fail "could not download $archive" Write-Fail "check that $Version is a published release: https://github.com/$Repo/releases" @@ -139,9 +144,15 @@ try { } Write-Step 'verifying checksum...' - $checksums = (Invoke-WebRequest -Uri "$base/checksums.txt").Content + # Downloaded to a file rather than read off the response. GitHub serves + # release assets as application/octet-stream, and for a non-text content type + # PowerShell hands back .Content as a Byte[], not a string: splitting that on + # a newline matches nothing and every archive reads as having no checksum. + # -OutFile takes the bytes as they come and Get-Content decodes them. + $checksumFile = Join-Path $tmp 'checksums.txt' + Invoke-WebRequest -Uri "$base/checksums.txt" -OutFile $checksumFile -UseBasicParsing $expected = $null - foreach ($line in $checksums -split "`n") { + foreach ($line in (Get-Content -Path $checksumFile)) { if ($line -match "^([0-9a-fA-F]{64})\s+\*?$([regex]::Escape($archive))\s*$") { $expected = $Matches[1] } diff --git a/scripts/install.sh b/scripts/install.sh index 39b92ac..7467333 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -62,7 +62,7 @@ require_version() { err "could not work out the latest version from the GitHub API" err "it rate limits unauthenticated requests, so this is usually temporary" err "wait a few minutes, or pick a version yourself:" - printf " VERSION=v0.1.3 curl -fsSL https://nan.builders/install | bash + printf " VERSION=v0.1.4 curl -fsSL https://nan.builders/install | bash " >&2 err "the releases are at https://github.com/$REPO/releases" exit 1