fix(install): resilient latest-version fetch (both installers)#946
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughBoth the bash ( ChangesInstaller GitHub API Retry and Fallback
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
dev-punia-altimate
left a comment
There was a problem hiding this comment.
🤖 Code Review — OpenCodeReview (Gemini) — 1 finding(s)
- 1 anchored to a line (posted inline when the comment stream is on)
- 0 without a line anchor
All findings (full text)
1. install.ps1 (L130)
[🟠 MEDIUM] By changing the API failure behavior from exit 1 to a fallback mechanism, $specificVersion can now safely be an empty string "".
However, this introduces a subtle bug further down in the script when it checks if the app is already installed:
try { $installedVersion = (& $probe --version 2>$null | Select-Object -First 1).ToString().Trim() } catch {}
if ($installedVersion -eq $specificVersion) {
Write-Muted "Version $specificVersion already installed"
exit 0
}If the GitHub API fails ($specificVersion = "") AND the local executable is missing or corrupted such that the --version command fails ($installedVersion defaults to ""), the condition "" -eq "" will evaluate to $true. The installer will output Version already installed and incorrectly short-circuit with exit 0 instead of downloading and replacing the broken installation.
To avoid this, you can explicitly reset $specificVersion = $null here when the API fails, which ensures the downstream string-comparison evaluates to $false.
Suggested change:
Write-Muted "Could not resolve the latest version from GitHub (API unavailable) — installing the latest release anyway."
$specificVersion = $null
🤖 Code Review — OpenCodeReview (Gemini) — No Issues FoundNo supported files changed. |
sahrizvi
left a comment
There was a problem hiding this comment.
Three findings inline below — one Critical (the retry loop is currently a no-op under set -euo pipefail), and two High (install.ps1 short-circuit on empty==empty, and no HTTP timeout on either retry). Repro details and one-line suggested fixes inline.
Reported on #930: a transient 504 from api.github.com/.../releases/latest (or the 60/hr/IP unauthenticated rate limit) aborted the whole install with "Failed to fetch version information" — even though the download itself uses releases/latest/download/<file>, which GitHub resolves server-side with no API call. The API response only feeds the version-string display and the already-installed short-circuit. Both installers now, in the latest path: - retry the API call up to 3x with linear backoff (bash uses curl --fail so a 504 retries instead of parsing an error body); - on continued failure, print a muted notice and proceed to install latest anyway (version string shown as "latest"); - only short-circuit as "already installed" on a real version match — never treat empty==empty (unresolved version + unreadable binary) as installed. Pinned-version installs (-Version / --version) are unchanged: a genuine 404 still hard-fails. Tests: version-fetch-resilience.test.ts pins the retry + graceful-degrade behavior in both installers. bash -n clean; install.ps1 parses clean and the Pester suite (6/6) still passes on PowerShell 7.6.2. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- install: append `|| true` to the retry's curl|sed assignment. Under `set -euo pipefail` a failing `curl --fail` propagated through the pipeline and aborted the script at attempt 1, before the loop could retry or degrade (sahrizvi; reproduced: exit 22 without the fix, all 3 attempts + degrade with it). Also add `--max-time 10` to bound a dead-air socket. - install.ps1: reset $specificVersion to $null (not "") on the degrade path, so the already-installed short-circuit can't false-match "" -eq "" when the version probe of a missing/corrupt binary also yields "" (dev-punia, sahrizvi). - install.ps1: add -TimeoutSec 10 to Invoke-RestMethod (defaults to 100s on PS 5.1, unbounded on PS 7+) to bound retries on dead air (sahrizvi). - tests: TS guards for `|| true`, --max-time/-TimeoutSec, and the $null reset. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019M7GkS3bYZaFhEbBhVTecG
be6c0c0 to
d23fc1a
Compare
- install.ps1: decode a Byte[] checksums.txt body so verification works on Windows PowerShell 5.1. GitHub serves release assets as octet-stream, so on PS 5.1 Invoke-WebRequest returns .Content as Byte[]; it coerced to a decimal string and every check silently soft-skipped (sahrizvi, P1). - install.ps1: pin the archive and checksums.txt to the resolved release tag instead of the mutable latest/ URL, so a release published mid-install can't hand back mismatched assets and trigger a spurious hard-fail (cubic, P2). Falls back to latest/ only when the version can't be resolved. - install: in verify_checksum, clean up via $(dirname "$file") rather than the caller's dynamically-scoped $tmp_dir local — self-contained (cubic, P2). - tests: Pester coverage for Test-Checksum (String + Byte[] + mismatch paths, verified to fail without the decode) and TS guards for the decode and the PowerShell same-release pinning. Note: the bash installer is intentionally left on the latest/download path here to keep this PR disjoint from #946 (which owns the bash latest-version block); the two PRs then merge in either order with no conflict. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019M7GkS3bYZaFhEbBhVTecG
- install.ps1: decode a Byte[] checksums.txt body so verification works on Windows PowerShell 5.1. GitHub serves release assets as octet-stream, so on PS 5.1 Invoke-WebRequest returns .Content as Byte[]; it coerced to a decimal string and every check silently soft-skipped (sahrizvi, P1). - install.ps1: pin the archive and checksums.txt to the resolved release tag instead of the mutable latest/ URL, so a release published mid-install can't hand back mismatched assets and trigger a spurious hard-fail (cubic, P2). Falls back to latest/ only when the version can't be resolved. - install: in verify_checksum, clean up via $(dirname "$file") rather than the caller's dynamically-scoped $tmp_dir local — self-contained (cubic, P2). - tests: Pester coverage for Test-Checksum (String + Byte[] + mismatch paths, verified to fail without the decode) and TS guards for the decode and the PowerShell same-release pinning. Note: the bash installer is intentionally left on the latest/download path here to keep this PR disjoint from #946 (which owns the bash latest-version block); the two PRs then merge in either order with no conflict. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019M7GkS3bYZaFhEbBhVTecG
install.ps1 had no BOM and used a few non-ASCII characters (em dash, ellipsis, right arrow) in comments and messages. Windows PowerShell 5.1 - the default shell on Windows 10 and preinstalled on Windows 11 - reads a BOM-less file as the system ANSI codepage, not UTF-8, so those multi-byte characters corrupt the token stream and the whole script fails to parse (verified on real PS 5.1). This is a pre-existing issue (the characters predate this PR) that CI doesn't catch because the Pester job runs under pwsh (PowerShell 7, UTF-8 by default). Replacing the three characters with ASCII equivalents (-, ..., ->) makes the installer parse and run on PS 5.1 while keeping pwsh behavior identical. Also removes the now-obsolete "integrity verification deferred" NOTE comment: the sibling PR #942 implements that verification and removes the same block, so deleting it here too keeps the two PRs mergeable in either order with no conflict. Same transliteration is applied verbatim in #942. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019M7GkS3bYZaFhEbBhVTecG
install.ps1 had no BOM and used a few non-ASCII characters (em dash, ellipsis, right arrow) in comments and messages. Windows PowerShell 5.1 — the default shell on Windows 10 and preinstalled on Windows 11 — reads a BOM-less file as the system ANSI codepage, not UTF-8, so those multi-byte characters corrupt the token stream and the whole script fails to parse (verified on real PS 5.1: "The '<' operator is reserved", cascading to "Missing closing '}'"). This is a pre-existing issue (the characters predate this PR) that CI doesn't catch because the Pester job runs under pwsh (PowerShell 7, UTF-8 by default). Replacing the three characters with ASCII equivalents (-, ..., ->) makes the installer parse and run on PS 5.1 while keeping pwsh behavior identical. Verified end-to-end on real Windows PowerShell 5.1: resolve version -> download -> extract -> place the binary all succeed. Same transliteration is applied verbatim in #946 so the two PRs merge cleanly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019M7GkS3bYZaFhEbBhVTecG
The #952 release-validation suite asserted the latest path hard-fails with "Failed to fetch version information" (>=2) and that exit 1 appears >=3 times. This PR makes the latest path retry then degrade gracefully instead of aborting, so update those assertions: the latest path no longer hard-fails (the unsupported -arch and pinned-404 paths still exit 1, hence >=2). (This test never ran on this PR until it was retargeted from the merged feat/windows-powershell-installer branch to main.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019M7GkS3bYZaFhEbBhVTecG
Combined end-to-end verification (both installer PRs together)#942 and #946 are sibling PRs that both touch Merge safety
Real Windows verificationRan the merged
#942 — checksum verification
#946 — resilient latest-version fetch
Cross-PR composition (verified on real PowerShell)With both changes combined: when the version can't be resolved, #946 sets CIGreen on both: TypeScript, Windows Installer (Pester), and the |
❌ Tests — Failures DetectedTypeScript — 15 failure(s)
Next StepPlease address the failing cases above and re-run verification. cc @mdesmet |
) * feat(install): verify release archive checksums (both installers) Raises the integrity bar for the standalone installers (follow-up to #930). - release.yml: generate a checksums.txt (sha256sum format) over the release archives and publish it as a release asset. - install (bash) + install.ps1: fetch checksums.txt and verify the downloaded archive's SHA256 before extracting. Hard-fail on mismatch; soft-skip with a notice when checksums.txt is absent (older pinned releases) or unreachable, so existing version-pinned installs keep working. - Cross-platform sha in bash (sha256sum or shasum -a 256); Get-FileHash on Windows. Verification runs before extraction in both. - Tests: checksum-verification.test.ts asserts release.yml publishes the file and both installers fetch + compare + hard-fail on mismatch. Verified: bash -n clean; install.ps1 parses clean and the Pester suite (6/6) still passes on PowerShell 7.6.2. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(install): address checksum-verification review - install.ps1: decode a Byte[] checksums.txt body so verification works on Windows PowerShell 5.1. GitHub serves release assets as octet-stream, so on PS 5.1 Invoke-WebRequest returns .Content as Byte[]; it coerced to a decimal string and every check silently soft-skipped (sahrizvi, P1). - install.ps1: pin the archive and checksums.txt to the resolved release tag instead of the mutable latest/ URL, so a release published mid-install can't hand back mismatched assets and trigger a spurious hard-fail (cubic, P2). Falls back to latest/ only when the version can't be resolved. - install: in verify_checksum, clean up via $(dirname "$file") rather than the caller's dynamically-scoped $tmp_dir local — self-contained (cubic, P2). - tests: Pester coverage for Test-Checksum (String + Byte[] + mismatch paths, verified to fail without the decode) and TS guards for the decode and the PowerShell same-release pinning. Note: the bash installer is intentionally left on the latest/download path here to keep this PR disjoint from #946 (which owns the bash latest-version block); the two PRs then merge in either order with no conflict. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019M7GkS3bYZaFhEbBhVTecG * fix(install.ps1): ASCII-only so it parses on Windows PowerShell 5.1 install.ps1 had no BOM and used a few non-ASCII characters (em dash, ellipsis, right arrow) in comments and messages. Windows PowerShell 5.1 — the default shell on Windows 10 and preinstalled on Windows 11 — reads a BOM-less file as the system ANSI codepage, not UTF-8, so those multi-byte characters corrupt the token stream and the whole script fails to parse (verified on real PS 5.1: "The '<' operator is reserved", cascading to "Missing closing '}'"). This is a pre-existing issue (the characters predate this PR) that CI doesn't catch because the Pester job runs under pwsh (PowerShell 7, UTF-8 by default). Replacing the three characters with ASCII equivalents (-, ..., ->) makes the installer parse and run on PS 5.1 while keeping pwsh behavior identical. Verified end-to-end on real Windows PowerShell 5.1: resolve version -> download -> extract -> place the binary all succeed. Same transliteration is applied verbatim in #946 so the two PRs merge cleanly. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019M7GkS3bYZaFhEbBhVTecG * fix(install): guard the verify_checksum cleanup against a pathological path Defensive depth (coderabbit): only `rm -rf` the cleanup dir when dirname resolves to a real subdirectory, never "." or "/", so an unexpectedly empty or root-level $file can't wipe the cwd or worse. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019M7GkS3bYZaFhEbBhVTecG * test: update #930 release-validation for the checksum URL refactor The #952 release-validation suite asserted the exact #930 URL literals. This PR builds the archive and checksums.txt from a shared $base (so they always come from the same release), so update those assertions to the $base/$url form, and convert the now-obsolete "verification deferred" test.todo into a real assertion that Test-Checksum verifies SHA256 before extraction. (This test never ran on this PR until it was retargeted from the merged feat/windows-powershell-installer branch to main.) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019M7GkS3bYZaFhEbBhVTecG --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: ralphstodomingo <ralphstodomingo@users.noreply.github.com>
sahrizvi
left a comment
There was a problem hiding this comment.
E2E tested, doesnt't touch core altimate-code, so LGTM.
What
Follow-up to #930 (reported by @ralphstodomingo): a transient 504 from
api.github.com/.../releases/latest— or the 60/hr/IP unauthenticated rate limit — aborted the whole install withFailed to fetch version information, even though the download usesreleases/latest/download/<file>(GitHub resolves "latest" server-side, no API call needed). The API response only feeds the version-string display and the already-installed short-circuit.This issue exists in both installers (
installbash:206-213 andinstall.ps1), so both are fixed here for parity.Stacked on
feat/windows-powershell-installer(sibling to #942) becauseinstall.ps1isn't onmainyet.Changes (latest path, both installers)
releases/latestAPI call up to 3× with linear backoff (bash usescurl --failso a 504 retries instead of parsing an error body).latest).-Version/--versionunchanged: a genuine 404 still hard-fails.Note (from the same review comment): the
exit 0-closes-an-interactive-window quirk underirm | iexis PowerShell-only and only affects pasting directly into an interactive shell (not the documentedpowershell -c "…"form);curl | bashexits in a subshell. Left as-is — low severity, no parity gap to fix.Verification
bash -n installclean;install.ps1parses clean and the Pester suite (6/6) still passes on PowerShell 7.6.2.version-fetch-resilience.test.tspins retry + graceful-degrade in both installers (57 pass across the install/branding set).🤖 Generated with Claude Code
Summary by cubic
Makes the “latest” install path resilient in both installers and fixes Windows parsing on PowerShell 5.1. Installs no longer fail when the GitHub releases API blips; they retry and proceed with “latest”.
releases/latestup to 3 times with backoff and a 10s timeout; on failure, continue and show “latest”. Pinned--version/-Versioninstalls unchanged.$specificVersionto$nullon degrade to avoid empty==empty.install.ps1ASCII-only so it parses on Windows PowerShell 5.1.packages/opencode/test/install/version-fetch-resilience.test.tsto pin retry, timeout, and graceful-degrade; updatepackages/opencode/test/release-validation/windows-installer-930-codex.test.tsto expect degrade (not hard-fail) on latest-version fetch.Written for commit e10e322. Summary will update on new commits.
Summary by CodeRabbit
Release Notes
Bug Fixes
Tests