#!/usr/bin/env bash set -euo pipefail repo="${CELL_GITHUB_REPO:-cellcortex-ai/cellcortex-pro}" prefix="${CELL_INSTALL_PREFIX:-$HOME/.local}" bin_dir="${prefix}/bin" channel_base="${CELL_CHANNEL_BASE_URL:-https://install.cellcortex.dev/channels}" channel_name="pro-stable.txt" use_latest="${CELL_INSTALL_USE_LATEST:-0}" usage() { cat <<'USAGE' Install CellCortex Pro edition as `cell`. Usage: curl -sSL https://install.cellcortex.dev/pro | bash curl -sSL https://install.cellcortex.dev/pro | bash -s -- --latest Optional env: CELL_VERSION Release tag (e.g. v0.1.0); overrides channel/default behavior CELL_INSTALL_PREFIX Install prefix (default ~/.local) CELL_GITHUB_TOKEN Optional GitHub token for private release asset access CELL_INSTALL_USE_LATEST Set to 1 to force GitHub latest release (testing only) CELL_CHANNEL_BASE_URL Override stable channel base URL CELL_INSTALL_PUBKEY_PATH Path to cosign public key (PEM) CELL_INSTALL_PUBKEY_B64 Base64-encoded cosign public key (PEM) CELL_INSTALL_ALLOW_UNSIGNED Set to 1 to bypass signature verification (not recommended) USAGE } while [[ $# -gt 0 ]]; do case "$1" in --latest) use_latest="1" shift ;; --help|-h) usage exit 0 ;; *) echo "Unknown argument: $1" >&2 usage exit 1 ;; esac done if ! command -v curl >/dev/null 2>&1; then echo "curl is required" >&2 exit 1 fi if ! command -v shasum >/dev/null 2>&1 && ! command -v sha256sum >/dev/null 2>&1; then echo "No SHA256 verifier found (shasum/sha256sum)." >&2 exit 1 fi os="$(uname -s)" case "${os}" in Linux) asset_cli="cell-pro-linux" ;; Darwin) asset_cli="cell-pro-macos" ;; *) echo "Unsupported OS: ${os}" >&2; exit 1 ;; esac resolve_stable_version() { local channel_url="${channel_base}/${channel_name}" local stable stable="$(curl --proto '=https' --tlsv1.2 -fsSL "${channel_url}" | tr -d '\r' | sed 's/#.*$//' | tr -d '[:space:]')" if [[ -z "${stable}" ]]; then return 1 fi printf '%s' "${stable}" } if [[ -n "${CELL_VERSION:-}" ]]; then base_url="https://github.com/${repo}/releases/download/${CELL_VERSION}" elif [[ "${use_latest}" == "1" ]]; then base_url="https://github.com/${repo}/releases/latest/download" else if stable_version="$(resolve_stable_version)"; then if [[ "${stable_version}" == "latest" ]]; then base_url="https://github.com/${repo}/releases/latest/download" else base_url="https://github.com/${repo}/releases/download/${stable_version}" fi else echo "Unable to resolve stable channel ${channel_base}/${channel_name}." >&2 echo "Retry later, set CELL_VERSION=, or use --latest for non-production testing." >&2 exit 1 fi fi tmp_dir="$(mktemp -d)" cleanup() { rm -rf "${tmp_dir}"; } trap cleanup EXIT curl_fetch() { local url="$1" local out="$2" if [[ -n "${CELL_GITHUB_TOKEN:-}" ]]; then curl --proto '=https' --tlsv1.2 -fsSL -H "Authorization: Bearer ${CELL_GITHUB_TOKEN}" "${url}" -o "${out}" else curl --proto '=https' --tlsv1.2 -fsSL "${url}" -o "${out}" fi } if ! curl_fetch "${base_url}/${asset_cli}" "${tmp_dir}/${asset_cli}"; then echo "Failed to download ${asset_cli}." >&2 echo "If Pro releases are private, set CELL_GITHUB_TOKEN with release-read access." >&2 exit 1 fi if ! curl_fetch "${base_url}/${asset_cli}.sha256" "${tmp_dir}/${asset_cli}.sha256"; then echo "Failed to download checksum for ${asset_cli}." >&2 echo "If Pro releases are private, set CELL_GITHUB_TOKEN with release-read access." >&2 exit 1 fi if ! curl_fetch "${base_url}/${asset_cli}.sig" "${tmp_dir}/${asset_cli}.sig"; then echo "Failed to download signature for ${asset_cli}." >&2 echo "If Pro releases are private, set CELL_GITHUB_TOKEN with release-read access." >&2 exit 1 fi if command -v shasum >/dev/null 2>&1; then (cd "${tmp_dir}" && shasum -a 256 -c "${asset_cli}.sha256") else (cd "${tmp_dir}" && sha256sum -c "${asset_cli}.sha256") fi resolve_pubkey_file() { if [[ -n "${CELL_INSTALL_PUBKEY_PATH:-}" ]]; then echo "${CELL_INSTALL_PUBKEY_PATH}" return 0 fi if [[ -n "${CELL_INSTALL_PUBKEY_B64:-}" ]]; then local pub="${tmp_dir}/cosign.pub" if printf '%s' "${CELL_INSTALL_PUBKEY_B64}" | base64 --decode > "${pub}" 2>/dev/null; then : elif printf '%s' "${CELL_INSTALL_PUBKEY_B64}" | base64 -D > "${pub}" 2>/dev/null; then : else echo "Failed to decode CELL_INSTALL_PUBKEY_B64 with base64." >&2 exit 1 fi echo "${pub}" return 0 fi return 1 } verify_signature() { local pubkey_file if ! pubkey_file="$(resolve_pubkey_file)"; then if [[ "${CELL_INSTALL_ALLOW_UNSIGNED:-0}" == "1" ]]; then echo "WARNING: skipping signature verification for ${asset_cli} (CELL_INSTALL_ALLOW_UNSIGNED=1)." >&2 return 0 fi echo "Signature verification requires CELL_INSTALL_PUBKEY_PATH or CELL_INSTALL_PUBKEY_B64." >&2 echo "Set CELL_INSTALL_ALLOW_UNSIGNED=1 only for trusted, temporary local testing." >&2 exit 1 fi if ! command -v cosign >/dev/null 2>&1; then echo "cosign is required for signature verification. Install from https://docs.sigstore.dev/cosign/installation/" >&2 exit 1 fi cosign verify-blob \ --key "${pubkey_file}" \ --signature "${tmp_dir}/${asset_cli}.sig" \ "${tmp_dir}/${asset_cli}" >/dev/null } verify_signature mkdir -p "${bin_dir}" install -m 0755 "${tmp_dir}/${asset_cli}" "${bin_dir}/cell" echo "Installed Pro CLI: ${bin_dir}/cell" echo "Activate with: ${bin_dir}/cell auth login --license-key "