Tutorial

Novas atualizações e melhorias para a Macfleet.

Aviso importante

Os exemplos de código e scripts fornecidos nestes tutoriais são apenas para fins educacionais. A Macfleet não é responsável por quaisquer problemas, danos ou vulnerabilidades de segurança que possam surgir do uso, modificação ou implementação destes exemplos. Sempre revise e teste o código em um ambiente seguro antes de usá-lo em sistemas de produção.

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

Novas atualizações e melhorias para a Macfleet.

Configurando um Runner do GitHub Actions em um Mac Mini (Apple Silicon)

Runner do GitHub Actions

GitHub Actions é uma plataforma poderosa de CI/CD que permite automatizar seus fluxos de trabalho de desenvolvimento de software. Embora o GitHub ofereça runners hospedados, runners auto-hospedados fornecem maior controle e personalização para sua configuração de CI/CD. Este tutorial o guia através da configuração e conexão de um runner auto-hospedado em um Mac mini para executar pipelines do macOS.

Pré-requisitos

Antes de começar, certifique-se de ter:

  • Um Mac mini (registre-se no Macfleet)
  • Um repositório GitHub com direitos de administrador
  • Um gerenciador de pacotes instalado (preferencialmente Homebrew)
  • Git instalado em seu sistema

Passo 1: Criar uma Conta de Usuário Dedicada

Primeiro, crie uma conta de usuário dedicada para o runner do GitHub Actions:

# Criar a conta de usuário 'gh-runner'
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

# Definir a senha para o usuário
sudo dscl . -passwd /Users/gh-runner sua_senha

# Adicionar 'gh-runner' ao grupo 'admin'
sudo dscl . -append /Groups/admin GroupMembership gh-runner

Mude para a nova conta de usuário:

su gh-runner

Passo 2: Instalar Software Necessário

Instale Git e Rosetta 2 (se estiver usando Apple Silicon):

# Instalar Git se ainda não estiver instalado
brew install git

# Instalar Rosetta 2 para Macs Apple Silicon
softwareupdate --install-rosetta

Passo 3: Configurar o Runner do GitHub Actions

  1. Vá para seu repositório GitHub
  2. Navegue para Configurações > Actions > Runners

Runner do GitHub Actions

  1. Clique em "New self-hosted runner" (https://github.com/<username>/<repository>/settings/actions/runners/new)
  2. Selecione macOS como imagem do runner e ARM64 como arquitetura
  3. Siga os comandos fornecidos para baixar e configurar o runner

Runner do GitHub Actions

Crie um arquivo .env no diretório _work do runner:

# arquivo _work/.env
ImageOS=macos15
XCODE_15_DEVELOPER_DIR=/Applications/Xcode.app/Contents/Developer
  1. Execute o script run.sh em seu diretório do runner para completar a configuração.
  2. Verifique se o runner está ativo e ouvindo por trabalhos no terminal e verifique as configurações do repositório GitHub para a associação do runner e status Idle.

Runner do GitHub Actions

Passo 4: Configurar Sudoers (Opcional)

Se suas ações requerem privilégios de root, configure o arquivo sudoers:

sudo visudo

Adicione a seguinte linha:

gh-runner ALL=(ALL) NOPASSWD: ALL

Passo 5: Usar o Runner em Fluxos de Trabalho

Configure seu fluxo de trabalho do GitHub Actions para usar o runner auto-hospedado:

name: Fluxo de trabalho de exemplo

on:
  workflow_dispatch:

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

O runner está autenticado em seu repositório e rotulado com self-hosted, macOS, e ARM64. Use-o em seus fluxos de trabalho especificando estes rótulos no campo runs-on:

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

Melhores Práticas

  • Mantenha seu software do runner atualizado
  • Monitore regularmente os logs do runner para problemas
  • Use rótulos específicos para diferentes tipos de runners
  • Implemente medidas de segurança adequadas
  • Considere usar múltiplos runners para balanceamento de carga

Solução de Problemas

Problemas comuns e soluções:

  1. Runner não conectando:

    • Verifique conectividade de rede
    • Verifique validade do token GitHub
    • Certifique-se de permissões adequadas
  2. Falhas de build:

    • Verifique instalação do Xcode
    • Verifique dependências necessárias
    • Revise logs do fluxo de trabalho
  3. Problemas de permissão:

    • Verifique permissões do usuário
    • Verifique configuração sudoers
    • Revise permissões do sistema de arquivos

Conclusão

Agora você tem um runner auto-hospedado do GitHub Actions configurado em seu Mac mini. Esta configuração fornece mais controle sobre seu ambiente CI/CD e permite executar fluxos de trabalho específicos do macOS de forma eficiente.

Lembre-se de manter regularmente seu runner e mantê-lo atualizado com os patches de segurança e versões de software mais recentes.

Aplicativo Nativo

Aplicativo nativo do Macfleet

Guia de Instalação do Macfleet

Macfleet é uma solução poderosa de gerenciamento de frota projetada especificamente para ambientes Mac Mini hospedados na nuvem. Como provedor de hospedagem na nuvem Mac Mini, você pode usar o Macfleet para monitorar, gerenciar e otimizar toda sua frota de instâncias Mac virtualizadas.

Este guia de instalação o conduzirá através da configuração do monitoramento do Macfleet em sistemas macOS, Windows e Linux para garantir supervisão abrangente de sua infraestrutura na nuvem.

🍎 macOS

  • Baixe o arquivo .dmg para Mac aqui
  • Clique duas vezes no arquivo .dmg baixado
  • Arraste o aplicativo Macfleet para a pasta Aplicativos
  • Ejete o arquivo .dmg
  • Abra Preferências do Sistema > Segurança e Privacidade
    • Aba Privacidade > Acessibilidade
    • Marque Macfleet para permitir monitoramento
  • Inicie o Macfleet a partir de Aplicativos
  • O rastreamento inicia automaticamente

🪟 Windows

  • Baixe o arquivo .exe para Windows aqui
  • Clique com o botão direito no arquivo .exe > "Executar como administrador"
  • Siga o assistente de instalação
  • Aceite os termos e condições
  • Permita no Windows Defender se solicitado
  • Conceda permissões de monitoramento de aplicativo
  • Inicie o Macfleet a partir do Menu Iniciar
  • O aplicativo começa o rastreamento automaticamente

🐧 Linux

  • Baixe o pacote .deb (Ubuntu/Debian) ou .rpm (CentOS/RHEL) aqui
  • Instale usando seu gerenciador de pacotes
    • Ubuntu/Debian: sudo dpkg -i Macfleet-linux.deb
    • CentOS/RHEL: sudo rpm -ivh Macfleet-linux.rpm
  • Permita permissões de acesso X11 se solicitado
  • Adicione o usuário aos grupos apropriados se necessário
  • Inicie o Macfleet a partir do menu Aplicativos
  • O aplicativo começa o rastreamento automaticamente

Nota: Após a instalação em todos os sistemas, faça login com suas credenciais do Macfleet para sincronizar dados com seu painel de controle.