Tutorial

Neue Updates und Verbesserungen zu Macfleet.

Wichtiger Hinweis

Die in diesen Tutorials bereitgestellten Codebeispiele und Skripte dienen nur zu Bildungszwecken. Macfleet ist nicht verantwortlich für Probleme, Schäden oder Sicherheitslücken, die durch die Verwendung, Änderung oder Implementierung dieser Beispiele entstehen können. Überprüfen und testen Sie Code immer in einer sicheren Umgebung, bevor Sie ihn in Produktionssystemen verwenden.

File Protection on macOS

Protect critical files and applications across your MacFleet devices using advanced file protection techniques, immutable flags, and enterprise security policies. This tutorial provides comprehensive tools for implementing organizational file security standards.

Understanding macOS File Protection Methods

macOS offers several file protection mechanisms:

  • Immutable Flags - System-level protection preventing modification or deletion
  • File Permissions - User and group-based access controls
  • Extended Attributes - Additional metadata for security enforcement
  • System Integrity Protection (SIP) - Built-in protection for system files

Basic File Protection Commands

Lock Single File

#!/bin/bash

# Lock a file using immutable flag
FILE_PATH="/Applications/WhatsApp.app"

chflags schg "$FILE_PATH"
echo "File locked: $FILE_PATH"

Unlock Single File

#!/bin/bash

# Unlock a file by removing immutable flag
FILE_PATH="/Applications/WhatsApp.app"

chflags noschg "$FILE_PATH"
echo "File unlocked: $FILE_PATH"

Check File Protection Status

#!/bin/bash

# Check if file is protected
FILE_PATH="/Applications/WhatsApp.app"

if ls -lO "$FILE_PATH" | grep -q "schg"; then
    echo "File is protected: $FILE_PATH"
else
    echo "File is not protected: $FILE_PATH"
fi

Enterprise File Protection System

#!/bin/bash

# MacFleet Enterprise File Protection System
# Comprehensive file security and protection management

# Configuration
MACFLEET_DIR="/etc/macfleet"
POLICIES_DIR="$MACFLEET_DIR/file_policies"
REPORTS_DIR="$MACFLEET_DIR/reports"
COMPLIANCE_DIR="$MACFLEET_DIR/compliance"
AUDIT_DIR="$MACFLEET_DIR/audit"
LOG_FILE="/var/log/macfleet_file_protection.log"
BACKUP_DIR="$MACFLEET_DIR/backups"

# Create directory structure
create_directories() {
    local dirs=("$MACFLEET_DIR" "$POLICIES_DIR" "$REPORTS_DIR" "$COMPLIANCE_DIR" "$AUDIT_DIR" "$BACKUP_DIR")
    for dir in "${dirs[@]}"; do
        [[ ! -d "$dir" ]] && mkdir -p "$dir"
    done
}

# Logging function
log_action() {
    local message="$1"
    local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    echo "[$timestamp] $message" | tee -a "$LOG_FILE"
}

# File Categories for Enterprise Protection
declare -A FILE_CATEGORIES=(
    ["critical_apps"]="/Applications/System Preferences.app,/Applications/Terminal.app,/Applications/Utilities"
    ["business_apps"]="/Applications/Microsoft Office,/Applications/Slack.app,/Applications/Zoom.app"
    ["system_configs"]="/etc/hosts,/etc/sudoers,/etc/ssh/sshd_config"
    ["security_tools"]="/Applications/1Password.app,/Applications/Keychain Access.app"
    ["development_tools"]="/Applications/Xcode.app,/Applications/Visual Studio Code.app"
    ["admin_utilities"]="/Applications/Activity Monitor.app,/Applications/Console.app"
)

# Protection Levels
declare -A PROTECTION_LEVELS=(
    ["maximum"]="schg,uappnd,uchg"        # System immutable, user append-only, user immutable
    ["high"]="schg,uchg"                  # System immutable, user immutable
    ["moderate"]="uchg"                   # User immutable only
    ["minimal"]="uappnd"                  # User append-only
    ["readonly"]="ro"                     # Read-only access
)

# Security Policies
declare -A SECURITY_POLICIES=(
    ["enterprise_lockdown"]="critical_apps:maximum,business_apps:high,system_configs:maximum,security_tools:high"
    ["standard_protection"]="critical_apps:high,system_configs:high,security_tools:moderate"
    ["development_safe"]="critical_apps:moderate,system_configs:high,development_tools:minimal"
    ["minimal_security"]="system_configs:moderate,security_tools:minimal"
    ["maintenance_mode"]="system_configs:readonly"
)

# Apply protection to file or directory
protect_file() {
    local file_path="$1"
    local protection_level="$2"
    local policy="$3"
    
    if [[ ! -e "$file_path" ]]; then
        log_action "ERROR: File not found: $file_path"
        return 1
    fi
    
    # Backup current flags
    local current_flags=$(ls -lO "$file_path" 2>/dev/null | awk '{print $5}' || echo "none")
    echo "$file_path:$current_flags:$(date)" >> "$BACKUP_DIR/file_flags_backup.log"
    
    # Apply protection based on level
    local flags="${PROTECTION_LEVELS[$protection_level]}"
    if [[ -z "$flags" ]]; then
        log_action "ERROR: Unknown protection level: $protection_level"
        return 1
    fi
    
    # Split flags and apply each one
    IFS=',' read -ra flag_array <<< "$flags"
    for flag in "${flag_array[@]}"; do
        if chflags "$flag" "$file_path" 2>/dev/null; then
            log_action "Applied protection flag '$flag' to: $file_path (Policy: $policy)"
        else
            log_action "ERROR: Failed to apply flag '$flag' to: $file_path"
        fi
    done
    
    # Set restrictive permissions if needed
    if [[ "$protection_level" == "maximum" || "$protection_level" == "high" ]]; then
        chmod 644 "$file_path" 2>/dev/null
        log_action "Set restrictive permissions for: $file_path"
    fi
    
    # Save protection metadata
    echo "file=$file_path,protection=$protection_level,policy=$policy,timestamp=$(date),user=$(whoami)" >> "$POLICIES_DIR/applied_protections.log"
}

# Remove protection from file
unprotect_file() {
    local file_path="$1"
    local reason="$2"
    
    if [[ ! -e "$file_path" ]]; then
        log_action "ERROR: File not found: $file_path"
        return 1
    fi
    
    # Remove all common protection flags
    local flags_to_remove=("schg" "uchg" "uappnd" "ro")
    
    for flag in "${flags_to_remove[@]}"; do
        if chflags "no$flag" "$file_path" 2>/dev/null; then
            log_action "Removed protection flag '$flag' from: $file_path (Reason: $reason)"
        fi
    done
    
    # Restore standard permissions
    if [[ -f "$file_path" ]]; then
        chmod 644 "$file_path" 2>/dev/null
    elif [[ -d "$file_path" ]]; then
        chmod 755 "$file_path" 2>/dev/null
    fi
    
    log_action "File unprotected: $file_path (Reason: $reason)"
}

# Apply protection to file category
protect_category() {
    local category="$1"
    local protection_level="$2"
    local policy="$3"
    
    if [[ -z "${FILE_CATEGORIES[$category]}" ]]; then
        log_action "ERROR: Unknown file category: $category"
        return 1
    fi
    
    log_action "Protecting category: $category with level: $protection_level (Policy: $policy)"
    
    # Split comma-separated file paths
    IFS=',' read -ra files <<< "${FILE_CATEGORIES[$category]}"
    
    for file_path in "${files[@]}"; do
        # Handle wildcard patterns
        if [[ "$file_path" == *"*"* ]]; then
            # Use find for pattern matching
            find "${file_path%/*}" -name "${file_path##*/}" 2>/dev/null | while read -r found_file; do
                protect_file "$found_file" "$protection_level" "$policy"
            done
        else
            protect_file "$file_path" "$protection_level" "$policy"
        fi
    done
}

# Apply comprehensive security policy
apply_security_policy() {
    local policy="$1"
    
    if [[ -z "${SECURITY_POLICIES[$policy]}" ]]; then
        log_action "ERROR: Unknown security policy: $policy"
        return 1
    fi
    
    log_action "Applying security policy: $policy"
    
    # Parse policy string: "category:level,category:level"
    IFS=',' read -ra policy_items <<< "${SECURITY_POLICIES[$policy]}"
    
    for item in "${policy_items[@]}"; do
        IFS=':' read -ra parts <<< "$item"
        local category="${parts[0]}"
        local protection_level="${parts[1]}"
        
        protect_category "$category" "$protection_level" "$policy"
    done
    
    log_action "Security policy '$policy' applied successfully"
    
    # Generate compliance report
    generate_compliance_report "$policy"
}

# Bulk file protection operations
bulk_protect_files() {
    local file_list="$1"
    local protection_level="$2"
    local policy="$3"
    
    if [[ ! -f "$file_list" ]]; then
        log_action "ERROR: File list not found: $file_list"
        return 1
    fi
    
    log_action "Starting bulk protection operation from list: $file_list"
    local protected_count=0
    local failed_count=0
    
    while IFS= read -r file_path; do
        [[ -z "$file_path" || "$file_path" =~ ^#.*$ ]] && continue
        
        if protect_file "$file_path" "$protection_level" "$policy"; then
            ((protected_count++))
        else
            ((failed_count++))
        fi
    done < "$file_list"
    
    log_action "Bulk protection completed: $protected_count protected, $failed_count failed"
}

# Critical system file protection
protect_system_files() {
    local protection_mode="$1"
    
    log_action "Applying system file protection: $protection_mode"
    
    # Define critical system files
    local critical_files=(
        "/etc/hosts"
        "/etc/sudoers"
        "/etc/ssh/sshd_config"
        "/etc/passwd"
        "/etc/group"
        "/System/Library/LaunchDaemons"
        "/Library/LaunchDaemons"
        "/usr/bin/sudo"
        "/bin/sh"
        "/bin/bash"
    )
    
    case "$protection_mode" in
        "lockdown")
            for file in "${critical_files[@]}"; do
                if [[ -e "$file" ]]; then
                    protect_file "$file" "maximum" "system_lockdown"
                fi
            done
            ;;
        "standard")
            for file in "${critical_files[@]}"; do
                if [[ -e "$file" ]]; then
                    protect_file "$file" "high" "system_standard"
                fi
            done
            ;;
        "minimal")
            for file in "${critical_files[@]}"; do
                if [[ -e "$file" ]]; then
                    protect_file "$file" "moderate" "system_minimal"
                fi
            done
            ;;
    esac
    
    log_action "System file protection applied: $protection_mode"
}

# File integrity monitoring
monitor_file_integrity() {
    local monitoring_mode="$1"
    local monitor_file="$POLICIES_DIR/integrity_monitor.log"
    
    log_action "Starting file integrity monitoring: $monitoring_mode"
    
    # Get list of protected files
    local protected_files=()
    if [[ -f "$POLICIES_DIR/applied_protections.log" ]]; then
        while IFS=',' read -r entry; do
            if [[ "$entry" =~ file=([^,]+) ]]; then
                protected_files+=("${BASH_REMATCH[1]}")
            fi
        done < "$POLICIES_DIR/applied_protections.log"
    fi
    
    # Monitor files for changes
    for file in "${protected_files[@]}"; do
        if [[ -e "$file" ]]; then
            local current_hash=$(shasum -a 256 "$file" 2>/dev/null | cut -d' ' -f1)
            local current_flags=$(ls -lO "$file" 2>/dev/null | awk '{print $5}' || echo "none")
            local timestamp=$(date -u +%Y-%m-%dT%H:%M:%SZ)
            
            echo "$timestamp:$file:$current_hash:$current_flags" >> "$monitor_file"
        fi
    done
    
    log_action "File integrity monitoring completed: $monitoring_mode"
}

# Emergency unlock procedures
emergency_unlock() {
    local reason="$1"
    local unlock_scope="$2"
    
    log_action "EMERGENCY UNLOCK INITIATED - Reason: $reason, Scope: $unlock_scope"
    
    case "$unlock_scope" in
        "all")
            # Unlock all protected files
            if [[ -f "$POLICIES_DIR/applied_protections.log" ]]; then
                while IFS=',' read -r entry; do
                    if [[ "$entry" =~ file=([^,]+) ]]; then
                        unprotect_file "${BASH_REMATCH[1]}" "emergency_unlock"
                    fi
                done < "$POLICIES_DIR/applied_protections.log"
            fi
            ;;
        "system")
            # Unlock only system files
            local system_files=("/etc/hosts" "/etc/sudoers" "/etc/ssh/sshd_config")
            for file in "${system_files[@]}"; do
                if [[ -e "$file" ]]; then
                    unprotect_file "$file" "emergency_system_unlock"
                fi
            done
            ;;
        "applications")
            # Unlock application files
            find /Applications -name "*.app" -exec chflags noschg {} \; 2>/dev/null
            log_action "Emergency unlock completed for applications"
            ;;
    esac
    
    # Create emergency unlock record
    echo "emergency_unlock:$reason:$unlock_scope:$(date):$(whoami)" >> "$AUDIT_DIR/emergency_operations.log"
    log_action "Emergency unlock completed: $unlock_scope"
}

# Generate comprehensive compliance report
generate_compliance_report() {
    local policy="$1"
    local report_file="$REPORTS_DIR/file_protection_compliance_$(date +%Y%m%d_%H%M%S).json"
    
    local protected_files_count=0
    local total_files_checked=0
    
    # Count protected files
    if [[ -f "$POLICIES_DIR/applied_protections.log" ]]; then
        protected_files_count=$(wc -l < "$POLICIES_DIR/applied_protections.log")
    fi
    
    # Count total files in categories
    for category in "${!FILE_CATEGORIES[@]}"; do
        IFS=',' read -ra files <<< "${FILE_CATEGORIES[$category]}"
        total_files_checked=$((total_files_checked + ${#files[@]}))
    done
    
    cat > "$report_file" << EOF
{
  "report_metadata": {
    "timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
    "hostname": "$(hostname)",
    "policy_applied": "$policy",
    "report_version": "1.0"
  },
  "file_protection_status": {
    "protected_files_count": $protected_files_count,
    "total_files_checked": $total_files_checked,
    "protection_coverage": $(echo "scale=2; $protected_files_count * 100 / $total_files_checked" | bc -l 2>/dev/null || echo "0"),
    "emergency_unlocks_recorded": $([ -f "$AUDIT_DIR/emergency_operations.log" ] && wc -l < "$AUDIT_DIR/emergency_operations.log" || echo "0")
  },
  "security_policy": {
    "name": "$policy",
    "categories_protected": $(echo "${!FILE_CATEGORIES[@]}" | wc -w),
    "compliance_frameworks": ["SOX", "HIPAA", "NIST", "ISO27001", "PCI-DSS"]
  },
  "system_status": {
    "sip_enabled": $(csrutil status | grep -q "enabled" && echo "true" || echo "false"),
    "gatekeeper_enabled": $(spctl --status | grep -q "enabled" && echo "true" || echo "false"),
    "filevault_enabled": $(fdesetup status | grep -q "On" && echo "true" || echo "false"),
    "backup_available": $([ -f "$BACKUP_DIR/file_flags_backup.log" ] && echo "true" || echo "false")
  },
  "integrity_monitoring": {
    "active": $([ -f "$POLICIES_DIR/integrity_monitor.log" ] && echo "true" || echo "false"),
    "last_check": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
    "monitored_files": $([ -f "$POLICIES_DIR/integrity_monitor.log" ] && wc -l < "$POLICIES_DIR/integrity_monitor.log" || echo "0")
  }
}
EOF
    
    log_action "Compliance report generated: $report_file"
    echo "Report saved to: $report_file"
}

# Health check and validation
perform_health_check() {
    echo "=== MacFleet File Protection Health Check ==="
    
    # Check system integrity protection
    local sip_status=$(csrutil status 2>/dev/null || echo "Unknown")
    echo "✓ System Integrity Protection: $sip_status"
    
    # Check protected files
    local protected_count=0
    if [[ -f "$POLICIES_DIR/applied_protections.log" ]]; then
        protected_count=$(wc -l < "$POLICIES_DIR/applied_protections.log")
    fi
    echo "✓ Protected files: $protected_count"
    
    # Check critical system files
    local critical_protected=0
    local critical_files=("/etc/hosts" "/etc/sudoers" "/etc/ssh/sshd_config")
    for file in "${critical_files[@]}"; do
        if [[ -e "$file" ]] && ls -lO "$file" | grep -q "schg"; then
            ((critical_protected++))
        fi
    done
    echo "✓ Critical system files protected: $critical_protected/${#critical_files[@]}"
    
    # Check backup availability
    if [[ -f "$BACKUP_DIR/file_flags_backup.log" ]]; then
        local backup_entries=$(wc -l < "$BACKUP_DIR/file_flags_backup.log")
        echo "✓ Backup entries: $backup_entries"
    else
        echo "○ No backup records found"
    fi
    
    # Check integrity monitoring
    if [[ -f "$POLICIES_DIR/integrity_monitor.log" ]]; then
        local monitor_entries=$(wc -l < "$POLICIES_DIR/integrity_monitor.log")
        echo "✓ Integrity monitoring entries: $monitor_entries"
    else
        echo "○ No integrity monitoring active"
    fi
    
    # Check for emergency operations
    if [[ -f "$AUDIT_DIR/emergency_operations.log" ]]; then
        local emergency_count=$(wc -l < "$AUDIT_DIR/emergency_operations.log")
        echo "⚠️  Emergency operations recorded: $emergency_count"
    else
        echo "✓ No emergency operations recorded"
    fi
}

# Fleet deployment function
deploy_to_fleet() {
    local policy="$1"
    local fleet_file="$2"
    
    if [[ ! -f "$fleet_file" ]]; then
        log_action "ERROR: Fleet file not found: $fleet_file"
        return 1
    fi
    
    log_action "Starting fleet deployment of policy: $policy"
    
    while IFS= read -r host; do
        [[ -z "$host" || "$host" =~ ^#.*$ ]] && continue
        
        echo "Deploying to: $host"
        
        # Copy this script to remote host and execute
        ssh "$host" "bash -s" << EOF
#!/bin/bash
# Remote deployment of file protection policy: $policy

# Create directories
mkdir -p /etc/macfleet/{file_policies,reports,compliance,audit,backups}

# Apply the policy (simplified for remote execution)
$(declare -p FILE_CATEGORIES)
$(declare -p PROTECTION_LEVELS)
$(declare -p SECURITY_POLICIES)
$(type apply_security_policy | sed '1d')

apply_security_policy "$policy"
EOF
        
        if [[ $? -eq 0 ]]; then
            log_action "Successfully deployed to: $host"
        else
            log_action "Failed to deploy to: $host"
        fi
        
    done < "$fleet_file"
    
    log_action "Fleet deployment completed"
}

# Main execution function
main() {
    create_directories
    
    case "${1:-}" in
        "apply_policy")
            apply_security_policy "$2"
            ;;
        "protect_file")
            protect_file "$2" "${3:-moderate}" "manual"
            ;;
        "unprotect_file")
            unprotect_file "$2" "${3:-manual_unlock}"
            ;;
        "protect_category")
            protect_category "$2" "${3:-moderate}" "manual"
            ;;
        "bulk_protect")
            bulk_protect_files "$2" "${3:-moderate}" "bulk_operation"
            ;;
        "protect_system")
            protect_system_files "${2:-standard}"
            ;;
        "monitor_integrity")
            monitor_file_integrity "${2:-standard}"
            ;;
        "emergency_unlock")
            emergency_unlock "${2:-manual}" "${3:-all}"
            ;;
        "health_check")
            perform_health_check
            ;;
        "report")
            generate_compliance_report "${2:-manual}"
            ;;
        "deploy")
            deploy_to_fleet "$2" "$3"
            ;;
        "help"|*)
            echo "MacFleet Enterprise File Protection System"
            echo ""
            echo "Usage: $0 <command> [options]"
            echo ""
            echo "Commands:"
            echo "  apply_policy <policy>           - Apply security policy (enterprise_lockdown|standard_protection|development_safe|minimal_security|maintenance_mode)"
            echo "  protect_file <path> [level]     - Protect single file (maximum|high|moderate|minimal|readonly)"
            echo "  unprotect_file <path> [reason]  - Remove protection from file"
            echo "  protect_category <category> [level] - Protect file category (critical_apps|business_apps|system_configs|security_tools|development_tools|admin_utilities)"
            echo "  bulk_protect <file_list> [level] - Protect files from list"
            echo "  protect_system [mode]           - Protect system files (lockdown|standard|minimal)"
            echo "  monitor_integrity [mode]        - Monitor file integrity (standard|strict)"
            echo "  emergency_unlock <reason> [scope] - Emergency unlock (all|system|applications)"
            echo "  health_check                    - Perform system health check"
            echo "  report [policy]                 - Generate compliance report"
            echo "  deploy <policy> <fleet_file>    - Deploy policy to fleet"
            echo ""
            echo "Examples:"
            echo "  $0 apply_policy enterprise_lockdown"
            echo "  $0 protect_file /Applications/Terminal.app maximum"
            echo "  $0 protect_system lockdown"
            echo "  $0 emergency_unlock 'maintenance required' system"
            echo "  $0 health_check"
            ;;
    esac
}

# Execute main function
main "$@"

Protection Levels Explained

LevelDescriptionFlags AppliedUse Case
MaximumComplete system protectionschg, uappnd, uchgCritical system files
HighStrong user protectionschg, uchgImportant applications
ModerateStandard user protectionuchgBusiness applications
MinimalBasic append protectionuappndLog files, databases
Read-onlyPrevent modificationsroConfiguration templates

File Protection Use Cases

Protect Critical Applications

# Protect system utilities from modification
./file_protection.sh protect_category critical_apps maximum

# Protect business applications
./file_protection.sh protect_category business_apps high

System Configuration Protection

# Lock down system configuration files
./file_protection.sh protect_system lockdown

# Standard system protection
./file_protection.sh protect_system standard

Development Environment Safety

# Apply development-safe policy
./file_protection.sh apply_policy development_safe

# Protect development tools with minimal restrictions
./file_protection.sh protect_category development_tools minimal

Emergency Procedures

Complete System Unlock

# Emergency unlock all files
./file_protection.sh emergency_unlock "critical_maintenance" all

# Unlock only system files
./file_protection.sh emergency_unlock "system_update" system

File Recovery

# Check protection status
ls -lO /Applications/Terminal.app

# Remove specific protection
./file_protection.sh unprotect_file /Applications/Terminal.app "maintenance"

Important Security Considerations

  • System Integrity Protection (SIP) provides additional layer beyond file flags
  • Root privileges required for system immutable flags (schg)
  • Backup protection state before making changes
  • Emergency procedures should be tested and documented
  • File integrity monitoring helps detect unauthorized changes

Compliance and Auditing

The enterprise system provides comprehensive audit trails for:

  • SOX Compliance - Financial data protection requirements
  • HIPAA Requirements - Healthcare information security
  • PCI-DSS Standards - Payment card industry data security
  • NIST Framework - Cybersecurity standards compliance
  • ISO 27001 - Information security management

Testing and Validation

Before enterprise deployment:

  1. Test protection levels on non-critical files first
  2. Verify emergency unlock procedures work correctly
  3. Confirm business applications remain functional
  4. Test integrity monitoring accuracy
  5. Validate compliance reporting completeness

This comprehensive system transforms basic file locking into an enterprise-grade protection platform with advanced security policies, compliance monitoring, and fleet management capabilities.

Tutorial

Neue Updates und Verbesserungen zu Macfleet.

Konfiguration eines GitHub Actions Runners auf einem Mac Mini (Apple Silicon)

GitHub Actions Runner

GitHub Actions ist eine leistungsstarke CI/CD-Plattform, die es Ihnen ermöglicht, Ihre Software-Entwicklungsworkflows zu automatisieren. Während GitHub gehostete Runner anbietet, bieten selbst-gehostete Runner erhöhte Kontrolle und Anpassung für Ihr CI/CD-Setup. Dieses Tutorial führt Sie durch die Einrichtung, Konfiguration und Verbindung eines selbst-gehosteten Runners auf einem Mac mini zur Ausführung von macOS-Pipelines.

Voraussetzungen

Bevor Sie beginnen, stellen Sie sicher, dass Sie haben:

  • Einen Mac mini (registrieren Sie sich bei Macfleet)
  • Ein GitHub-Repository mit Administratorrechten
  • Einen installierten Paketmanager (vorzugsweise Homebrew)
  • Git auf Ihrem System installiert

Schritt 1: Ein dediziertes Benutzerkonto erstellen

Erstellen Sie zunächst ein dediziertes Benutzerkonto für den GitHub Actions Runner:

# Das 'gh-runner' Benutzerkonto erstellen
sudo dscl . -create /Users/gh-runner
sudo dscl . -create /Users/gh-runner UserShell /bin/bash
sudo dscl . -create /Users/gh-runner RealName "GitHub runner"
sudo dscl . -create /Users/gh-runner UniqueID "1001"
sudo dscl . -create /Users/gh-runner PrimaryGroupID 20
sudo dscl . -create /Users/gh-runner NFSHomeDirectory /Users/gh-runner

# Das Passwort für den Benutzer setzen
sudo dscl . -passwd /Users/gh-runner ihr_passwort

# 'gh-runner' zur 'admin'-Gruppe hinzufügen
sudo dscl . -append /Groups/admin GroupMembership gh-runner

Wechseln Sie zum neuen Benutzerkonto:

su gh-runner

Schritt 2: Erforderliche Software installieren

Installieren Sie Git und Rosetta 2 (wenn Sie Apple Silicon verwenden):

# Git installieren, falls noch nicht installiert
brew install git

# Rosetta 2 für Apple Silicon Macs installieren
softwareupdate --install-rosetta

Schritt 3: Den GitHub Actions Runner konfigurieren

  1. Gehen Sie zu Ihrem GitHub-Repository
  2. Navigieren Sie zu Einstellungen > Actions > Runners

GitHub Actions Runner

  1. Klicken Sie auf "New self-hosted runner" (https://github.com/<username>/<repository>/settings/actions/runners/new)
  2. Wählen Sie macOS als Runner-Image und ARM64 als Architektur
  3. Folgen Sie den bereitgestellten Befehlen, um den Runner herunterzuladen und zu konfigurieren

GitHub Actions Runner

Erstellen Sie eine .env-Datei im _work-Verzeichnis des Runners:

# _work/.env Datei
ImageOS=macos15
XCODE_15_DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
  1. Führen Sie das run.sh-Skript in Ihrem Runner-Verzeichnis aus, um die Einrichtung abzuschließen.
  2. Überprüfen Sie, dass der Runner aktiv ist und auf Jobs im Terminal wartet, und überprüfen Sie die GitHub-Repository-Einstellungen für die Runner-Zuordnung und den Idle-Status.

GitHub Actions Runner

Schritt 4: Sudoers konfigurieren (Optional)

Wenn Ihre Actions Root-Privilegien benötigen, konfigurieren Sie die sudoers-Datei:

sudo visudo

Fügen Sie die folgende Zeile hinzu:

gh-runner ALL=(ALL) NOPASSWD: ALL

Schritt 5: Den Runner in Workflows verwenden

Konfigurieren Sie Ihren GitHub Actions Workflow, um den selbst-gehosteten Runner zu verwenden:

name: Beispiel-Workflow

on:
  workflow_dispatch:

jobs:
  build:
    runs-on: [self-hosted, macOS, ARM64]
    steps:
      - name: NodeJS installieren
        run: brew install node

Der Runner ist bei Ihrem Repository authentifiziert und mit self-hosted, macOS und ARM64 markiert. Verwenden Sie ihn in Ihren Workflows, indem Sie diese Labels im runs-on-Feld angeben:

runs-on: [self-hosted, macOS, ARM64]

Best Practices

  • Halten Sie Ihre Runner-Software auf dem neuesten Stand
  • Überwachen Sie regelmäßig Runner-Logs auf Probleme
  • Verwenden Sie spezifische Labels für verschiedene Runner-Typen
  • Implementieren Sie angemessene Sicherheitsmaßnahmen
  • Erwägen Sie die Verwendung mehrerer Runner für Lastverteilung

Fehlerbehebung

Häufige Probleme und Lösungen:

  1. Runner verbindet sich nicht:

    • Überprüfen Sie die Netzwerkverbindung
    • Überprüfen Sie die Gültigkeit des GitHub-Tokens
    • Stellen Sie angemessene Berechtigungen sicher
  2. Build-Fehler:

    • Überprüfen Sie die Xcode-Installation
    • Überprüfen Sie erforderliche Abhängigkeiten
    • Überprüfen Sie Workflow-Logs
  3. Berechtigungsprobleme:

    • Überprüfen Sie Benutzerberechtigungen
    • Überprüfen Sie sudoers-Konfiguration
    • Überprüfen Sie Dateisystem-Berechtigungen

Fazit

Sie haben jetzt einen selbst-gehosteten GitHub Actions Runner auf Ihrem Mac mini konfiguriert. Diese Einrichtung bietet Ihnen mehr Kontrolle über Ihre CI/CD-Umgebung und ermöglicht es Ihnen, macOS-spezifische Workflows effizient auszuführen.

Denken Sie daran, Ihren Runner regelmäßig zu warten und ihn mit den neuesten Sicherheitspatches und Software-Versionen auf dem neuesten Stand zu halten.

Native App

Macfleet native App

Macfleet Installationsanleitung

Macfleet ist eine leistungsstarke Flottenmanagement-Lösung, die speziell für Cloud-gehostete Mac Mini-Umgebungen entwickelt wurde. Als Mac Mini Cloud-Hosting-Anbieter können Sie Macfleet verwenden, um Ihre gesamte Flotte virtualisierter Mac-Instanzen zu überwachen, zu verwalten und zu optimieren.

Diese Installationsanleitung führt Sie durch die Einrichtung der Macfleet-Überwachung auf macOS-, Windows- und Linux-Systemen, um eine umfassende Übersicht über Ihre Cloud-Infrastruktur zu gewährleisten.

🍎 macOS

  • Laden Sie die .dmg-Datei für Mac hier herunter
  • Doppelklicken Sie auf die heruntergeladene .dmg-Datei
  • Ziehen Sie die Macfleet-App in den Anwendungsordner
  • Werfen Sie die .dmg-Datei aus
  • Öffnen Sie Systemeinstellungen > Sicherheit & Datenschutz
    • Datenschutz-Tab > Bedienungshilfen
    • Aktivieren Sie Macfleet, um Überwachung zu erlauben
  • Starten Sie Macfleet aus den Anwendungen
  • Die Verfolgung startet automatisch

🪟 Windows

  • Laden Sie die .exe-Datei für Windows hier herunter
  • Rechtsklick auf die .exe-Datei > "Als Administrator ausführen"
  • Folgen Sie dem Installationsassistenten
  • Akzeptieren Sie die Allgemeinen Geschäftsbedingungen
  • Erlauben Sie in Windows Defender, wenn aufgefordert
  • Gewähren Sie Anwendungsüberwachungsberechtigungen
  • Starten Sie Macfleet aus dem Startmenü
  • Die Anwendung beginnt automatisch mit der Verfolgung

🐧 Linux

  • Laden Sie das .deb-Paket (Ubuntu/Debian) oder .rpm (CentOS/RHEL) hier herunter
  • Installieren Sie mit Ihrem Paketmanager
    • Ubuntu/Debian: sudo dpkg -i Macfleet-linux.deb
    • CentOS/RHEL: sudo rpm -ivh Macfleet-linux.rpm
  • Erlauben Sie X11-Zugriffsberechtigungen, wenn aufgefordert
  • Fügen Sie den Benutzer zu entsprechenden Gruppen hinzu, falls erforderlich
  • Starten Sie Macfleet aus dem Anwendungsmenü
  • Die Anwendung beginnt automatisch mit der Verfolgung

Hinweis: Nach der Installation auf allen Systemen melden Sie sich mit Ihren Macfleet-Anmeldedaten an, um Daten mit Ihrem Dashboard zu synchronisieren.