#!/bin/sh
# sbomlyze installer script
# Usage: curl -sSfL https://raw.githubusercontent.com/rezmoss/sbomlyze/main/install.sh | sh -s -- [options]
#
# Options:
# -b
Install directory (default: ./bin)
# -d Enable debug output
# -v Install specific version (default: latest)
#
# Examples:
# curl -sSfL https://raw.githubusercontent.com/rezmoss/sbomlyze/main/install.sh | sh
# curl -sSfL https://raw.githubusercontent.com/rezmoss/sbomlyze/main/install.sh | sh -s -- -b /usr/local/bin
# curl -sSfL https://raw.githubusercontent.com/rezmoss/sbomlyze/main/install.sh | sudo sh -s -- -b /usr/local/bin
set -e
GITHUB_REPO="rezmoss/sbomlyze"
BINARY_NAME="sbomlyze"
INSTALL_DIR="./bin"
VERSION=""
DEBUG=0
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
log_info() {
printf "${GREEN}[INFO]${NC} %s\n" "$1"
}
log_warn() {
printf "${YELLOW}[WARN]${NC} %s\n" "$1"
}
log_error() {
printf "${RED}[ERROR]${NC} %s\n" "$1" >&2
}
log_debug() {
if [ "$DEBUG" -eq 1 ]; then
printf "[DEBUG] %s\n" "$1" >&2
fi
}
# Parse command line arguments
while getopts "b:dv:h" opt; do
case $opt in
b)
INSTALL_DIR="$OPTARG"
;;
d)
DEBUG=1
;;
v)
VERSION="$OPTARG"
;;
h)
echo "sbomlyze installer"
echo ""
echo "Usage: curl -sSfL https://raw.githubusercontent.com/rezmoss/sbomlyze/main/install.sh | sh -s -- [options]"
echo ""
echo "Options:"
echo " -b Install directory (default: ./bin)"
echo " -d Enable debug output"
echo " -v Install specific version (default: latest)"
echo " -h Show this help message"
echo ""
echo "Examples:"
echo " # Install to ./bin"
echo " curl -sSfL https://raw.githubusercontent.com/rezmoss/sbomlyze/main/install.sh | sh"
echo ""
echo " # Install to /usr/local/bin (requires sudo)"
echo " curl -sSfL https://raw.githubusercontent.com/rezmoss/sbomlyze/main/install.sh | sudo sh -s -- -b /usr/local/bin"
echo ""
echo " # Install specific version"
echo " curl -sSfL https://raw.githubusercontent.com/rezmoss/sbomlyze/main/install.sh | sh -s -- -v 0.3.7"
exit 0
;;
\?)
log_error "Invalid option: -$OPTARG"
exit 1
;;
esac
done
# Detect OS
detect_os() {
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
case "$OS" in
darwin)
OS="Darwin"
;;
linux)
OS="Linux"
;;
mingw*|msys*|cygwin*)
OS="Windows"
;;
*)
log_error "Unsupported operating system: $OS"
exit 1
;;
esac
log_debug "Detected OS: $OS"
echo "$OS"
}
# Detect architecture
detect_arch() {
ARCH=$(uname -m)
case "$ARCH" in
x86_64|amd64)
ARCH="x86_64"
;;
arm64|aarch64)
ARCH="arm64"
;;
i386|i686)
ARCH="i386"
;;
armv6l)
ARCH="armv6"
;;
armv7l)
ARCH="armv7"
;;
*)
log_error "Unsupported architecture: $ARCH"
exit 1
;;
esac
log_debug "Detected architecture: $ARCH"
echo "$ARCH"
}
# Get latest version from GitHub
get_latest_version() {
LATEST=$(curl -sSf "https://api.github.com/repos/${GITHUB_REPO}/releases/latest" | grep '"tag_name":' | sed -E 's/.*"([^"]+)".*/\1/')
if [ -z "$LATEST" ]; then
log_error "Failed to fetch latest version"
exit 1
fi
log_debug "Latest version: $LATEST"
echo "$LATEST"
}
sha256_file() {
if command -v sha256sum >/dev/null 2>&1; then
sha256sum "$1" | awk '{print $1}'
elif command -v shasum >/dev/null 2>&1; then
shasum -a 256 "$1" | awk '{print $1}'
elif command -v openssl >/dev/null 2>&1; then
openssl dgst -sha256 "$1" | awk '{print $NF}'
else
log_error "No SHA256 tool found (tried sha256sum, shasum, and openssl)"
return 1
fi
}
verify_checksum() {
ARCHIVE=$1
CHECKSUMS=$2
EXPECTED=$(awk -v file="$FILENAME" '$2 == file {print $1; exit}' "$CHECKSUMS")
if [ -z "$EXPECTED" ]; then
log_error "No checksum found for ${FILENAME}"
return 1
fi
ACTUAL=$(sha256_file "$ARCHIVE")
if [ "$ACTUAL" != "$EXPECTED" ]; then
log_error "Checksum verification failed for ${FILENAME}"
log_error "Expected: $EXPECTED"
log_error "Actual: $ACTUAL"
return 1
fi
log_info "Checksum verified"
}
verify_provenance() {
ARCHIVE=$1
if ! command -v gh >/dev/null 2>&1; then
log_warn "GitHub CLI not found; provenance verification skipped"
log_warn "SHA256 verification succeeded. Install gh to verify release provenance."
return 0
fi
if ! gh attestation verify --help >/dev/null 2>&1; then
log_warn "Installed GitHub CLI does not support attestation verification"
log_warn "SHA256 verification succeeded. Upgrade gh to verify release provenance."
return 0
fi
log_info "Verifying GitHub build provenance..."
if ! gh attestation verify "$ARCHIVE" \
--repo "$GITHUB_REPO" \
--signer-workflow "$GITHUB_REPO/.github/workflows/release.yml"; then
log_error "Build provenance verification failed for ${FILENAME}"
return 1
fi
log_info "Build provenance verified"
}
# Download and install
install() {
OS=$(detect_os)
ARCH=$(detect_arch)
# Get version
if [ -z "$VERSION" ]; then
VERSION=$(get_latest_version)
else
# Ensure version starts with 'v'
case "$VERSION" in
v*) ;;
*) VERSION="v$VERSION" ;;
esac
fi
# Strip 'v' prefix for filename
VERSION_NUM="${VERSION#v}"
log_info "Installing sbomlyze ${VERSION} for ${OS}/${ARCH}"
# Determine file extension
EXT="tar.gz"
if [ "$OS" = "Windows" ]; then
EXT="zip"
fi
# Build download URL
FILENAME="${BINARY_NAME}_${VERSION_NUM}_${OS}_${ARCH}.${EXT}"
URL="https://github.com/${GITHUB_REPO}/releases/download/${VERSION}/${FILENAME}"
log_debug "Download URL: $URL"
# Create temp directory
TMP_DIR=$(mktemp -d)
trap "rm -rf $TMP_DIR" EXIT
log_info "Downloading ${FILENAME}..."
# Download
HTTP_CODE=$(curl -sSL -w "%{http_code}" -o "${TMP_DIR}/${FILENAME}" "$URL")
if [ "$HTTP_CODE" != "200" ]; then
log_error "Download failed (HTTP $HTTP_CODE)"
log_error "URL: $URL"
log_error ""
log_error "Available releases: https://github.com/${GITHUB_REPO}/releases"
exit 1
fi
CHECKSUMS_URL="https://github.com/${GITHUB_REPO}/releases/download/${VERSION}/checksums.txt"
log_info "Verifying SHA256 checksum..."
curl -sSfL -o "${TMP_DIR}/checksums.txt" "$CHECKSUMS_URL"
verify_checksum "${TMP_DIR}/${FILENAME}" "${TMP_DIR}/checksums.txt"
verify_provenance "${TMP_DIR}/${FILENAME}"
# Extract
log_info "Extracting..."
cd "$TMP_DIR"
if [ "$EXT" = "zip" ]; then
unzip -q "$FILENAME"
else
tar -xzf "$FILENAME"
fi
# Create install directory if needed
mkdir -p "$INSTALL_DIR"
# Install binary
if [ "$OS" = "Windows" ]; then
BINARY="${BINARY_NAME}.exe"
else
BINARY="$BINARY_NAME"
fi
log_info "Installing to ${INSTALL_DIR}/${BINARY}..."
# Move binary
mv "$BINARY" "$INSTALL_DIR/"
chmod +x "$INSTALL_DIR/$BINARY"
# Remove quarantine attribute on macOS
if [ "$OS" = "Darwin" ]; then
xattr -d com.apple.quarantine "$INSTALL_DIR/$BINARY" 2>/dev/null || true
fi
log_info "Successfully installed sbomlyze ${VERSION} to ${INSTALL_DIR}/${BINARY}"
# Check if install dir is in PATH
case ":$PATH:" in
*":$INSTALL_DIR:"*)
;;
*)
log_warn "Installation directory is not in your PATH"
log_warn "Add it with: export PATH=\"\$PATH:$INSTALL_DIR\""
;;
esac
# Verify installation
if [ -x "$INSTALL_DIR/$BINARY" ]; then
log_info "Verifying installation..."
"$INSTALL_DIR/$BINARY" --version
fi
}
# Run installation
install