#!/usr/bin/env bash set -euo pipefail SERVER='https://staging.demo.stratacos.net' ENROLLMENT_TOKEN='GFmpMiCXEWIddoRAfHC2Aw3agLCc9vZnJxaIYxOGzGQ' MODE='permanent' NAME='' PYTHON="python3" INSTALL_DIR="/usr/local/lib/stratacos-agent" START_NOW=0 LABEL="com.stratacos.security.agent" PLIST="/Library/LaunchDaemons/${LABEL}.plist" usage() { cat <<'EOF' Usage: sudo ./install-agent-macos.sh --server URL --enrollment-token TOKEN [options] Options: --mode permanent|ephemeral Permanent launch daemon or temporary state (default: permanent) --name NAME Friendly agent name --python PATH Python executable (default: python3) --install-dir PATH Agent code directory (default: /usr/local/lib/stratacos-agent) --start-now Start the agent immediately after installation EOF } while [[ $# -gt 0 ]]; do case "$1" in --server) SERVER="${2:?Missing value for --server}"; shift 2 ;; --enrollment-token) ENROLLMENT_TOKEN="${2:?Missing value for --enrollment-token}"; shift 2 ;; --mode) MODE="${2:?Missing value for --mode}"; shift 2 ;; --name) NAME="${2:?Missing value for --name}"; shift 2 ;; --python) PYTHON="${2:?Missing value for --python}"; shift 2 ;; --install-dir) INSTALL_DIR="${2:?Missing value for --install-dir}"; shift 2 ;; --start-now) START_NOW=1; shift ;; -h|--help) usage; exit 0 ;; *) echo "Unknown option: $1" >&2; usage; exit 2 ;; esac done if [[ -z "$SERVER" ]]; then read -r -p "Dashboard server URL: " SERVER fi if [[ -z "$ENROLLMENT_TOKEN" ]]; then read -r -s -p "Enrollment token: " ENROLLMENT_TOKEN printf '\n' fi [[ -n "$SERVER" && -n "$ENROLLMENT_TOKEN" ]] || { usage; exit 2; } [[ "$MODE" == "permanent" || "$MODE" == "ephemeral" ]] || { echo "--mode must be permanent or ephemeral" >&2; exit 2; } [[ "$(id -u)" -eq 0 ]] || { echo "Run this installer with sudo/root privileges." >&2; exit 1; } command -v "$PYTHON" >/dev/null || { echo "Python executable not found: $PYTHON" >&2; exit 1; } SOURCE_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" if [[ "$MODE" == "permanent" ]]; then DATA_DIR="/Library/Application Support/Stratacos/Agent" else DATA_DIR="$(mktemp -d /tmp/stratacos-agent.XXXXXX)" fi install -d -m 0755 "$INSTALL_DIR" install -d -m 0700 "$DATA_DIR" rm -rf "$INSTALL_DIR/pqc_dashboard" install -m 0755 "$SOURCE_ROOT/agent.py" "$INSTALL_DIR/agent.py" cp -R "$SOURCE_ROOT/pqc_dashboard" "$INSTALL_DIR/pqc_dashboard" chmod -R a+rX "$INSTALL_DIR/pqc_dashboard" CONFIG_PATH="$DATA_DIR/agent-config.json" STATE_PATH="$DATA_DIR/agent-state.json" SERVER="$SERVER" ENROLLMENT_TOKEN="$ENROLLMENT_TOKEN" NAME="$NAME" DATA_DIR="$DATA_DIR" STATE_PATH="$STATE_PATH" CONFIG_PATH="$CONFIG_PATH" "$PYTHON" - <<'PY' import json, os config = { "server": os.environ["SERVER"].rstrip("/"), "enrollmentToken": os.environ["ENROLLMENT_TOKEN"], "name": os.environ.get("NAME", ""), "dataDir": os.environ["DATA_DIR"], "stateFile": os.environ["STATE_PATH"], "pollingIntervalSeconds": 3, } with open(os.environ["CONFIG_PATH"], "w", encoding="utf-8") as handle: json.dump(config, handle, indent=2) PY chmod 0600 "$CONFIG_PATH" if [[ "$MODE" == "permanent" ]]; then cat > "$PLIST" < Label$LABEL ProgramArguments $PYTHON -B $INSTALL_DIR/agent.py --config $CONFIG_PATH WorkingDirectory$INSTALL_DIR RunAtLoad KeepAlive ProcessTypeBackground StandardOutPath/var/log/stratacos-agent.log StandardErrorPath/var/log/stratacos-agent.err.log EOF chmod 0644 "$PLIST" launchctl bootout system "$PLIST" >/dev/null 2>&1 || true launchctl bootstrap system "$PLIST" [[ "$START_NOW" -eq 1 ]] && launchctl kickstart -k "system/$LABEL" echo "Installed permanent Stratacos agent launch daemon." echo "State: $STATE_PATH" else echo "Prepared ephemeral Stratacos agent. It has no startup daemon and uses temporary state." echo "Run once with: $PYTHON -B $INSTALL_DIR/agent.py --config $CONFIG_PATH" [[ "$START_NOW" -eq 1 ]] && exec "$PYTHON" -B "$INSTALL_DIR/agent.py" --config "$CONFIG_PATH" fi