Prechádzať zdrojové kódy

fix(install): make macOS native install rootless (brew + venv permission errors)

    macOS mixed root-only steps (default /opt path, sudo git clone) with steps
    that must not run as root: brew refuses to run as root, and a root-owned
    venv/node_modules can't be managed by the launchd agent. The installer now
    refuses sudo on macOS, defaults to ~/bambuddy, and drops sudo from the
    download/venv/frontend/env/dir steps. A --path under a root-owned parent still
    works via a single elevate-and-chown. Linux (service user + systemd) unchanged.
maziggy 2 mesiacov pred
rodič
commit
ae7674b3c1
1 zmenil súbory, kde vykonal 71 pridanie a 7 odobranie
  1. 71 7
      install/install.sh

+ 71 - 7
install/install.sh

@@ -332,6 +332,26 @@ create_user() {
     log_success "Service user created"
 }
 
+# Ensure a directory exists and is owned by the current user. Used on macOS so
+# the install tree stays user-owned (git/venv/npm never touch a root-owned dir).
+# Only elevates when the target's parent is root-owned (e.g. /opt); a path under
+# $HOME is created without any sudo prompt.
+ensure_user_owned_dir() {
+    local dir="$1"
+
+    if [[ -d "$dir" ]] && [[ -w "$dir" ]]; then
+        return
+    fi
+
+    if mkdir -p "$dir" 2>/dev/null; then
+        return
+    fi
+
+    log_info "Creating $dir (requires your password)..."
+    sudo mkdir -p "$dir"
+    sudo chown "$(id -un):$(id -gn)" "$dir"
+}
+
 download_bambuddy() {
     log_info "Downloading BamBuddy..."
 
@@ -343,7 +363,23 @@ download_bambuddy() {
         exit 1
     fi
 
-    if [[ -d "$INSTALL_PATH/.git" ]]; then
+    if [[ "$OS_TYPE" == "macos" ]]; then
+        # macOS has no service user — the whole install runs as the current user.
+        # Create the target user-owned (elevating only if its parent is root-owned,
+        # e.g. /opt), then clone/update without sudo so the venv/frontend the user
+        # builds next aren't fighting a root-owned tree.
+        ensure_user_owned_dir "$INSTALL_PATH"
+        if [[ -d "$INSTALL_PATH/.git" ]]; then
+            log_info "Existing installation found, updating..."
+            git config --global --add safe.directory "$INSTALL_PATH" 2>/dev/null || true
+            cd "$INSTALL_PATH"
+            git fetch origin
+            git checkout "$BRANCH" 2>/dev/null || git checkout -b "$BRANCH" "origin/$BRANCH"
+            git reset --hard "origin/$BRANCH"
+        else
+            git clone --branch "$BRANCH" https://github.com/maziggy/bambuddy.git "$INSTALL_PATH"
+        fi
+    elif [[ -d "$INSTALL_PATH/.git" ]]; then
         log_info "Existing installation found, updating..."
         # Add safe.directory to avoid "dubious ownership" error when running as root
         git config --global --add safe.directory "$INSTALL_PATH" 2>/dev/null || true
@@ -472,9 +508,12 @@ build_frontend() {
 create_directories() {
     log_info "Creating data directories..."
 
-    sudo mkdir -p "$DATA_DIR" "$LOG_DIR"
-
-    if [[ "$OS_TYPE" != "macos" ]]; then
+    if [[ "$OS_TYPE" == "macos" ]]; then
+        # Rootless: DATA_DIR/LOG_DIR default under the user-owned install path.
+        ensure_user_owned_dir "$DATA_DIR"
+        ensure_user_owned_dir "$LOG_DIR"
+    else
+        sudo mkdir -p "$DATA_DIR" "$LOG_DIR"
         sudo chown -R "$SERVICE_USER:$SERVICE_USER" "$DATA_DIR" "$LOG_DIR"
     fi
 
@@ -503,11 +542,15 @@ LOG_LEVEL=$LOG_LEVEL
 LOG_TO_FILE=true
 EOF
 
-    sudo mv /tmp/bambuddy.env "$env_file"
-    if [[ "$OS_TYPE" != "macos" ]]; then
+    if [[ "$OS_TYPE" == "macos" ]]; then
+        # Rootless: install path is user-owned, so write it directly.
+        mv /tmp/bambuddy.env "$env_file"
+        chmod 600 "$env_file"
+    else
+        sudo mv /tmp/bambuddy.env "$env_file"
         sudo chown "$SERVICE_USER:$SERVICE_USER" "$env_file"
+        sudo chmod 600 "$env_file"
     fi
-    sudo chmod 600 "$env_file"
 
     log_success "Environment file created at $env_file"
 }
@@ -845,6 +888,27 @@ main() {
     detect_os
     log_success "Detected: $OS_TYPE (package manager: $PKG_MANAGER)"
 
+    # macOS must run rootless. Homebrew hard-refuses to run as root, and a venv
+    # / node_modules created by root can't be managed by the launchd agent (which
+    # runs as the user). Bail early with an actionable message instead of dying
+    # halfway through on "brew: running as root is not supported".
+    if [[ "$OS_TYPE" == "macos" ]]; then
+        if [[ "$EUID" -eq 0 ]]; then
+            log_error "Don't run the macOS installer with sudo."
+            log_info  "Homebrew, the Python venv, and the launchd agent must all be created as your"
+            log_info  "normal user. Re-run without sudo (the script elevates only when it truly needs to):"
+            echo ""
+            echo "    ./install.sh"
+            echo ""
+            exit 1
+        fi
+        # /opt requires sudo to create and would leave a root-owned tree; default
+        # macOS installs to a user-owned location so the whole flow stays rootless.
+        if [[ "$DEFAULT_INSTALL_PATH" == "/opt/bambuddy" ]]; then
+            DEFAULT_INSTALL_PATH="$HOME/bambuddy"
+        fi
+    fi
+
     # Check/install Python
     if ! detect_python; then
         log_info "Python 3.10+ not found, will install..."