# GitHub Self-Hosted Runner Management Guide

## SSH Connection

### Connection Details
- **Host:** 100.126.148.125
- **User:** githubrunner
- **SSH Key:** ~/.ssh/id_rsa_remarkable (passwordless)
- **Connection Command:** `ssh -i ~/.ssh/id_rsa_remarkable githubrunner@100.126.148.125`

### User Configuration
- **User:** githubrunner
- **Groups:** staff, everyone, localaccounts, com.apple.access_ssh, etc.
- **Home Directory:** /Users/githubrunner
- **Shell:** zsh (default)
- **Sudo Access:** Configured for passwordless sudo (NOPASSWD: ALL)

## Runner Configuration

### Runner Installation
- **Location:** ~/actions-runner
- **Version:** 2.331.0
- **Organization:** coredevices
- **Runner Name:** mac-mini-github-runner
- **Labels:** self-hosted, macOS, ARM64
- **Working Directory:** ~/actions-runner/_work

### Runner Files Structure
```
~/actions-runner/
├── .credentials          # Runner registration credentials
├── .credentials_rsaparams
├── .env                  # Environment variables for runner
├── .path                 # PATH configuration for runner
├── .runner               # Runner configuration (JSON)
├── .service              # Service configuration marker
├── bin/                  # Runner binaries
├── config.sh             # Configuration script
├── run.sh                # Start runner script
├── runsvc.sh            # Service wrapper script
├── svc.sh               # Service management script
├── _work/               # Job working directory
└── _diag/               # Diagnostic logs
```

### Important Configuration Files

#### .env File
Contains environment variables used by the runner:
```bash
LANG=en_US.UTF-8
JAVA_HOME=/opt/homebrew/opt/openjdk@17
DEVELOPER_DIR=/Applications/Xcode_26.2.app/Contents/Developer
```

#### .path File
PATH entries for the runner (one per line, order matters):
```
/opt/homebrew/opt/openjdk@17/bin
/opt/homebrew/opt/ruby/bin
/opt/homebrew/lib/ruby/gems/4.0.0/bin
/opt/homebrew/bin
/usr/local/bin
/usr/bin
/bin
/usr/sbin
/sbin
```

**Critical:** The runner uses `.env` and `.path` files, NOT ~/.zshrc. Always update these files when adding new tools or environment variables.

#### .runner File
JSON configuration showing:
```json
{
  "agentId": 64,
  "agentName": "mac-mini-github-runner",
  "poolId": 1,
  "poolName": "Default",
  "serverUrl": "https://pipelinesghubeus24.actions.githubusercontent.com/...",
  "gitHubUrl": "https://github.com/coredevices",
  "workFolder": "_work"
}
```

## Running the Runner

### Manual Start (Current Method)
```bash
cd ~/actions-runner
nohup ./run.sh > runner.log 2>&1 &
```

**Check if running:**
```bash
ps aux | grep "Runner.Listener" | grep -v grep
```

**View logs:**
```bash
tail -f ~/actions-runner/runner.log
```

**Stop runner:**
```bash
pkill -f "Runner.Listener"
```

### Service Management (Auto-Start)

#### Using Built-in Service Script
```bash
cd ~/actions-runner

# Install service (creates LaunchAgent)
./svc.sh install githubrunner

# Start service
./svc.sh start

# Stop service
./svc.sh stop

# Check status
./svc.sh status

# Uninstall service
./svc.sh uninstall
```

#### LaunchAgent Location
- **User LaunchAgent:** `~/Library/LaunchAgents/actions.runner.coredevices.mac-mini-github-runner.plist`
- **Logs:** `~/Library/Logs/actions.runner.coredevices.mac-mini-github-runner/`

#### Important LaunchAgent Limitations

**SSH Session Limitations:**
When connected via SSH without a GUI session, LaunchAgent commands may fail with errors like:
- `Bootstrap failed: 125: Domain does not support specified action`
- `Could not enable service: 125: Domain does not support specified action`

**This is because:**
1. User LaunchAgents require an active GUI session
2. SSH connections don't create GUI sessions by default
3. `launchctl bootstrap gui/$(id -u)` and `launchctl enable gui/$(id -u)/...` require GUI context

**Workarounds:**
1. **Manual start via SSH:** Use `nohup ./run.sh &` (currently implemented)
2. **GUI login:** Have the user log in via VNC/console, then service will auto-start
3. **System Service:** Convert to system-level LaunchDaemon (requires running as root/system)

**Auto-Start Behavior:**
- LaunchAgent is configured with `<key>RunAtLoad</key><true/>`
- Will automatically start when githubrunner user logs in via GUI
- Will NOT auto-start from SSH-only sessions
- Will auto-start after system reboot IF user has auto-login enabled

## Environment Configuration

### Shell Configuration (~/.zshrc)
The shell configuration is set up but NOT used by the runner directly:
```bash
# Homebrew environment
eval "$(/opt/homebrew/bin/brew shellenv)"

# Ruby from Homebrew
export PATH="/opt/homebrew/opt/ruby/bin:$PATH"
export PATH="/opt/homebrew/lib/ruby/gems/4.0.0/bin:$PATH"

# Java 17
export PATH="/opt/homebrew/opt/openjdk@17/bin:$PATH"
export JAVA_HOME="/opt/homebrew/opt/openjdk@17"

# Xcode
export DEVELOPER_DIR="/Applications/Xcode_26.2.app/Contents/Developer"
```

**Important:** This is for interactive shell sessions only. The runner uses `.env` and `.path` files instead.

### Installed Software

| Component | Version | Location |
|-----------|---------|----------|
| Homebrew | 5.0.12 | /opt/homebrew |
| Xcode | 26.2 (17C52) | /Applications/Xcode_26.2.app |
| Java (OpenJDK) | 17.0.18 | /opt/homebrew/opt/openjdk@17 |
| Gradle | 9.3.1 | /opt/homebrew/bin/gradle |
| Ruby | 4.0.1 | /opt/homebrew/opt/ruby |
| Bundler | 4.0.4 & 4.0.5 | /opt/homebrew/lib/ruby/gems/4.0.0/bin |
| CocoaPods | 1.16.2 | /opt/homebrew/lib/ruby/gems/4.0.0/bin |
| xcpretty | 0.4.1 | /opt/homebrew/lib/ruby/gems/4.0.0/bin |
| Git | 2.52.0 | /opt/homebrew/bin/git |
| Git LFS | 3.7.1 | /opt/homebrew/bin/git-lfs |
| xcodes CLI | 1.6.2 | /opt/homebrew/bin/xcodes |

### Tool Verification Commands
```bash
# Via SSH
ssh -i ~/.ssh/id_rsa_remarkable githubrunner@100.126.148.125 '
  echo "=== Xcode ===" && xcodebuild -version
  echo "=== Java ===" && /opt/homebrew/opt/openjdk@17/bin/java -version 2>&1 | head -2
  echo "=== Gradle ===" && /opt/homebrew/bin/gradle --version | grep Gradle | head -1
  echo "=== Ruby ===" && /opt/homebrew/opt/ruby/bin/ruby --version
  echo "=== CocoaPods ===" && /opt/homebrew/lib/ruby/gems/4.0.0/bin/pod --version
  echo "=== xcpretty ===" && /opt/homebrew/lib/ruby/gems/4.0.0/bin/xcpretty --version
  echo "=== Git ===" && /opt/homebrew/bin/git --version
  echo "=== Git LFS ===" && /opt/homebrew/bin/git-lfs version
'
```

## Workflow Configuration

### Workflow File: .github/workflows/build-ios.yml
- **Runner:** `runs-on: [self-hosted, macOS, ARM64]`
- **Xcode Setup:** Uses `sudo xcode-select` (requires passwordless sudo)
- **Removed Steps:** JDK setup, Swift setup, xcpretty installation (pre-installed)

### Workflow Requirements Met
✅ Git 2.52.0 with Git LFS
✅ Xcode 26.2 (Build 17C52)
✅ Java 17 (Temurin)
✅ Gradle 9.3+
✅ Ruby 4.0+
✅ CocoaPods 1.16.2
✅ xcpretty
✅ Passwordless sudo
✅ Keychain access for code signing

## Common Operations

### Check Runner Status
```bash
# Check if runner is running
ssh -i ~/.ssh/id_rsa_remarkable githubrunner@100.126.148.125 '
  ps aux | grep "Runner.Listener" | grep -v grep
'

# Check recent logs
ssh -i ~/.ssh/id_rsa_remarkable githubrunner@100.126.148.125 '
  tail -30 ~/actions-runner/runner.log
'

# Check service status
ssh -i ~/.ssh/id_rsa_remarkable githubrunner@100.126.148.125 '
  cd ~/actions-runner && ./svc.sh status
'
```

### Start Runner
```bash
# Manual start (current method)
ssh -i ~/.ssh/id_rsa_remarkable githubrunner@100.126.148.125 '
  cd ~/actions-runner && nohup ./run.sh > runner.log 2>&1 &
'

# Via service (may fail over SSH without GUI)
ssh -i ~/.ssh/id_rsa_remarkable githubrunner@100.126.148.125 '
  cd ~/actions-runner && ./svc.sh start
'
```

### Stop Runner
```bash
# Kill runner process
ssh -i ~/.ssh/id_rsa_remarkable githubrunner@100.126.148.125 '
  pkill -f "Runner.Listener"
'

# Via service
ssh -i ~/.ssh/id_rsa_remarkable githubrunner@100.126.148.125 '
  cd ~/actions-runner && ./svc.sh stop
'
```

### Restart Runner (Pick up environment changes)
```bash
ssh -i ~/.ssh/id_rsa_remarkable githubrunner@100.126.148.125 '
  pkill -f "Runner.Listener"
  cd ~/actions-runner && nohup ./run.sh > runner.log 2>&1 &
'
```

### Update Runner Configuration
```bash
# Update PATH
ssh -i ~/.ssh/id_rsa_remarkable githubrunner@100.126.148.125 '
  echo "/new/path" >> ~/actions-runner/.path
'

# Update environment variables
ssh -i ~/.ssh/id_rsa_remarkable githubrunner@100.126.148.125 '
  echo "NEW_VAR=value" >> ~/actions-runner/.env
'

# Restart runner to pick up changes
ssh -i ~/.ssh/id_rsa_remarkable githubrunner@100.126.148.125 '
  pkill -f "Runner.Listener"
  cd ~/actions-runner && nohup ./run.sh > runner.log 2>&1 &
'
```

## Local Configuration

### local.properties File
The repository requires a `local.properties` file for the self-hosted runner to specify tool paths that Gradle needs.

**Location:** Repository root (`~/actions-runner/_work/CoreApp/CoreApp/local.properties`)

**Contents:**
```properties
# CocoaPods executable path for Kotlin Multiplatform
kotlin.apple.cocoapods.bin=/opt/homebrew/lib/ruby/gems/4.0.0/bin/pod
```

**Setup:**
```bash
# On the runner machine
cd ~/actions-runner/_work/CoreApp/CoreApp
cp local.properties.template local.properties
# Edit if needed for your specific paths
```

**Note:** This file is gitignored and must be created on each runner. A template (`local.properties.template`) is provided in the repository.

## Troubleshooting

### CocoaPods Not Found Error
If Gradle reports "CocoaPods executable not found in your PATH":

1. Verify CocoaPods is installed:
   ```bash
   /opt/homebrew/lib/ruby/gems/4.0.0/bin/pod --version
   ```

2. Ensure `local.properties` exists in workspace:
   ```bash
   cat ~/actions-runner/_work/CoreApp/CoreApp/local.properties
   ```

3. Check the path in local.properties matches where pod is installed:
   ```bash
   ls -la /opt/homebrew/lib/ruby/gems/4.0.0/bin/pod
   ```

4. If path is wrong, update local.properties and re-run build

### Runner Not Starting
1. **Check if already running:**
   ```bash
   ps aux | grep "Runner.Listener" | grep -v grep
   ```

2. **Check logs for errors:**
   ```bash
   tail -50 ~/actions-runner/runner.log
   ```

3. **Verify runner configuration:**
   ```bash
   cat ~/actions-runner/.runner
   ```

4. **Check credentials:**
   ```bash
   ls -la ~/actions-runner/.credentials*
   ```

### Runner Not Picking Up Jobs
1. **Verify runner is connected:**
   ```bash
   tail ~/actions-runner/runner.log | grep "Connected to GitHub"
   ```

2. **Check runner labels match workflow:**
   - Workflow needs: `[self-hosted, macOS, ARM64]`
   - Runner automatically gets these labels on macOS ARM64

3. **Check GitHub repository settings:**
   - Go to Settings → Actions → Runners
   - Verify mac-mini-github-runner is online

### Service Won't Start via SSH
This is expected behavior. User LaunchAgents require GUI sessions.

**Solutions:**
1. Use manual start: `nohup ./run.sh &`
2. Have user log in via GUI (VNC/console)
3. Convert to system LaunchDaemon (more complex)

### Tool Not Found During Build
1. **Check tool is installed:**
   ```bash
   which tool-name
   /opt/homebrew/bin/tool-name --version
   ```

2. **Verify runner PATH includes tool:**
   ```bash
   cat ~/actions-runner/.path
   ```

3. **Add to runner PATH if missing:**
   ```bash
   echo "/path/to/tool" >> ~/actions-runner/.path
   # Restart runner
   ```

4. **Check environment variables:**
   ```bash
   cat ~/actions-runner/.env
   ```

### Sudo Password Required
The runner needs passwordless sudo for `xcode-select`.

**Verify sudo is configured:**
```bash
sudo -n xcode-select -p
```

**If fails, check sudoers:**
```bash
sudo cat /etc/sudoers.d/githubrunner
# Should contain: githubrunner ALL=(ALL) NOPASSWD: ALL
```

### Build Fails with "Command not found"
This usually means the tool is not in the runner's PATH.

**Debug:**
1. SSH into the machine
2. Run the command manually to verify it works
3. Check the full path: `which command-name`
4. Add that path to `~/actions-runner/.path`
5. Restart the runner

## Security Considerations

### Sudo Access
- githubrunner has NOPASSWD sudo access
- Required for `xcode-select` during builds
- Configured in `/etc/sudoers.d/githubrunner`

### SSH Key
- Private key: `~/.ssh/id_rsa_remarkable` (on your machine)
- Allows passwordless SSH access
- Keep this key secure

### Runner Credentials
- Stored in `~/actions-runner/.credentials`
- Encrypted with RSA parameters in `.credentials_rsaparams`
- Required for runner to connect to GitHub

### Code Signing
- GitHub secrets contain P12 certificates and passwords
- Provisioning profiles downloaded during build
- Stored temporarily in keychain during build

## Best Practices

### 1. Always Use Full Paths in Runner Config
Don't rely on shell initialization files. Add everything to `.path` and `.env`.

### 2. Restart Runner After Configuration Changes
Environment changes require a runner restart to take effect.

### 3. Monitor Logs Regularly
```bash
tail -f ~/actions-runner/runner.log
```

### 4. Keep Software Updated
```bash
# Update Homebrew packages
brew update && brew upgrade

# Check for Xcode updates
xcodes list

# Update runner (GitHub will notify when updates are available)
```

### 5. Test Workflow Changes
Always test workflow changes with a self-hosted runner to ensure compatibility.

### 6. Backup Configuration
Keep backups of:
- `~/actions-runner/.env`
- `~/actions-runner/.path`
- `/etc/sudoers.d/githubrunner`

## Quick Reference Commands

```bash
# Connect to runner
ssh -i ~/.ssh/id_rsa_remarkable githubrunner@100.126.148.125

# Check runner status
ps aux | grep "Runner.Listener" | grep -v grep

# Start runner
cd ~/actions-runner && nohup ./run.sh > runner.log 2>&1 &

# Stop runner
pkill -f "Runner.Listener"

# View logs
tail -f ~/actions-runner/runner.log

# Check tool versions
xcodebuild -version
java -version
gradle --version
ruby --version
pod --version

# Update PATH
echo "/new/path" >> ~/actions-runner/.path

# Update environment
echo "VAR=value" >> ~/actions-runner/.env

# Verify sudo
sudo -n xcode-select -p

# Service management (may not work over SSH)
cd ~/actions-runner
./svc.sh status
./svc.sh start
./svc.sh stop
```

## System Information

- **Hostname:** Mac Mini
- **IP:** 100.126.148.125
- **OS:** macOS 15.7.1 (24G231) Sequoia
- **Architecture:** arm64 (Apple M4)
- **Memory:** 16GB
- **Disk:** 228GB total, ~111GB available after setup
- **Xcode Developer Directory:** /Applications/Xcode_26.2.app/Contents/Developer

## Additional Notes

### Xcode 26.2
- This is a preview/beta version of Xcode
- Designed for macOS Sequoia 26 but runs on macOS 15
- Downloaded via xcodes CLI with Apple ID authentication
- Required 2FA authentication during download
- XIP file size: ~2.2GB (compressed)
- Installed size: ~35GB

### Apple Developer Authentication
During Xcode download:
- Email: applecore@repebble.com
- Required 2FA codes sent to phone ending in ••73
- Credentials stored temporarily for download session

### Installation Time
Total setup time: ~2-3 hours
- Homebrew: 5-10 minutes
- Xcode download: 30-90 minutes (depends on connection)
- Xcode extraction: 10-15 minutes
- Other tools: 10-15 minutes
- Configuration: 5-10 minutes

---

*Last Updated: 2026-02-02*
*Runner Version: 2.331.0*
*Xcode Version: 26.2 (17C52)*
