#!/bin/sh set -eu # Socket Patch installer # Usage: # curl -fsSL https://install.socket.dev/patch | sh # # install.socket.dev/patch serves a byte-for-byte copy of this file; the URL # above and the raw.githubusercontent.com path to this script are # interchangeable. See docs/installer-hosting.md for how the copy is published. # # Override the version that gets installed by exporting SOCKET_PATCH_VERSION: # curl -fsSL https://install.socket.dev/patch | SOCKET_PATCH_VERSION=3.0.0 sh # # Override where the archives come from with SOCKET_PATCH_BASE_URL — a releases # base that answers GitHub's two asset paths, `/latest/download/` # and `/download/v/`. Use it to install without reaching # github.com at all: # # … | SOCKET_PATCH_BASE_URL=https://install.socket.dev/patch/SocketDev/socket-patch/releases sh # # install.socket.dev relays those exact paths from the GitHub release, which is # why one template covers both origins. Whichever origin is used, the archive is # still verified against the SHA256SUMS fetched from that same origin. # # Override where the binary is installed with SOCKET_PATCH_INSTALL_DIR. REPO="SocketDev/socket-patch" BINARY="socket-patch" VERSION="${SOCKET_PATCH_VERSION:-latest}" # Releases base. Default is GitHub; see the SOCKET_PATCH_BASE_URL note above for # installing through install.socket.dev instead. Trailing slashes are trimmed so # a base with one does not produce `//download`. RELEASES_BASE="${SOCKET_PATCH_BASE_URL:-https://github.com/${REPO}/releases}" while :; do case "$RELEASES_BASE" in */) RELEASES_BASE="${RELEASES_BASE%/}" ;; *) break ;; esac done # Detect platform OS="$(uname -s)" ARCH="$(uname -m)" case "$OS" in Darwin) case "$ARCH" in arm64) TARGET="aarch64-apple-darwin" ;; x86_64) TARGET="x86_64-apple-darwin" ;; *) echo "Error: unsupported architecture: $ARCH" >&2; exit 1 ;; esac ;; Linux) # Detect libc: musl or glibc detect_libc() { if ldd --version 2>&1 | grep -qi musl; then echo "musl" return fi # `[ -e ]` cannot take a glob (SC2144): with several matches it is a # syntax error, with none it tests the literal pattern. Loop instead. for loader in /lib/ld-musl-*.so.1; do if [ -e "$loader" ]; then echo "musl" return fi done echo "gnu" } LIBC="$(detect_libc)" case "$ARCH" in x86_64) if [ "$LIBC" = "musl" ]; then TARGET="x86_64-unknown-linux-musl" else TARGET="x86_64-unknown-linux-gnu"; fi ;; aarch64) if [ "$LIBC" = "musl" ]; then TARGET="aarch64-unknown-linux-musl" else TARGET="aarch64-unknown-linux-gnu"; fi ;; armv7l) if [ "$LIBC" = "musl" ]; then TARGET="arm-unknown-linux-musleabihf" else TARGET="arm-unknown-linux-gnueabihf"; fi ;; i686) if [ "$LIBC" = "musl" ]; then TARGET="i686-unknown-linux-musl" else TARGET="i686-unknown-linux-gnu"; fi ;; *) echo "Error: unsupported architecture: $ARCH" >&2; exit 1 ;; esac ;; *) echo "Error: unsupported OS: $OS" >&2 exit 1 ;; esac # Detect downloader if command -v curl >/dev/null 2>&1; then download() { curl -fsSL -o "$1" "$2"; } elif command -v wget >/dev/null 2>&1; then download() { wget -qO "$1" "$2"; } else echo "Error: curl or wget is required" >&2 exit 1 fi # Locate a SHA-256 implementation. shasum and sha256sum cover macOS + Linux. if command -v shasum >/dev/null 2>&1; then sha256() { shasum -a 256 "$1" | awk '{print $1}'; } elif command -v sha256sum >/dev/null 2>&1; then sha256() { sha256sum "$1" | awk '{print $1}'; } else echo "Error: shasum or sha256sum is required for integrity verification" >&2 exit 1 fi # Pick install directory. An explicit SOCKET_PATCH_INSTALL_DIR wins over both # defaults — needed for unprivileged installs into a toolchain-managed prefix, # and for testing the script without writing to a system path. if [ -n "${SOCKET_PATCH_INSTALL_DIR:-}" ]; then INSTALL_DIR="$SOCKET_PATCH_INSTALL_DIR" mkdir -p "$INSTALL_DIR" elif [ -w /usr/local/bin ]; then INSTALL_DIR="/usr/local/bin" else INSTALL_DIR="${HOME}/.local/bin" mkdir -p "$INSTALL_DIR" fi # Create temp dir with cleanup TMPDIR="$(mktemp -d)" trap 'rm -rf "$TMPDIR"' EXIT # Pick the release path. "latest" is resolved by the origin (GitHub redirects; # install.socket.dev resolves it against the upstream release), so the script # never has to know the version number. Tagged versions are served from # /download/v/. if [ "$VERSION" = "latest" ]; then BASE_URL="${RELEASES_BASE}/latest/download" else BASE_URL="${RELEASES_BASE}/download/v${VERSION#v}" fi ARCHIVE="${BINARY}-${TARGET}.tar.gz" ARCHIVE_URL="${BASE_URL}/${ARCHIVE}" SHA_URL="${BASE_URL}/SHA256SUMS" echo "Downloading ${ARCHIVE}..." download "${TMPDIR}/${ARCHIVE}" "${ARCHIVE_URL}" echo "Downloading SHA256SUMS..." download "${TMPDIR}/SHA256SUMS" "${SHA_URL}" # Verify the tarball matches the published checksum before extraction. The # SHA256SUMS file follows the standard " " format, one line # per release artifact. EXPECTED="$(awk -v a="${ARCHIVE}" '$2 == a || $2 == "*"a {print $1; exit}' "${TMPDIR}/SHA256SUMS")" if [ -z "${EXPECTED}" ]; then echo "Error: no checksum entry for ${ARCHIVE} in SHA256SUMS" >&2 exit 1 fi ACTUAL="$(sha256 "${TMPDIR}/${ARCHIVE}")" if [ "${EXPECTED}" != "${ACTUAL}" ]; then echo "Error: checksum mismatch for ${ARCHIVE}" >&2 echo " expected: ${EXPECTED}" >&2 echo " actual: ${ACTUAL}" >&2 exit 1 fi tar xzf "${TMPDIR}/${ARCHIVE}" -C "${TMPDIR}" # Install install -m 755 "${TMPDIR}/${BINARY}" "${INSTALL_DIR}/${BINARY}" echo "Installed ${BINARY} to ${INSTALL_DIR}/${BINARY}" # Print version "${INSTALL_DIR}/${BINARY}" --version 2>/dev/null || true # Warn if not on PATH case ":${PATH}:" in *":${INSTALL_DIR}:"*) ;; *) echo "" echo "Warning: ${INSTALL_DIR} is not on your PATH." echo "Add it with:" echo " export PATH=\"${INSTALL_DIR}:\$PATH\"" ;; esac