#!/bin/bash # # ETC Collector — Trial Mode Installer (Linux + macOS) # https://etcsec.com/trial # # Runs ONE anonymous security audit against the EtcSec trial backend and # exits. No service is installed, no config is written to disk, no root is # required. Results expire in 7 days. # # The community binary (Apache 2.0) ships with a `trial` subcommand since # v3.0.20. This script just downloads it to /tmp and execs `etc-collector # trial` with the right env vars. # # Usage: # curl -fsSL https://get.etcsec.com/install-trial.sh | TRIAL_TOKEN=tcol_xxx bash # # Environment variables: # TRIAL_TOKEN (required) Opaque enrollment token from etcsec.com/trial # TRIAL_BASE_URL (optional) Default: https://etcsec.com/v1/trial # TRIAL_VERSION (optional) Default: 3.0.20 (first release with trial mode) # TRIAL_IDLE_TIMEOUT (optional) Minutes before the collector gives up waiting. # Default: 20. set -euo pipefail : "${TRIAL_TOKEN:?TRIAL_TOKEN env var is required. Start a session at https://etcsec.com/trial}" TRIAL_BASE_URL="${TRIAL_BASE_URL:-https://etcsec.com/v1/trial}" TRIAL_VERSION="${TRIAL_VERSION:-3.0.20}" TRIAL_IDLE_TIMEOUT="${TRIAL_IDLE_TIMEOUT:-20m}" if [ "${TRIAL_TOKEN#tcol_}" = "$TRIAL_TOKEN" ]; then echo "Error: TRIAL_TOKEN must start with 'tcol_'. Got: ${TRIAL_TOKEN:0:8}..." >&2 exit 1 fi if [ -t 1 ] && [ -t 2 ]; then GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m' else GREEN=''; YELLOW=''; CYAN=''; NC='' fi OS="$(uname -s | tr '[:upper:]' '[:lower:]')" ARCH="$(uname -m)" case "$ARCH" in x86_64|amd64) ARCH=amd64 ;; aarch64|arm64) ARCH=arm64 ;; *) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;; esac case "$OS" in linux|darwin) ;; *) echo "Unsupported OS: $OS (Linux or macOS required)" >&2; exit 1 ;; esac PLATFORM="${OS}-${ARCH}" TMPDIR="$(mktemp -d -t etcsec-trial.XXXXXX)" trap 'rm -rf "$TMPDIR"' EXIT INT TERM echo -e "${CYAN}▶ EtcSec trial — running a one-shot audit${NC}" echo -e " Platform: ${PLATFORM}" echo -e " Version: ${TRIAL_VERSION}" echo -e " Backend: ${TRIAL_BASE_URL}" echo -e " Idle: ${TRIAL_IDLE_TIMEOUT}" echo "" TARBALL="etc-collector-${TRIAL_VERSION}-${PLATFORM}.tar.gz" DOWNLOAD_URL="https://get.etcsec.com/downloads/${TARBALL}" CHECKSUMS_URL="https://get.etcsec.com/downloads/v${TRIAL_VERSION}/checksums.sha256" echo -e "${YELLOW}↓${NC} Downloading ${TARBALL}..." curl -fsSL -o "${TMPDIR}/${TARBALL}" "${DOWNLOAD_URL}" echo -e "${YELLOW}↓${NC} Verifying checksum..." if curl -fsSL -o "${TMPDIR}/checksums.sha256" "${CHECKSUMS_URL}" 2>/dev/null; then EXPECTED="$(grep " ${TARBALL}$" "${TMPDIR}/checksums.sha256" | awk '{print $1}' || true)" if [ -n "$EXPECTED" ]; then if command -v sha256sum >/dev/null 2>&1; then ACTUAL="$(sha256sum "${TMPDIR}/${TARBALL}" | awk '{print $1}')" else ACTUAL="$(shasum -a 256 "${TMPDIR}/${TARBALL}" | awk '{print $1}')" fi if [ "$ACTUAL" != "$EXPECTED" ]; then echo "Checksum mismatch. Expected $EXPECTED, got $ACTUAL" >&2 exit 2 fi echo " OK" else echo " (checksum not listed for this build — skipping)" fi else echo " (checksums file unavailable — skipping)" fi echo -e "${YELLOW}↓${NC} Extracting..." tar -xzf "${TMPDIR}/${TARBALL}" -C "${TMPDIR}" BIN="" CANDIDATES=( "${TMPDIR}/etc-collector" "${TMPDIR}/bin/etc-collector" "${TMPDIR}/etc-collector-${TRIAL_VERSION}/etc-collector" "${TMPDIR}/etc-collector-${TRIAL_VERSION}-${PLATFORM}/etc-collector" ) for cand in "${CANDIDATES[@]}"; do if [ -f "$cand" ]; then BIN="$cand" break fi done if [ -z "$BIN" ]; then # Release tarballs sometimes ship the binary without the +x bit; don't # filter by permissions — just find it by name. BIN="$(find "${TMPDIR}" -type f -name 'etc-collector' 2>/dev/null | head -n 1 || true)" fi if [ -z "$BIN" ] || [ ! -f "$BIN" ]; then echo "Could not locate etc-collector binary in extracted archive." >&2 exit 3 fi chmod +x "$BIN" echo -e "${GREEN}▶${NC} Starting trial audit (Ctrl-C to stop)..." echo "" # Exec into the binary so signals propagate and the script exits with the # binary's exit code. exec "$BIN" trial \ --token="${TRIAL_TOKEN}" \ --base-url="${TRIAL_BASE_URL}" \ --idle-timeout="${TRIAL_IDLE_TIMEOUT}"