From 5e8341bdb46475daa95af66ffbb9b08b3b69e715 Mon Sep 17 00:00:00 2001 From: Sri Aradhyula Date: Thu, 13 Aug 2026 15:59:56 -0500 Subject: [PATCH] fix(installer): avoid latest release API lookup Signed-off-by: Sri Aradhyula --- README.md | 12 +++++++++--- install.sh | 29 ++++++++++------------------- tests/installer.test.ts | 16 ++++++++++++++++ 3 files changed, 35 insertions(+), 22 deletions(-) create mode 100644 tests/installer.test.ts diff --git a/README.md b/README.md index 91f2dc5..48e2f77 100644 --- a/README.md +++ b/README.md @@ -48,9 +48,15 @@ bash <(curl -fsSL https://raw.githubusercontent.com/cnoe-io/caipe-cli/main/setup Then verify the installation with `caipe --version`. If `~/.local/bin` is not already on your `PATH`, the setup script prints the exact command to add it. -The npm package and downloadable release binaries are not published yet. Do -not use `npm install caipe`, `npx github:cnoe-io/caipe-cli`, or `install.sh` -until the first multi-architecture release is available. +The installer downloads the latest multi-architecture GitHub release and +verifies its SHA-256 checksum. Pin a release when reproducibility matters: + +```bash +curl -fsSL https://raw.githubusercontent.com/cnoe-io/caipe-cli/main/install.sh \ + | CAIPE_VERSION=0.2.22 sh +``` + +The npm package is not published yet; use `install.sh` until it is available. ### Updates diff --git a/install.sh b/install.sh index b9c6266..5a27dc6 100755 --- a/install.sh +++ b/install.sh @@ -15,7 +15,8 @@ set -e REPO="cnoe-io/caipe-cli" INSTALL_DIR="${CAIPE_INSTALL_DIR:-/usr/local/bin}" -VERSION="${CAIPE_VERSION:-}" +DEFAULT_VERSION="latest" +VERSION="${CAIPE_VERSION:-$DEFAULT_VERSION}" TAG="" NO_VERIFY="${CAIPE_NO_VERIFY:-0}" @@ -55,35 +56,25 @@ detect_platform() { # ── resolve latest version ──────────────────────────────────────────────────── resolve_version() { - if [ -n "$VERSION" ]; then + if [ "$VERSION" != "$DEFAULT_VERSION" ]; then TAG="$VERSION" info "Using pinned version: $VERSION" return fi - info "Resolving latest release…" - need_cmd curl - - TAG=$(curl -fsSL \ - "https://api.github.com/repos/${REPO}/releases/latest" \ - | grep '"tag_name"' \ - | head -1 \ - | sed 's/.*"tag_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/') - - if [ -z "$TAG" ]; then - die "Could not determine latest caipe release. Set CAIPE_VERSION to install a specific version." - fi - - VERSION="${TAG#caipe/}" - VERSION="${VERSION#v}" - info "Latest version: $VERSION" + info "Using latest release" } # ── download and verify ─────────────────────────────────────────────────────── download_binary() { BINARY_NAME="caipe-${PLATFORM}" - BASE_URL="https://github.com/${REPO}/releases/download/${TAG}" + if [ -n "$TAG" ]; then + BASE_URL="https://github.com/${REPO}/releases/download/${TAG}" + else + # This redirect is not subject to the unauthenticated GitHub API rate limit. + BASE_URL="https://github.com/${REPO}/releases/latest/download" + fi BINARY_URL="${BASE_URL}/${BINARY_NAME}" CHECKSUMS_URL="${BASE_URL}/caipe-checksums.txt" diff --git a/tests/installer.test.ts b/tests/installer.test.ts new file mode 100644 index 0000000..a562334 --- /dev/null +++ b/tests/installer.test.ts @@ -0,0 +1,16 @@ +import { readFileSync } from "node:fs"; +import { describe, expect, it } from "vitest"; + +const installer = readFileSync(new URL("../install.sh", import.meta.url), "utf8"); + +describe("release installer", () => { + it("uses the API-free latest-release redirect by default", () => { + expect(installer).toContain('DEFAULT_VERSION="latest"'); + expect(installer).toContain('BASE_URL="https://github.com/${REPO}/releases/latest/download"'); + expect(installer).not.toContain("api.github.com"); + }); + + it("keeps explicit version pins on immutable release URLs", () => { + expect(installer).toContain('BASE_URL="https://github.com/${REPO}/releases/download/${TAG}"'); + }); +});