#!/bin/sh set -e # Quint Agent install script # Usage: curl -fsSL https://get.quintai.dev | sudo sh -s -- --token # --------------------------------------------------------------------------- # Banner # --------------------------------------------------------------------------- cat <<'BANNER' ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⣸⠀⠀⠀⠀⣠⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣀⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢠⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⢀⣴⠛⡄⠀⣠⠞⠁⠀⠀⠀⠀⠀⠀⣠⣾⠟⠛⠛⠛⠿⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠈⠉⠀⠀⠀⠀⠀⢀⣀⠀⠀⠀⠀⣿⡇⠀⠀⠀⠀⠀ ⠀⠀⠀⢀⣀⣤⣶⣋⣁⣀⣱⣞⣁⣀⣀⣀⡀⠀⠀⠀⢠⣿⠃⠀⠀⠀⠀⠀⢹⣷⠀⢸⣿⠀⠀⠀⠀⣿⠀⠀⢸⣿⠀⠀⣿⡧⠚⠛⠻⣿⡆⠀⠛⣿⡟⠛⠃⠀⠀⠀ ⠀⠀⠀⠈⠉⠉⠉⢉⣽⠟⡉⠉⣩⠿⠛⠉⠁⠀⠀⠀⢸⣿⠀⠀⠀⠀⠀⠀⢸⣿⠀⢸⣿⠀⠀⠀⠀⣿⠀⠀⢸⣿⠀⠀⣿⡇⠀⠀⠀⣿⡇⠀⠀⣿⡇⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⢀⣴⠟⠁⠀⣧⡞⠁⠀⠀⠀⠀⠀⠀⠀⠀⢻⣧⣀⠀⠀⢀⣠⣾⠏⠀⠸⣿⡀⠀⢀⡰⣿⠀⠀⢸⣿⠀⠀⣿⡇⠀⠀⠀⣿⡇⠀⠀⣿⡇⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠛⠁⠀⠀⠀⡟⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠛⠛⠛⠛⢻⣧⠀⠀⠀⠙⠛⠛⠋⠀⠛⠀⠀⠘⠛⠀⠀⠛⠃⠀⠀⠀⠛⠃⠀⠀⠘⠛⠛⠃⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠉⠁⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ Firewall for AI Agents ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ BANNER # --------------------------------------------------------------------------- # Check root # --------------------------------------------------------------------------- if [ "$(id -u)" -ne 0 ]; then echo "Error: this installer must be run as root." echo "" echo " curl -fsSL https://get.quintai.dev | sudo sh -s -- --token " echo "" exit 1 fi # --------------------------------------------------------------------------- # Defaults # --------------------------------------------------------------------------- TOKEN="" API_URL="https://api.quintai.dev" # --------------------------------------------------------------------------- # Parse arguments # --------------------------------------------------------------------------- while [ $# -gt 0 ]; do case "$1" in --token) TOKEN="$2" shift 2 ;; --api-url) API_URL="$2" shift 2 ;; *) echo "Unknown option: $1" shift ;; esac done if [ -z "$TOKEN" ]; then echo "Usage: curl -fsSL https://get.quintai.dev | sudo sh -s -- --token [--api-url ]" echo "" echo "Options:" echo " --token (required) Agent enrollment token" echo " --api-url API endpoint (default: https://api.quintai.dev)" exit 1 fi # --------------------------------------------------------------------------- # Detect OS and architecture # --------------------------------------------------------------------------- OS="$(uname -s | tr '[:upper:]' '[:lower:]')" ARCH="$(uname -m)" case "$ARCH" in x86_64) ARCH="amd64" ;; aarch64) ARCH="arm64" ;; arm64) ARCH="arm64" ;; *) echo "Error: unsupported architecture: $ARCH" exit 1 ;; esac echo "Detected OS=${OS} ARCH=${ARCH}" # --------------------------------------------------------------------------- # Fetch latest version from GitHub releases API # --------------------------------------------------------------------------- FALLBACK_VERSION="1.0.0" VERSION="$(curl -fsSL https://api.github.com/repos/Quint-Security/quint-proxy/releases/latest 2>/dev/null \ | grep tag_name | cut -d'"' -f4 | sed 's/^v//' || true)" if [ -z "$VERSION" ]; then echo "Warning: could not reach GitHub releases API, falling back to v${FALLBACK_VERSION}" VERSION="$FALLBACK_VERSION" fi echo "Installing Quint Agent v${VERSION} ..." # --------------------------------------------------------------------------- # Download binary (tarball format) # --------------------------------------------------------------------------- # Asset naming matches Makefile output: quint-proxy-{os}-{arch}.tar.gz TARBALL_URL="https://github.com/Quint-Security/quint-proxy/releases/download/v${VERSION}/quint-proxy-${OS}-${ARCH}.tar.gz" CHECKSUM_URL="https://github.com/Quint-Security/quint-proxy/releases/download/v${VERSION}/quint-proxy-${OS}-${ARCH}.tar.gz.sha256" echo "Downloading from ${TARBALL_URL} ..." if ! curl -fsSL -o /tmp/quint-download.tar.gz "$TARBALL_URL"; then echo "Error: failed to download quint v${VERSION} from ${TARBALL_URL}" exit 1 fi # Verify SHA256 checksum echo "Verifying checksum ..." if curl -fsSL -o /tmp/quint-download.sha256 "$CHECKSUM_URL" 2>/dev/null; then EXPECTED="$(awk '{print $1}' /tmp/quint-download.sha256)" if command -v shasum >/dev/null 2>&1; then ACTUAL="$(shasum -a 256 /tmp/quint-download.tar.gz | awk '{print $1}')" elif command -v sha256sum >/dev/null 2>&1; then ACTUAL="$(sha256sum /tmp/quint-download.tar.gz | awk '{print $1}')" else echo "Warning: no SHA256 tool found, skipping checksum verification" ACTUAL="$EXPECTED" fi if [ "$EXPECTED" != "$ACTUAL" ]; then echo "Error: checksum mismatch!" echo " Expected: $EXPECTED" echo " Got: $ACTUAL" rm -f /tmp/quint-download.tar.gz /tmp/quint-download.sha256 exit 1 fi echo "Checksum verified." rm -f /tmp/quint-download.sha256 else echo "Warning: could not download checksum file, skipping verification" fi tar xzf /tmp/quint-download.tar.gz -C /tmp # Binary in tarball is named quint-proxy; install as quint if [ -f /tmp/quint-proxy ]; then mv /tmp/quint-proxy /usr/local/bin/quint elif [ -f /tmp/quint ]; then mv /tmp/quint /usr/local/bin/quint else echo "Error: could not find quint binary in tarball" rm -f /tmp/quint-download.tar.gz exit 1 fi chmod +x /usr/local/bin/quint rm -f /tmp/quint-download.tar.gz echo "Installed binary to /usr/local/bin/quint" # Also install to homebrew path if it exists (avoid PATH shadowing on macOS) if [ -d "/opt/homebrew/bin" ]; then cp /usr/local/bin/quint /opt/homebrew/bin/quint 2>/dev/null || true echo "Copied binary to /opt/homebrew/bin/quint" fi # --------------------------------------------------------------------------- # Check for dylib (macOS local monitoring) # --------------------------------------------------------------------------- DYLIB_PATH="/usr/local/lib/quint_monitor.dylib" if [ "$OS" = "darwin" ] && [ ! -f "$DYLIB_PATH" ]; then echo "Note: ${DYLIB_PATH} not found. Local monitoring will be unavailable" echo " until the dylib is installed. Run 'quint setup' again after" echo " installing it to enable local monitoring." fi # --------------------------------------------------------------------------- # Delegate to quint setup (handles everything else) # --------------------------------------------------------------------------- # quint setup handles: # - CA certificate generation and system trust # - LaunchAgent for GUI app env vars # - PAC file generation and system proxy configuration # - User config directory (~/.quint/) and CA copy # - env.sh / env.fish with agent wrappers # - Shell profile injection (.zshrc, .bashrc, fish) # - /etc/quint/config.yaml with all required fields # - LaunchDaemon / systemd service install and start # - Daemon readiness check echo "" echo "Running quint setup ..." echo "" SETUP_ARGS="--token $TOKEN --api-url $API_URL" /usr/local/bin/quint setup $SETUP_ARGS # --------------------------------------------------------------------------- # Verify # --------------------------------------------------------------------------- echo "" if /usr/local/bin/quint version >/dev/null 2>&1; then INSTALLED_VERSION="$(/usr/local/bin/quint version 2>/dev/null || echo "v${VERSION}")" echo "Quint Agent installed successfully! (${INSTALLED_VERSION})" echo "" echo " Binary: /usr/local/bin/quint" echo " Proxy: eval \$(quint env --proxy) or open a new terminal" echo " Logs: /var/log/quint/agent.log" echo "" echo " Every new terminal session will auto-route AI agent traffic" echo " through Quint. To use immediately: eval \$(quint env --proxy)" else echo "Warning: 'quint version' check failed, but the binary was installed." echo "Check logs at /var/log/quint/agent.err for details." exit 1 fi