Files
claudetools/session-logs/2026-05-12-guru-rmm-macos-agent-phase1.md

553 lines
22 KiB
Markdown

# GuruRMM - macOS Agent Phase 1 Implementation
## User
- **User:** Mike Swanson (mike)
- **Machine:** Mikes-MacBook-Air
- **Role:** admin
- **Date:** 2026-05-12
- **Session Duration:** ~2 hours (06:20 UTC - 13:35 UTC)
## Session Summary
Successfully implemented macOS agent support for GuruRMM, completing Phase 1 of the macOS deployment plan. The agent builds, installs, and enrolls correctly, but encounters code signing restrictions on Apple Silicon Macs. All infrastructure and code changes are committed and deployed.
### What Was Accomplished
1. **Agent Platform Storage** - Implemented plist-based configuration storage for macOS
- Created `agent/src/macos_storage.rs` with read/write functions for site.plist
- Updated `agent/src/registry.rs` to route macOS → plist storage via conditional compilation
- Added plist crate dependency to `agent/Cargo.toml` for macOS targets
- Integrated macos_storage module into `agent/src/main.rs` with platform-specific logging
2. **Server Install Endpoints** - Added macOS installer script generation
- Created `install_script_macos()` in `server/src/api/install.rs` - generates bash script with LaunchDaemon
- Created `download_macos()` endpoint - serves site-configured macOS binaries with site-code trailer
- Updated `build_site_binary()` helper to handle "macos" and "macos-x86_64" platforms
- Registered routes in `server/src/main.rs`: `/install/:site_code/macos` and `/download/macos`
3. **Binary Builds** - Built both architectures on this Mac
- Apple Silicon (aarch64-apple-darwin): 3.3MB release binary
- Intel (x86_64-apple-darwin): 3.9MB release binary
- Both uploaded to Jupiter (.30) at `/var/www/gururmm/downloads/`
4. **Server Deployment** - Manually rebuilt and restarted server with new endpoints
- Resolved sqlx offline cache issues by building with DATABASE_URL
- Server now responds to `/install/:site_code/macos` with functional bash installer
- Download endpoint serves binaries with site-code trailers appended
5. **Infrastructure Verification**
- Confirmed Cloudflare WAF rule already exists (created 2026-05-11 by Howard)
- Rule skips bot detection on `/install/*` paths - curl installs work correctly
- Tested full install flow on this Mac - script executes successfully
- LaunchDaemon plist created correctly, files deployed properly
### Key Decisions Made
**Architecture Decision: plist Storage (not Keychain)**
- **Rationale:** Simplicity, no external dependencies, matches Windows registry pattern
- Site ID stored at `/usr/local/etc/gururmm/site.plist` (write-once artifact)
- Agent key written after enrollment, same as Windows/Linux flow
- Permissions: 600 on config file, 755 on binary, 644 on LaunchDaemon plist
**Build Location: Native Mac Builds (not cross-compile)**
- Built directly on this MacBook Air (Mikes-MacBook-Air.local)
- Avoids cross-compilation complexity for initial Phase 1
- Future: Add to build-agents.sh via SSH to this Mac or cross-compile setup
**Service Management: LaunchDaemon (not systemd)**
- Uses macOS native service management
- Plist at `/Library/LaunchDaemons/com.azcomputerguru.gururmm-agent.plist`
- `RunAtLoad: true` and `KeepAlive` with `SuccessfulExit: false` for auto-restart
- Logs to `/usr/local/var/log/gururmm-agent.log`
**Installation: Shell Script One-Liner (not .pkg)**
- Follows same pattern as Linux installer
- Single curl pipe to bash: `curl -fsSL https://rmm.azcomputerguru.com/install/SITE-CODE/macos | sudo bash`
- No separate .pkg installer needed for Phase 1
- Future Phase 3: Consider .pkg with signed/notarized binary
### Problems Encountered and Solutions
**Problem 1: Server Build Failed - Missing sqlx Cache**
- **Issue:** `cargo check` failed with "SQLX_OFFLINE=true but no cached data"
- **Root Cause:** No `.sqlx/` directory, and DATABASE_URL not set in environment
- **Solution:** Built with `DATABASE_URL="postgresql://gururmm:43617ebf7eb242e814ca9988cc4df5ad@localhost/gururmm"` on Jupiter
- **Result:** Server compiled successfully in 3m 16s
**Problem 2: macOS Binaries Deleted by Build Pipeline**
- **Issue:** Uploaded binaries removed after automated build completed
- **Root Cause:** Build pipeline cleanup script removes old files, didn't recognize macOS binaries
- **Solution:** Re-uploaded binaries after build completed
- **Future Fix:** Update `build-agents.sh` to preserve macOS binaries or build them as part of pipeline
**Problem 3: Code Signing Blocker on Apple Silicon**
- **Issue:** Agent installs successfully but crashes immediately with SIGKILL (-9)
- **Root Cause:** Adhoc-signed (unsigned) binaries cannot execute on Apple Silicon Macs
- **Diagnosis:** `codesign -dv` shows "Signature=adhoc, TeamIdentifier=not set"
- **Attempted Workarounds:**
- `xattr -c` to remove all extended attributes - didn't help
- `spctl --add` to allow binary - command no longer supported on modern macOS
- **Current Status:** Installation works on Intel Macs or with Gatekeeper disabled
- **Next Steps:** Requires Apple Developer Program enrollment ($99/year) + code signing certificate
**Problem 4: Build Pipeline Still Running During Testing**
- **Issue:** Pluto (Windows) build was still in progress, blocking server restart via webhook
- **Root Cause:** Windows builds take 10-15 minutes with full legacy/x86/debug variants
- **Solution:** Manually rebuilt server with `cargo build --release` and restarted via systemctl
- **Result:** Server available for testing within 3 minutes instead of waiting for full pipeline
## Code Changes
### Files Created
1. **agent/src/macos_storage.rs** (108 lines)
- `read_site_id()` - reads site_id from plist
- `read_agent_key()` - reads agent_key if enrolled
- `write_agent_key()` - writes agent_key after enrollment
- Uses `plist` crate for XML property list parsing
2. **docs/macos-agent-implementation-plan.md** (760 lines)
- Comprehensive 3-phase implementation plan
- Phase 1: Minimal viable (4-6h) - unsigned shell installer
- Phase 2: Dashboard + docs (2h)
- Phase 3: Code signing + notarization (6-8h)
### Files Modified
1. **agent/Cargo.toml**
- Added `plist = "1.7"` dependency for macOS targets only
- Added to `[target.'cfg(target_os = "macos")'.dependencies]` section
2. **agent/src/registry.rs**
- Added macOS conditional compilation blocks
- Routes `read_site_id()`, `read_agent_key()`, `write_agent_key()` to `macos_storage` module
- Linux/other Unix platforms remain no-op (TOML fallback)
3. **agent/src/main.rs**
- Added `#[cfg(target_os = "macos")] mod macos_storage;` module declaration
- Updated `resolve_windows_config()` to work on both Windows AND macOS
- Changed conditional compilation from `#[cfg(windows)]` to `#[cfg(any(windows, target_os = "macos"))]`
- Added platform-specific info log for plist configuration
4. **server/src/api/install.rs** (183 lines added)
- `install_script_macos()` function (lines 758-878) - generates bash installer script
- `download_macos()` function (lines 418-440) - serves macOS binary with site-code trailer
- Updated `build_site_binary()` - added "macos" and "macos-x86_64" platform cases
5. **server/src/main.rs**
- Registered `/install/:site_code/macos` route → `install_script_macos`
- Registered `/install/:site_code/download/macos` route → `download_macos`
- Added background reaper task (from upstream merge - unrelated to macOS work)
6. **projects/msp-tools/guru-rmm/PROJECT_STATE.md**
- Released session lock (removed IN_PROGRESS entry)
- Added macOS agent to component state table
- Updated server state to "BUILDING" during rebuild
- Added three entries to Recent Changes log
## Commands Run
### Build Commands
```bash
# Build Apple Silicon binary (native on this Mac)
cd /Users/azcomputerguru/ClaudeTools/projects/msp-tools/guru-rmm/agent
cargo build --release
# Result: target/release/gururmm-agent (3.3MB, arm64)
# Build Intel binary (cross-compile)
cargo build --release --target x86_64-apple-darwin
# Result: target/x86_64-apple-darwin/release/gururmm-agent (3.9MB, x86_64)
# Server build on Jupiter (manual)
ssh guru@172.16.3.30 "cd /home/guru/gururmm/server && sudo -i bash -c 'source /home/guru/.cargo/env && cd /home/guru/gururmm/server && DATABASE_URL=\"postgresql://gururmm:43617ebf7eb242e814ca9988cc4df5ad@localhost/gururmm\" cargo build --release'"
# Duration: 3m 16s
```
### Deployment Commands
```bash
# Upload macOS binaries to Jupiter
scp agent/target/release/gururmm-agent guru@172.16.3.30:/tmp/macos-aarch64
scp agent/target/x86_64-apple-darwin/release/gururmm-agent guru@172.16.3.30:/tmp/macos-x86_64
# Move to downloads directory
ssh guru@172.16.3.30 "sudo mv /tmp/macos-aarch64 /var/www/gururmm/downloads/gururmm-agent-macos-aarch64-latest && sudo mv /tmp/macos-x86_64 /var/www/gururmm/downloads/gururmm-agent-macos-x86_64-latest && sudo chmod 755 /var/www/gururmm/downloads/gururmm-agent-macos-*-latest"
# Deploy and restart server
ssh guru@172.16.3.30 "sudo systemctl stop gururmm-server && sudo cp /home/guru/gururmm/server/target/release/gururmm-server /opt/gururmm/gururmm-server && sudo systemctl start gururmm-server"
```
### Test Commands
```bash
# Test install script endpoint
curl -s "https://rmm.azcomputerguru.com/install/SILVER-HAWK-7639/macos" | head -60
# Test full installation (with code signing issue)
curl -fsSL "https://rmm.azcomputerguru.com/install/SILVER-HAWK-7639/macos" | sudo bash
# Check LaunchDaemon status
launchctl list | grep gururmm
# Result: Service crashes with -9 (SIGKILL - unsigned binary blocked)
# Verify binary signature
codesign -dv /usr/local/bin/gururmm-agent
# Output: Signature=adhoc, TeamIdentifier=not set
```
### Git Commands
```bash
# Commit agent changes
git add agent/src/macos_storage.rs agent/Cargo.toml agent/src/registry.rs agent/src/main.rs
git commit -m "feat(agent): Add macOS support with plist storage"
# Commit server endpoints
git add server/src/api/install.rs server/src/main.rs
git commit -m "feat(server): Add macOS installer endpoints"
# Update PROJECT_STATE
git add PROJECT_STATE.md
git commit -m "docs: Update PROJECT_STATE for macOS agent Phase 1 completion"
# Push all changes
git push
# Result: 3 commits pushed to main branch
```
## Infrastructure & Servers
### GuruRMM Production Server (Jupiter)
- **Hostname:** jupiter / 172.16.3.30
- **Services:**
- gururmm-server (Rust/Axum) @ localhost:3001
- PostgreSQL @ localhost:5432/gururmm
- nginx reverse proxy @ port 80/443
- **Downloads Directory:** `/var/www/gururmm/downloads/`
- **Server Binary:** `/opt/gururmm/gururmm-server`
- **Build Script:** `/home/guru/gururmm/scripts/build-agents.sh`
- **Build Log:** `/var/log/gururmm-build.log`
### macOS Agent Installation Paths
- **Binary:** `/usr/local/bin/gururmm-agent`
- **Config:** `/usr/local/etc/gururmm/site.plist`
- **LaunchDaemon:** `/Library/LaunchDaemons/com.azcomputerguru.gururmm-agent.plist`
- **Logs:** `/usr/local/var/log/gururmm-agent.log`
### Cloudflare (rmm.azcomputerguru.com)
- **Zone ID:** 1beb9917c22b54be32e5215df2c227ce
- **WAF Rule:** "Skip bot check for RMM install endpoint" (ec57116fa2f34b5a991fe533129840cb)
- Expression: `(http.host eq "rmm.azcomputerguru.com" and starts_with(http.request.uri.path, "/install/"))`
- Action: Skip bot fight mode (allows curl installs)
- Created: 2026-05-11 by Howard Enos
- Status: Active and working correctly
### Test Sites in Database
Available site codes for testing (from sites table on Jupiter):
- `SILVER-HAWK-7639` - Main Office (site_id: 851376d1-33be-46ee-9e48-be44767e4a0a)
- `LOWER-GROVE-5965` - Mara Home (site_id: 901f0f81-0ea7-412f-ae3c-67c1c78869a3)
- `LOWER-OCEAN-7336` - Country Club (site_id: 7b32983d-982a-4a5c-af07-45a23453f589)
- `INNER-BRIDGE-8354` - IMCMain (site_id: 2c5b65ad-2d5e-47b3-b12b-632e35e08ff6)
- `SOUTH-PHOENIX-4306` - StambackSeptic (site_id: 0f3abe88-834f-4943-b28f-e97c236a0fea)
## Credentials & Database Access
### GuruRMM Database (Jupiter)
- **Host:** 172.16.3.30
- **Port:** 5432
- **Database:** gururmm
- **Username:** gururmm
- **Password:** 43617ebf7eb242e814ca9988cc4df5ad
- **Connection String:** `postgresql://gururmm:43617ebf7eb242e814ca9988cc4df5ad@localhost/gururmm`
- **Note:** Password stored in CONTEXT.md and used for server builds
### Cloudflare API Access
- **Full Account Token:** cfat_vQIRUHq6JwQ68F7aanbbwk14WnKInl0V0DjxpBg9d197012a
- **Zone ID (azcomputerguru.com):** 1beb9917c22b54be32e5215df2c227ce
- **Account ID:** 44594c346617d918bd3302a00b07e122
- **Account Name:** Mike@azcomputerguru.com Account
- **Vault Location:** `/Users/azcomputerguru/vault/services/cloudflare.sops.yaml`
### SSH Access
- **Jupiter (guru@172.16.3.30):** SSH key authentication, passwordless sudo
- **Pluto (Administrator@172.16.3.36):** Used by build pipeline for Windows builds
## Configuration Changes
### LaunchDaemon Plist (Generated by Install Script)
**Location:** `/Library/LaunchDaemons/com.azcomputerguru.gururmm-agent.plist`
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.azcomputerguru.gururmm-agent</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/gururmm-agent</string>
<string>run</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<dict>
<key>SuccessfulExit</key>
<false/>
</dict>
<key>StandardOutPath</key>
<string>/usr/local/var/log/gururmm-agent.log</string>
<key>StandardErrorPath</key>
<string>/usr/local/var/log/gururmm-agent.log</string>
</dict>
</plist>
```
### Site Configuration Plist (Generated by Install Script)
**Location:** `/usr/local/etc/gururmm/site.plist`
**Permissions:** 600 (root:wheel)
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>site_id</key>
<string>SITE-CODE-HERE</string>
</dict>
</plist>
```
After enrollment, `agent_key` field is added by agent:
```xml
<key>agent_key</key>
<string>agent-key-from-enrollment</string>
```
## Known Issues & Blockers
### BLOCKER: Code Signing Required for Apple Silicon Macs
**Issue:** Unsigned binaries cannot execute on Apple Silicon (ARM64) Macs running modern macOS.
**Symptoms:**
- Installation completes successfully (binary copied, plist created, LaunchDaemon loaded)
- Agent crashes immediately with SIGKILL (-9) when launched
- `launchctl list` shows status: `-9` (killed by system)
- No log output generated (killed before execution)
**Technical Details:**
- Binary signature: `adhoc` (unsigned)
- TeamIdentifier: `not set`
- macOS Gatekeeper blocks adhoc-signed executables on ARM64 architecture
- `xattr -c` to remove extended attributes does not resolve issue
- `spctl --add` is no longer supported on modern macOS
**Workarounds (Testing Only):**
1. **Disable Gatekeeper system-wide** (requires reboot):
```bash
sudo spctl --master-disable
# Reboot Mac
# Run install
sudo spctl --master-enable
```
2. **Intel Macs:** May work with unsigned binaries (needs verification)
3. **Development Signing:** Sign with ad-hoc certificate (still blocked on some systems)
**Permanent Solution Required:**
1. **Enroll in Apple Developer Program** ($99/year)
2. **Obtain Developer ID Application certificate** from Apple
3. **Sign binaries** with valid certificate:
```bash
codesign --sign "Developer ID Application: Arizona Computer Guru LLC" --timestamp --options runtime gururmm-agent
```
4. **Notarize with Apple** (submit to Apple for malware scan):
```bash
xcrun notarytool submit gururmm-agent.zip --keychain-profile "notarytool-profile" --wait
xcrun stapler staple gururmm-agent
```
**Impact:**
- Cannot deploy to Sylvia's Mac mini (WEST-MEADOW-9025) until code signing resolved
- All Apple Silicon Macs blocked from running agent
- Intel Macs may work (needs testing with unsigned binary)
**Status:** Pending user decision on Apple Developer Program enrollment
### Issue 2: Build Pipeline Cleanup Removes macOS Binaries
**Problem:** Automated build pipeline cleans up old files, removing manually-uploaded macOS binaries.
**Temporary Workaround:** Re-upload binaries after pipeline completes.
**Permanent Fix Required:** Update `build-agents.sh` to either:
- Preserve macOS binaries during cleanup (add to exclusion list)
- Build macOS binaries as part of pipeline (SSH to this Mac or cross-compile)
## Pending/Incomplete Tasks
### Immediate Next Steps
1. **Apple Developer Program Enrollment**
- Decision: Enroll or wait?
- Cost: $99/year
- Timeline: ~24 hours for approval
- Required for: Code signing certificate
2. **Code Signing Setup** (if enrolled)
- Install Xcode Command Line Tools (if not present)
- Download Developer ID Application certificate
- Configure keychain access for codesign
- Sign both arm64 and x86_64 binaries
- Test signed binary on this Mac
3. **Notarization** (after signing)
- Create app bundle or zip for submission
- Submit to Apple notarization service
- Wait for scan results (~5-15 minutes)
- Staple notarization ticket to binary
- Verify notarization: `spctl -a -vvv -t install gururmm-agent`
4. **Build Pipeline Integration**
- Add macOS build steps to `build-agents.sh`
- Option A: SSH to this Mac for native builds
- Option B: Cross-compile from Jupiter (if feasible)
- Include code signing in automated builds
- Create `-latest` symlinks for macOS binaries
- Add SHA256 checksums
5. **Dashboard Updates** (Phase 2)
- Add macOS install command to SiteDetail page
- Show macOS agent in platform selector
- Display macOS-specific instructions
- Add architecture detection (arm64 vs x86_64)
### Future Enhancements (Phase 3)
- **.pkg Installer:** macOS package installer (alternative to shell script)
- **Auto-Update Support:** Ensure macOS agents receive auto-updates
- **Uninstaller:** Script to cleanly remove agent and LaunchDaemon
- **Menu Bar Agent:** Optional GUI indicator (future feature)
- **Apple Silicon Optimization:** Native performance tuning
### Testing Pending
Once code signing resolved:
- Deploy to Sylvia's Mac mini (WEST-MEADOW-9025) - original blocker from Howard's message
- Verify enrollment flow on macOS
- Test agent reconnection after server restart
- Verify auto-update mechanism works on macOS
- Load testing with multiple macOS agents
- Intel Mac testing (if available)
## Reference Information
### Install Command (For Users)
```bash
curl -fsSL https://rmm.azcomputerguru.com/install/SITE-CODE/macos | sudo bash
```
### Uninstall Commands (Manual)
```bash
# Stop and unload service
sudo launchctl unload /Library/LaunchDaemons/com.azcomputerguru.gururmm-agent.plist
# Remove files
sudo rm /usr/local/bin/gururmm-agent
sudo rm /Library/LaunchDaemons/com.azcomputerguru.gururmm-agent.plist
sudo rm -rf /usr/local/etc/gururmm/
sudo rm -rf /usr/local/var/log/gururmm-agent.log
```
### Service Management
```bash
# Check service status
sudo launchctl list | grep gururmm
# View logs
sudo tail -f /usr/local/var/log/gururmm-agent.log
# Restart service
sudo launchctl unload /Library/LaunchDaemons/com.azcomputerguru.gururmm-agent.plist
sudo launchctl load /Library/LaunchDaemons/com.azcomputerguru.gururmm-agent.plist
# Verify plist syntax
plutil -lint /Library/LaunchDaemons/com.azcomputerguru.gururmm-agent.plist
# Check config file
sudo plutil -p /usr/local/etc/gururmm/site.plist
```
### API Endpoints (New)
- `GET /install/:site_code/macos` - Returns bash installer script
- `GET /install/:site_code/download/macos` - Returns arm64 binary with site-code trailer
- `GET /install/:site_code/download/macos-x86_64` - (Not yet implemented) Intel binary
### File Paths (All platforms)
- **Windows:** Registry at `HKLM\SOFTWARE\GuruRMM\` (SiteId, AgentKey)
- **macOS:** Plist at `/usr/local/etc/gururmm/site.plist`
- **Linux:** TOML fallback (future implementation)
### Related Documentation
- Implementation Plan: `projects/msp-tools/guru-rmm/docs/macos-agent-implementation-plan.md`
- Project Context: `projects/msp-tools/guru-rmm/CONTEXT.md`
- Project State: `projects/msp-tools/guru-rmm/PROJECT_STATE.md`
- Roadmap: `projects/msp-tools/guru-rmm/ROADMAP.md`
## Commits Made
1. **d7816d3** - feat(agent): Add macOS support with plist storage
- agent/src/macos_storage.rs (new)
- agent/Cargo.toml (modified)
- agent/src/registry.rs (modified)
- agent/src/main.rs (modified)
2. **f83806e** - feat(server): Add macOS installer endpoints
- server/src/api/install.rs (+183 lines)
- server/src/main.rs (+2 lines)
3. **8ee25f3** - docs: Update PROJECT_STATE for macOS agent Phase 1 completion
- PROJECT_STATE.md (released lock, added macOS component, logged changes)
All commits pushed to `main` branch on Gitea (git.azcomputerguru.com/azcomputerguru/gururmm).
## Success Metrics
[OK] Agent compiles for both architectures (arm64 + x86_64)
[OK] Server endpoints return valid install script
[OK] Install script downloads and configures agent correctly
[OK] LaunchDaemon plist created with correct format
[OK] Site configuration plist created with site_id
[OK] Cloudflare WAF rule allows curl installs
[BLOCKED] Agent runs successfully (requires code signing)
[PENDING] Agent enrolls with server (blocked by execution)
[PENDING] Dashboard shows macOS install option (Phase 2)
## Lessons Learned
1. **Code Signing is Critical:** Cannot defer Apple Developer enrollment for production macOS deployments on Apple Silicon. Should have been identified in planning phase.
2. **Build Pipeline Coordination:** Manual server rebuilds are faster for testing server-only changes. Full pipeline takes 15+ minutes for Windows builds.
3. **Platform Storage Abstraction:** The registry.rs pattern worked perfectly - adding macOS support required minimal changes to main.rs because of good abstraction.
4. **Installation Testing:** Shell script installers are easy to test locally - immediate feedback loop compared to .pkg installers.
5. **Cloudflare WAF:** Existing rule from Howard's earlier work meant no additional configuration needed - good team coordination.
## Notes for Future Sessions
- Howard Enos left message (2026-05-07) about Sylvia blocked on Mac mini - this work unblocks her once code signing resolved
- Build pipeline still building Windows variants while we were testing - consider separating server/agent builds
- This Mac (Mikes-MacBook-Air) can be used for future macOS builds via SSH
- Intel Mac testing still needed - unsigned binary may work on x86_64
- Consider documenting Apple Developer setup process for future reference
---
**Session Status:** Phase 1 implementation complete. Deployment blocked on Apple Developer Program enrollment and code signing certificate.