#!/bin/sh # Sensa installer — descarga el binario `sensa` para tu OS/arch y lo instala. # # El repositorio es PRIVADO, así que la descarga requiere autenticación de # GitHub. El instalador usa, por orden: # 1. `gh` (GitHub CLI) autenticado → gh auth login # 2. un token en GITHUB_TOKEN / GH_TOKEN → export GITHUB_TOKEN=... # 3. un mirror público en SENSA_INSTALL_BASE (si algún día se aloja fuera) # # Uso: # gh auth login && curl -fsSL .../install.sh | sh # GITHUB_TOKEN=ghp_xxx sh install.sh # # Overrides: # SENSA_INSTALL_BASE base URL de un mirror público (evita la auth) # SENSA_INSTALL_DIR directorio de instalación (def: /usr/local/bin o ~/.local/bin) # SENSA_VERSION tag a instalar (def: latest) set -eu SENSA_INSTALL_BASE="${SENSA_INSTALL_BASE:-https://install.sensa.co}" REPO="manugamero/sensa-install" BIN="sensa" VERSION="${SENSA_VERSION:-latest}" info() { printf '\033[1;38;5;209m▸\033[0m %s\n' "$1"; } err() { printf '\033[1;31m✗\033[0m %s\n' "$1" >&2; exit 1; } # verify_checksum # Best-effort SHA-256 check against /checksums.txt. No-ops if the # checksum list or a sha tool is unavailable; fails hard only on a mismatch. verify_checksum() { _file="$1"; _name="$2"; _base="$3"; _tool="" if command -v sha256sum >/dev/null 2>&1; then _tool="sha256sum" elif command -v shasum >/dev/null 2>&1; then _tool="shasum -a 256" else return 0; fi _sums="$(curl -fsSL "$_base/checksums.txt" 2>/dev/null)" || return 0 _want="$(printf '%s\n' "$_sums" | grep " ${_name}\$" | awk '{print $1}' | head -1)" [ -n "$_want" ] || return 0 _got="$($_tool "$_file" | awk '{print $1}')" [ "$_want" = "$_got" ] || err "Checksum no coincide para ${_name} (esperado ${_want}, obtenido ${_got})" info "Checksum verificado ✓" } # --- detect platform (Go-style names, matching goreleaser archives) -------- os="$(uname -s)" arch="$(uname -m)" case "$os" in Darwin) OS="darwin" ;; Linux) OS="linux" ;; *) err "SO no soportado: $os (usa la versión web en sensa.co)" ;; esac case "$arch" in x86_64|amd64) ARCH="amd64" ;; arm64|aarch64) ARCH="arm64" ;; *) err "Arquitectura no soportada: $arch" ;; esac ARCHIVE="${BIN}_${OS}_${ARCH}.tar.gz" # --- choose install dir ----------------------------------------------------- if [ -n "${SENSA_INSTALL_DIR:-}" ]; then DIR="$SENSA_INSTALL_DIR" elif [ -w /usr/local/bin ] 2>/dev/null; then DIR="/usr/local/bin" else DIR="$HOME/.local/bin" fi mkdir -p "$DIR" tmp="$(mktemp -d)" trap 'rm -rf "$tmp"' EXIT out="$tmp/$ARCHIVE" # --- resolve token ---------------------------------------------------------- TOKEN="${GITHUB_TOKEN:-${GH_TOKEN:-}}" if [ -z "$TOKEN" ] && command -v gh >/dev/null 2>&1; then TOKEN="$(gh auth token 2>/dev/null || true)" fi # --- download --------------------------------------------------------------- info "Descargando $BIN ($OS/$ARCH)…" if [ -n "${SENSA_INSTALL_BASE:-}" ]; then # Public mirror: plain download, no auth, verified against checksums.txt. curl -fsSL "$SENSA_INSTALL_BASE/$ARCHIVE" -o "$out" \ || err "No se pudo descargar $SENSA_INSTALL_BASE/$ARCHIVE" verify_checksum "$out" "$ARCHIVE" "$SENSA_INSTALL_BASE" elif command -v gh >/dev/null 2>&1 && gh auth token >/dev/null 2>&1; then # Private repo via GitHub CLI (preferred). if [ "$VERSION" = "latest" ]; then gh release download --repo "$REPO" --pattern "$ARCHIVE" --dir "$tmp" --clobber \ || err "gh no pudo descargar $ARCHIVE del último release" else gh release download "$VERSION" --repo "$REPO" --pattern "$ARCHIVE" --dir "$tmp" --clobber \ || err "gh no pudo descargar $ARCHIVE de $VERSION" fi elif [ -n "$TOKEN" ]; then # Private repo via API + token (no gh). if [ "$VERSION" = "latest" ]; then rel="latest"; else rel="tags/$VERSION"; fi api="https://api.github.com/repos/$REPO/releases/$rel" json="$(curl -fsSL -H "Authorization: Bearer $TOKEN" -H "Accept: application/vnd.github+json" "$api")" \ || err "No se pudo consultar el release ($api)" asset_id="$(printf '%s\n' "$json" | awk -v n="\"name\": \"$ARCHIVE\"" ' /"id":/ { if (match($0, /[0-9]+/)) id = substr($0, RSTART, RLENGTH) } index($0, n) { print id; exit }')" [ -n "$asset_id" ] || err "No se encontró el asset $ARCHIVE en el release" curl -fsSL -H "Authorization: Bearer $TOKEN" -H "Accept: application/octet-stream" \ "https://api.github.com/repos/$REPO/releases/assets/$asset_id" -o "$out" \ || err "No se pudo descargar el asset $asset_id" else err "Repo privado: autentícate con GitHub para instalar. Opción A: gh auth login Opción B: export GITHUB_TOKEN= Opción C: define SENSA_INSTALL_BASE si alojas un mirror público" fi # --- install ---------------------------------------------------------------- [ -f "$out" ] || err "Descarga fallida: no existe $ARCHIVE" tar -xzf "$out" -C "$tmp" [ -f "$tmp/$BIN" ] || err "Archivo inválido: falta el binario $BIN" chmod +x "$tmp/$BIN" mv "$tmp/$BIN" "$DIR/$BIN" info "Instalado en $DIR/$BIN" case ":$PATH:" in *":$DIR:"*) ;; *) info "Añade $DIR a tu PATH: export PATH=\"$DIR:\$PATH\"" ;; esac printf '\n\033[1;38;5;209mListo.\033[0m Ejecuta \033[1msensa\033[0m para empezar tu auditoría.\n'