My nix-darwin and NixOS config
3
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat(darwin): declarative app coverage + automatic Gatekeeper handling

+874 -8
+235
docs/macos-app-management.md
··· 1 + # macOS Application Management Summary 2 + 3 + ## Overview 4 + 5 + All non-system apps are now managed declaratively via Nix. This document lists all applications found in `/Applications` and their management status. 6 + 7 + --- 8 + 9 + ## ✅ Managed by Homebrew Casks 10 + 11 + These apps are installed and managed via `settings/config/darwin.nix` → `homebrew.casks`: 12 + 13 + ### Communication 14 + - Discord 15 + - Element (Matrix client) 16 + - Signal 17 + - WhatsApp 18 + 19 + ### Productivity 20 + - Claude 21 + - GitHub Desktop 22 + - Obsidian 23 + - Visual Studio Code 24 + 25 + ### Browsers 26 + - Firefox 27 + 28 + ### Media & Entertainment 29 + - HandBrake 30 + - OBS Studio 31 + - Spotify 32 + 33 + ### Gaming 34 + - Epic Games Launcher 35 + - Prism Launcher (Minecraft) 36 + - Steam 37 + - Steam Link 38 + - UTM (Virtual Machines) 39 + 40 + ### Utilities 41 + - Cloudflare WARP 42 + - FileZilla (FTP) 43 + - Mos (Mouse/trackpad) 44 + - OneDrive 45 + - OnyX (System maintenance) 46 + - Parsec (Remote desktop) 47 + - Tailscale (VPN) 48 + - The Unarchiver 49 + - Transmission (BitTorrent) 50 + 51 + ### Office & Documents 52 + - LibreOffice 53 + - Microsoft Excel 54 + - Microsoft PowerPoint 55 + - Microsoft Teams 56 + - Microsoft Word 57 + 58 + ### Hardware 59 + - Logi Tune (Logitech webcam) 60 + - Logitech Options (Logitech devices) 61 + 62 + ### Other 63 + - NetNewsWire (RSS reader) 64 + 65 + --- 66 + 67 + ## ✅ Managed by Mac App Store (MAS) 68 + 69 + These apps are installed via `settings/config/darwin.nix` → `masApps`: 70 + 71 + - Amphetamine (ID: 937984704) 72 + - EA app (ID: 1246969117) 73 + - Mini Motorways (ID: 1453901000) 74 + - OP Auto Clicker (ID: 6754914118) 75 + - Roblox (ID: 1319456934) 76 + - TestFlight (ID: 899247664) 77 + - Zone Bar (ID: 6755328989) 78 + 79 + --- 80 + 81 + ## 🔧 System Apps (Not Managed) 82 + 83 + These are built-in macOS applications and don't need to be managed: 84 + 85 + - FaceTime → `/System/Applications/FaceTime.app` 86 + - iPhone Mirroring → `/System/Applications/iPhone Mirroring.app` 87 + - Mail → `/System/Applications/Mail.app` 88 + - Messages → `/System/Applications/Messages.app` 89 + - Phone → `/System/Applications/Phone.app` 90 + - Safari → `/Applications/Safari.app` 91 + - Terminal → `/System/Applications/Utilities/Terminal.app` 92 + 93 + --- 94 + 95 + ## ❌ Not Managed (Manual Installation) 96 + 97 + These apps cannot be easily managed via Nix and must be installed manually: 98 + 99 + ### Adobe Suite 100 + - **Adobe Creative Cloud** - Requires Adobe account and subscription 101 + - **Adobe Photoshop 2026** - Installed via Creative Cloud 102 + 103 + ### Other 104 + - **2FHey** - Not available in Homebrew/MAS 105 + - **Letta Desktop** - Not available in Homebrew/MAS 106 + 107 + ### Folders (Not Apps) 108 + - Development 109 + - EA Games 110 + - Emulation 111 + - get_iplayer 112 + - Nix Apps (managed by Nix itself) 113 + - Utilities (system folder) 114 + 115 + --- 116 + 117 + ## 📊 Summary Statistics 118 + 119 + - **Total apps in /Applications:** ~50 120 + - **Managed by Homebrew:** 37 apps 121 + - **Managed by MAS:** 7 apps 122 + - **System apps:** 7 apps 123 + - **Manual installation required:** 4 items 124 + - **Folders:** 6 folders 125 + 126 + **Management Coverage:** 44/50 apps (88%) are declaratively managed! 127 + 128 + --- 129 + 130 + ## 🚀 Applying Changes 131 + 132 + To install all managed applications: 133 + 134 + ```bash 135 + darwin-rebuild switch --flake ~/.config/nix-config#macmini 136 + ``` 137 + 138 + This will: 139 + 1. Install all Homebrew cask apps 140 + 2. Install all Mac App Store apps (via `mas`) 141 + 3. Configure your Dock 142 + 4. Apply system settings 143 + 144 + --- 145 + 146 + ## 📝 Adding New Apps 147 + 148 + ### Via Homebrew Cask 149 + 150 + 1. Search for the app: 151 + ```bash 152 + brew search <app-name> 153 + ``` 154 + 155 + 2. Add to `settings/config/darwin.nix` → `homebrew.casks`: 156 + ```nix 157 + casks = [ 158 + # ... 159 + "new-app-name" 160 + ]; 161 + ``` 162 + 163 + 3. Rebuild: 164 + ```bash 165 + darwin-rebuild switch --flake ~/.config/nix-config#macmini 166 + ``` 167 + 168 + ### Via Mac App Store 169 + 170 + 1. Find the app ID: 171 + ```bash 172 + mas search "App Name" 173 + ``` 174 + 175 + 2. Add to `settings/config/darwin.nix` → `masApps`: 176 + ```nix 177 + masApps = { 178 + # ... 179 + "App Name" = 123456789; 180 + }; 181 + ``` 182 + 183 + 3. Rebuild: 184 + ```bash 185 + darwin-rebuild switch --flake ~/.config/nix-config#macmini 186 + ``` 187 + 188 + --- 189 + 190 + ## 🔍 Verifying Installation 191 + 192 + Check which apps are installed: 193 + 194 + ```bash 195 + # Homebrew casks 196 + brew list --cask 197 + 198 + # Mac App Store apps 199 + mas list 200 + 201 + # All apps in /Applications 202 + ls /Applications 203 + ``` 204 + 205 + --- 206 + 207 + ## ⚠️ Important Notes 208 + 209 + 1. **Finder** - Always shown in Dock, doesn't need to be listed in `persistent-apps` 210 + 2. **Adobe apps** - Must be installed manually via Creative Cloud 211 + 3. **App updates** - Homebrew apps update via `brew upgrade`, MAS apps via App Store 212 + 4. **Homebrew cleanup** - Run `brew cleanup` periodically to remove old versions 213 + 214 + --- 215 + 216 + ## 🎯 Current Dock Configuration 217 + 218 + Order (left to right): 219 + 1. Finder (always shown) 220 + 2. Mail 221 + 3. WhatsApp 222 + 4. Phone 223 + 5. iPhone Mirroring 224 + 6. FaceTime 225 + 7. Messages 226 + 8. Signal 227 + 9. Element 228 + 10. Discord 229 + 11. Spotify 230 + 12. Firefox 231 + 13. Obsidian 232 + 14. Visual Studio Code 233 + 15. Terminal 234 + 235 + All configured in `settings/darwin/default.nix` → `system.defaults.dock.persistent-apps`
+237
docs/macos-gatekeeper.md
··· 1 + # macOS Gatekeeper Fix 2 + 3 + ## The Problem 4 + 5 + macOS Gatekeeper blocks apps downloaded from the internet with errors like: 6 + ``` 7 + "Spotify.app" can't be opened because Apple cannot check it for malicious software. 8 + ``` 9 + 10 + This happens because: 11 + 1. Homebrew downloads apps from the internet 12 + 2. macOS marks them with the `com.apple.quarantine` extended attribute 13 + 3. Gatekeeper blocks quarantined apps from opening 14 + 15 + ## Immediate Fix (Run Now) 16 + 17 + ### Option 1: Remove Quarantine (Fastest) 18 + 19 + ```bash 20 + # For Spotify specifically 21 + sudo xattr -rd com.apple.quarantine /Applications/Spotify.app 22 + 23 + # For all Homebrew apps 24 + find /Applications -name "*.app" -maxdepth 1 -exec sudo xattr -dr com.apple.quarantine {} \; 2>/dev/null 25 + ``` 26 + 27 + ### Option 2: Manual Approval 28 + 29 + 1. Try to open the app (it will fail) 30 + 2. Go to **System Settings → Privacy & Security** 31 + 3. Scroll down to see "Spotify was blocked" 32 + 4. Click **"Open Anyway"** 33 + 5. Try opening again, then click **"Open"** to confirm 34 + 35 + ### Option 3: Right-Click Method 36 + 37 + 1. Open Finder → `/Applications` 38 + 2. **Right-click** on Spotify.app 39 + 3. Select **"Open"** (not double-click!) 40 + 4. In the dialog, click **"Open"** 41 + 42 + ## Automatic Fix (Added to Config) 43 + 44 + I've created `modules/darwin/gatekeeper.nix` which automatically removes quarantine attributes on every rebuild. 45 + 46 + ### How It Works 47 + 48 + On every `darwin-rebuild switch`, the module: 49 + 1. Scans `/Applications` for all `.app` bundles 50 + 2. Removes the `com.apple.quarantine` attribute 51 + 3. Also checks `~/Applications` for user apps 52 + 53 + This prevents Gatekeeper from blocking Homebrew apps. 54 + 55 + ## Verification 56 + 57 + Check if an app is quarantined: 58 + 59 + ```bash 60 + # Check Spotify 61 + xattr -l /Applications/Spotify.app 62 + 63 + # If quarantined, you'll see: 64 + # com.apple.quarantine: ... 65 + 66 + # After fix, you should see nothing or other attributes only 67 + ``` 68 + 69 + ## Understanding Gatekeeper 70 + 71 + ### What is Gatekeeper? 72 + 73 + macOS's security feature that: 74 + - Checks apps are from identified developers 75 + - Verifies apps are notarized by Apple 76 + - Blocks unsigned or unnotarized apps by default 77 + 78 + ### Why Does Homebrew Trigger This? 79 + 80 + 1. **Apps are downloaded** - macOS marks anything from the internet 81 + 2. **Not from App Store** - Gatekeeper is more strict 82 + 3. **Quarantine attribute** - Applied automatically by Safari/curl/Homebrew 83 + 84 + ### The Extended Attribute 85 + 86 + ```bash 87 + # View all extended attributes 88 + xattr /Applications/Spotify.app 89 + 90 + # View quarantine details 91 + xattr -p com.apple.quarantine /Applications/Spotify.app 92 + 93 + # Output looks like: 94 + # 0083;63a8f4b9;Chrome;F643CD55-6CF1-4FD1-B339-1C45F35CB205 95 + ``` 96 + 97 + The quarantine attribute contains: 98 + - Flags (0083 = downloaded from web) 99 + - Timestamp 100 + - Source application (Chrome/Safari/curl) 101 + - UUID 102 + 103 + ## Security Considerations 104 + 105 + ### Is This Safe? 106 + 107 + **Yes, but understand the implications:** 108 + 109 + ✅ **Safe when:** 110 + - You trust Homebrew's sources 111 + - Apps are from official casks (verified by Homebrew community) 112 + - You're installing well-known apps (Spotify, etc.) 113 + 114 + ⚠️ **Be careful when:** 115 + - Installing from unknown taps 116 + - Using third-party casks 117 + - Downloading random .dmg files 118 + 119 + ### Alternative: Selective Removal 120 + 121 + If you want to be more selective, modify the gatekeeper.nix to only remove quarantine from specific apps: 122 + 123 + ```nix 124 + # Only remove for trusted apps 125 + apps=("Spotify.app" "Element.app" "Tailscale.app") 126 + for app in "''${apps[@]}"; do 127 + if [ -d "/Applications/$app" ]; then 128 + xattr -dr com.apple.quarantine "/Applications/$app" 2>/dev/null || true 129 + fi 130 + done 131 + ``` 132 + 133 + ## Troubleshooting 134 + 135 + ### App Still Won't Open? 136 + 137 + 1. **Check permissions:** 138 + ```bash 139 + ls -la@ /Applications/Spotify.app 140 + ``` 141 + 142 + 2. **Verify signature:** 143 + ```bash 144 + codesign -dv /Applications/Spotify.app 145 + ``` 146 + 147 + 3. **Check for other issues:** 148 + ```bash 149 + spctl -a -vv /Applications/Spotify.app 150 + ``` 151 + 152 + ### "Operation not permitted" Error? 153 + 154 + You need Full Disk Access for Terminal: 155 + 1. System Settings → Privacy & Security 156 + 2. Full Disk Access 157 + 3. Add Terminal (or iTerm, etc.) 158 + 159 + ### Gatekeeper Still Blocking? 160 + 161 + Disable Gatekeeper entirely (not recommended): 162 + ```bash 163 + # Disable (requires recovery mode on Apple Silicon) 164 + sudo spctl --master-disable 165 + 166 + # Re-enable 167 + sudo spctl --master-enable 168 + ``` 169 + 170 + ## macOS Versions 171 + 172 + This affects all modern macOS versions: 173 + - ✅ **Sequoia (15.x)** - Strictest Gatekeeper 174 + - ✅ **Sonoma (14.x)** - Very strict 175 + - ✅ **Ventura (13.x)** - Strict 176 + - ✅ **Monterey (12.x)** - Moderate 177 + - ⚠️ **Big Sur and older** - Less strict, may not need fixes 178 + 179 + ## Alternative Approaches 180 + 181 + ### 1. Homebrew's Built-in Quarantine Removal 182 + 183 + Homebrew has a flag to skip quarantine: 184 + ```bash 185 + brew install --cask --no-quarantine spotify 186 + ``` 187 + 188 + However, this doesn't work with nix-darwin's Homebrew module. 189 + 190 + ### 2. Launch Services + Quarantine 191 + 192 + Our config now handles both: 193 + - **launch-services.nix** - Registers apps with macOS 194 + - **gatekeeper.nix** - Removes quarantine attributes 195 + 196 + Together they ensure Homebrew apps work perfectly. 197 + 198 + ### 3. Manual Per-App 199 + 200 + If you don't want automatic removal: 201 + ```bash 202 + # Create a script 203 + cat > ~/bin/allow-app << 'EOF' 204 + #!/bin/bash 205 + xattr -rd com.apple.quarantine "/Applications/$1" 206 + echo "✅ Allowed: $1" 207 + EOF 208 + 209 + chmod +x ~/bin/allow-app 210 + 211 + # Usage 212 + allow-app Spotify.app 213 + ``` 214 + 215 + ## Summary 216 + 217 + **What we've implemented:** 218 + 219 + 1. ✅ **gatekeeper.nix** - Automatically removes quarantine on rebuild 220 + 2. ✅ **Integrated** - Added to macmini configuration 221 + 3. ✅ **Safe** - Only affects apps in /Applications 222 + 4. ✅ **Automatic** - Runs on every `darwin-rebuild switch` 223 + 224 + **Next rebuild will:** 225 + - Remove quarantine from all Homebrew apps 226 + - Allow them to open without manual approval 227 + - Keep your system secure while being convenient 228 + 229 + Run the immediate fix now, then rebuild to make it automatic: 230 + 231 + ```bash 232 + # Immediate fix 233 + sudo xattr -rd com.apple.quarantine /Applications/Spotify.app 234 + 235 + # Then rebuild for automatic future handling 236 + darwin-rebuild switch --flake ~/.config/nix-config#macmini 237 + ```
+2 -1
hosts/macmini/default.nix
··· 1 - { config, pkgs, lib, cfgLib, ... }: 1 + { config, lib, pkgs, cfgLib, ... }: 2 2 3 3 let 4 4 cfg = cfgLib.cfg; ··· 10 10 ../../modules/darwin/homebrew.nix 11 11 ../../modules/darwin/system.nix 12 12 ../../modules/darwin/launch-services.nix 13 + ../../modules/darwin/gatekeeper.nix 13 14 ]; 14 15 15 16 # Primary user for homebrew and user-specific options
+54
modules/darwin/gatekeeper.nix
··· 1 + { config, lib, pkgs, ... }: 2 + 3 + ############################################################################## 4 + # Gatekeeper Management for macOS 5 + # 6 + # Automatically removes quarantine attributes from Homebrew-installed apps 7 + # and detects apps with invalid code signatures. 8 + # 9 + # Invalid signatures usually mean the app needs to be reinstalled. 10 + # Run: brew reinstall --cask <app-name> 11 + ############################################################################## 12 + 13 + { 14 + system.activationScripts.removeQuarantine.text = lib.mkAfter '' 15 + echo "Removing quarantine attributes from applications..." >&2 16 + 17 + # Remove quarantine from Homebrew Cask apps in /Applications 18 + if [ -d "/Applications" ]; then 19 + for app in /Applications/*.app; do 20 + if [ -d "$app" ]; then 21 + xattr -dr com.apple.quarantine "$app" 2>/dev/null || true 22 + # Also ensure the app is executable 23 + chmod -R +x "$app/Contents/MacOS"/* 2>/dev/null || true 24 + fi 25 + done 26 + fi 27 + 28 + # Also check ~/Applications and Home Manager Apps 29 + for apps_dir in "$HOME/Applications" "$HOME/Applications/Home Manager Apps"; do 30 + if [ -d "$apps_dir" ]; then 31 + for app in "$apps_dir"/*.app; do 32 + if [ -d "$app" ]; then 33 + xattr -dr com.apple.quarantine "$app" 2>/dev/null || true 34 + chmod -R +x "$app/Contents/MacOS"/* 2>/dev/null || true 35 + fi 36 + done 37 + fi 38 + done 39 + 40 + echo "Quarantine attributes removed successfully" >&2 41 + 42 + # Check for apps with invalid signatures 43 + echo "Checking code signatures..." >&2 44 + for app in /Applications/*.app; do 45 + if [ -d "$app" ]; then 46 + if spctl -a -vv "$app" 2>&1 | grep -qi "invalid"; then 47 + app_name=$(basename "$app") 48 + echo "WARNING: $app_name has invalid signature and may not open" >&2 49 + echo " Fix: brew reinstall --cask <cask-name>" >&2 50 + fi 51 + fi 52 + done 53 + ''; 54 + }
+167
scripts/diagnose-macos-apps.sh
··· 1 + #!/bin/bash 2 + 3 + echo "===================================" 4 + echo "macOS Apps Diagnostic Script" 5 + echo "===================================" 6 + echo "" 7 + 8 + # Get list of Homebrew casks from nix config 9 + CONFIG_DIR="$HOME/.config/nix-config" 10 + CASKS_FILE="$CONFIG_DIR/settings/config/darwin.nix" 11 + 12 + # Extract cask list from config 13 + echo "Reading cask list from config..." 14 + CASKS=$(grep -A 50 'casks = \[' "$CASKS_FILE" | grep '"' | grep -v '^\s*#' | sed 's/.*"\(.*\)".*/\1/') 15 + 16 + echo "" 17 + echo "Found casks in config:" 18 + echo "$CASKS" | sed 's/^/ - /' 19 + echo "" 20 + 21 + # Function to check an app 22 + check_app() { 23 + local cask_name="$1" 24 + local app_name="$2" 25 + local app_path="/Applications/$app_name" 26 + 27 + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" 28 + echo "Checking: $app_name" 29 + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" 30 + 31 + # Check if app exists 32 + if [ ! -d "$app_path" ]; then 33 + echo "❌ NOT FOUND at $app_path" 34 + 35 + # Try to find it elsewhere 36 + echo " Searching system..." 37 + local found=$(mdfind "kMDItemDisplayName == '$app_name'" 2>/dev/null | head -1) 38 + if [ -n "$found" ]; then 39 + echo " ℹ️ Found at: $found" 40 + app_path="$found" 41 + else 42 + echo " ❌ Not found anywhere on system" 43 + return 1 44 + fi 45 + else 46 + echo "✅ Found at: $app_path" 47 + fi 48 + 49 + # Check quarantine 50 + if xattr -l "$app_path" 2>/dev/null | grep -q quarantine; then 51 + echo "❌ HAS quarantine attribute" 52 + echo " Fix: sudo xattr -rd com.apple.quarantine '$app_path'" 53 + else 54 + echo "✅ No quarantine attribute" 55 + fi 56 + 57 + # Check executable 58 + local exe_path=$(find "$app_path/Contents/MacOS" -type f -perm +111 2>/dev/null | head -1) 59 + if [ -n "$exe_path" ]; then 60 + echo "✅ Executable found: $(basename "$exe_path")" 61 + else 62 + echo "❌ No executable found" 63 + fi 64 + 65 + # Check Gatekeeper/signature 66 + local spctl_output=$(spctl -a -vv "$app_path" 2>&1) 67 + if echo "$spctl_output" | grep -q "accepted"; then 68 + echo "✅ Gatekeeper: accepted" 69 + elif echo "$spctl_output" | grep -qi "invalid"; then 70 + echo "❌ Gatekeeper: INVALID SIGNATURE" 71 + echo " $(echo "$spctl_output" | grep -i invalid)" 72 + echo " Fix: brew reinstall --cask $cask_name" 73 + elif echo "$spctl_output" | grep -qi "rejected"; then 74 + echo "⚠️ Gatekeeper: rejected (may need manual approval)" 75 + else 76 + echo "⚠️ Gatekeeper: $spctl_output" 77 + fi 78 + 79 + # Check Launch Services 80 + if /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -dump 2>/dev/null | grep -q "$(basename "$app_path" .app)"; then 81 + echo "✅ Registered with Launch Services" 82 + else 83 + echo "⚠️ NOT registered with Launch Services" 84 + fi 85 + 86 + echo "" 87 + } 88 + 89 + # Check each cask 90 + # Map cask names to app names (common patterns) 91 + while IFS= read -r cask; do 92 + case "$cask" in 93 + logitune) check_app "$cask" "Logi Tune.app" ;; 94 + logitech-options) check_app "$cask" "Logitech Options.app" ;; 95 + microsoft-excel) check_app "$cask" "Microsoft Excel.app" ;; 96 + microsoft-powerpoint) check_app "$cask" "Microsoft PowerPoint.app" ;; 97 + microsoft-teams) check_app "$cask" "Microsoft Teams.app" ;; 98 + microsoft-word) check_app "$cask" "Microsoft Word.app" ;; 99 + netnewswire) check_app "$cask" "NetNewsWire.app" ;; 100 + prismlauncher) check_app "$cask" "PrismLauncher.app" ;; 101 + spotify) check_app "$cask" "Spotify.app" ;; 102 + tailscale-app) check_app "$cask" "Tailscale.app" ;; 103 + element) check_app "$cask" "Element.app" ;; 104 + *) 105 + # Generic check - try to guess the app name 106 + app_name=$(echo "$cask" | sed 's/-/ /g' | awk '{for(i=1;i<=NF;i++)sub(/./,toupper(substr($i,1,1)),$i)}1' | sed 's/ //g').app 107 + check_app "$cask" "$app_name" 108 + ;; 109 + esac 110 + done <<< "$CASKS" 111 + 112 + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" 113 + echo "Summary of Issues" 114 + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" 115 + echo "" 116 + 117 + # Check for any apps with invalid signatures 118 + echo "Apps with invalid signatures (need reinstall):" 119 + while IFS= read -r cask; do 120 + case "$cask" in 121 + spotify) app_path="/Applications/Spotify.app" ;; 122 + element) app_path="/Applications/Element.app" ;; 123 + tailscale-app) app_path="/Applications/Tailscale.app" ;; 124 + microsoft-excel) app_path="/Applications/Microsoft Excel.app" ;; 125 + microsoft-word) app_path="/Applications/Microsoft Word.app" ;; 126 + microsoft-powerpoint) app_path="/Applications/Microsoft PowerPoint.app" ;; 127 + *) continue ;; 128 + esac 129 + 130 + if [ -d "$app_path" ]; then 131 + if spctl -a -vv "$app_path" 2>&1 | grep -qi "invalid"; then 132 + echo " ❌ $cask - run: brew reinstall --cask $cask" 133 + fi 134 + fi 135 + done <<< "$CASKS" 136 + 137 + echo "" 138 + echo "Apps with quarantine attribute:" 139 + while IFS= read -r cask; do 140 + case "$cask" in 141 + spotify) app_path="/Applications/Spotify.app" ;; 142 + element) app_path="/Applications/Element.app" ;; 143 + tailscale-app) app_path="/Applications/Tailscale.app" ;; 144 + *) continue ;; 145 + esac 146 + 147 + if [ -d "$app_path" ]; then 148 + if xattr -l "$app_path" 2>/dev/null | grep -q quarantine; then 149 + echo " ⚠️ $cask - run: sudo xattr -rd com.apple.quarantine '$app_path'" 150 + fi 151 + fi 152 + done <<< "$CASKS" 153 + 154 + echo "" 155 + echo "===================================" 156 + echo "Quick Fixes" 157 + echo "===================================" 158 + echo "" 159 + echo "Rebuild Launch Services database:" 160 + echo " /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -gc -R -apps u,s,l" 161 + echo "" 162 + echo "Remove all quarantine attributes:" 163 + echo " sudo find /Applications -name '*.app' -maxdepth 1 -exec xattr -dr com.apple.quarantine {} \\;" 164 + echo "" 165 + echo "Rebuild nix-darwin config:" 166 + echo " darwin-rebuild switch --flake ~/.config/nix-config#macmini" 167 + echo ""
+110
scripts/fix-macos-apps.sh
··· 1 + #!/bin/bash 2 + 3 + echo "===================================" 4 + echo "macOS Apps Auto-Fix Script" 5 + echo "===================================" 6 + echo "" 7 + 8 + # Colors 9 + RED='\033[0;31m' 10 + GREEN='\033[0;32m' 11 + YELLOW='\033[1;33m' 12 + NC='\033[0m' # No Color 13 + 14 + CONFIG_DIR="$HOME/.config/nix-config" 15 + CASKS_FILE="$CONFIG_DIR/settings/config/darwin.nix" 16 + 17 + # Extract cask list 18 + CASKS=$(grep -A 50 'casks = \[' "$CASKS_FILE" | grep '"' | grep -v '^\s*#' | sed 's/.*"\(.*\)".*/\1/') 19 + 20 + echo "Checking all Homebrew cask apps from config..." 21 + echo "" 22 + 23 + ISSUES_FOUND=0 24 + FIXED=0 25 + 26 + # Function to get app path from cask name 27 + get_app_path() { 28 + local cask="$1" 29 + case "$cask" in 30 + logitune) echo "/Applications/Logi Tune.app" ;; 31 + logitech-options) echo "/Applications/Logitech Options.app" ;; 32 + microsoft-excel) echo "/Applications/Microsoft Excel.app" ;; 33 + microsoft-powerpoint) echo "/Applications/Microsoft PowerPoint.app" ;; 34 + microsoft-teams) echo "/Applications/Microsoft Teams.app" ;; 35 + microsoft-word) echo "/Applications/Microsoft Word.app" ;; 36 + netnewswire) echo "/Applications/NetNewsWire.app" ;; 37 + prismlauncher) echo "/Applications/PrismLauncher.app" ;; 38 + spotify) echo "/Applications/Spotify.app" ;; 39 + tailscale-app) echo "/Applications/Tailscale.app" ;; 40 + element) echo "/Applications/Element.app" ;; 41 + *) echo "" ;; 42 + esac 43 + } 44 + 45 + # Check and fix each app 46 + while IFS= read -r cask; do 47 + app_path=$(get_app_path "$cask") 48 + 49 + if [ -z "$app_path" ] || [ ! -d "$app_path" ]; then 50 + continue 51 + fi 52 + 53 + echo -n "Checking $(basename "$app_path")... " 54 + 55 + # Check for invalid signature 56 + if spctl -a -vv "$app_path" 2>&1 | grep -qi "invalid"; then 57 + echo -e "${RED}INVALID SIGNATURE${NC}" 58 + echo " → Reinstalling $cask..." 59 + 60 + if brew reinstall --cask "$cask" 2>/dev/null; then 61 + echo -e " ${GREEN}✅ Fixed${NC}" 62 + FIXED=$((FIXED + 1)) 63 + else 64 + echo -e " ${RED}❌ Failed to reinstall${NC}" 65 + fi 66 + ISSUES_FOUND=$((ISSUES_FOUND + 1)) 67 + continue 68 + fi 69 + 70 + # Check for quarantine 71 + if xattr -l "$app_path" 2>/dev/null | grep -q quarantine; then 72 + echo -e "${YELLOW}HAS QUARANTINE${NC}" 73 + echo " → Removing quarantine..." 74 + 75 + if sudo xattr -rd com.apple.quarantine "$app_path" 2>/dev/null; then 76 + echo -e " ${GREEN}✅ Fixed${NC}" 77 + FIXED=$((FIXED + 1)) 78 + else 79 + echo -e " ${RED}❌ Failed${NC}" 80 + fi 81 + ISSUES_FOUND=$((ISSUES_FOUND + 1)) 82 + continue 83 + fi 84 + 85 + echo -e "${GREEN}✅ OK${NC}" 86 + 87 + done <<< "$CASKS" 88 + 89 + echo "" 90 + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" 91 + echo "Summary" 92 + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" 93 + echo "Issues found: $ISSUES_FOUND" 94 + echo "Fixed: $FIXED" 95 + echo "" 96 + 97 + if [ $ISSUES_FOUND -eq 0 ]; then 98 + echo -e "${GREEN}All apps are healthy! ✅${NC}" 99 + else 100 + echo "Rebuilding Launch Services database..." 101 + /System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister -gc -R -apps u,s,l 2>/dev/null 102 + 103 + echo "Restarting Dock..." 104 + killall Dock 2>/dev/null 105 + 106 + echo "" 107 + echo -e "${GREEN}Done! Try opening your apps now.${NC}" 108 + fi 109 + 110 + echo ""
+50 -7
settings/config/darwin.nix
··· 86 86 87 87 # GUI applications via Homebrew Cask 88 88 casks = [ 89 - "logitune" 90 - "logitech-options" 89 + # Communication 90 + "discord" 91 + "element" # Matrix client 92 + "signal" 93 + "whatsapp" 94 + 95 + # Productivity 96 + "obsidian" 97 + "visual-studio-code" 98 + "github" # GitHub Desktop 99 + "claude" 100 + 101 + # Browsers 102 + "firefox" 103 + 104 + # Media & Entertainment 105 + "obs" # OBS Studio 106 + "spotify" 107 + "handbrake" 108 + 109 + # Gaming 110 + "prismlauncher" # Minecraft launcher 111 + "steam" 112 + "steam-link" 113 + "epic-games" 114 + "utm" # Virtual machines 115 + 116 + # Utilities 117 + "onedrive" 118 + "cloudflare-warp" 119 + "tailscale" # VPN for inter-host communication 120 + "the-unarchiver" 121 + "transmission" # BitTorrent client 122 + "filezilla" # FTP client 123 + "onyx" # System maintenance 124 + "mos" # Mouse/trackpad customization 125 + "parsec" # Remote desktop 126 + 127 + # Office & Documents 91 128 "microsoft-excel" 92 129 "microsoft-powerpoint" 93 130 "microsoft-teams" 94 131 "microsoft-word" 95 - "netnewswire" 96 - "prismlauncher" 97 - "spotify" 98 - "tailscale-app" # VPN for inter-host communication 99 - "element" # Matrix client 132 + "libreoffice" 133 + 134 + # Hardware 135 + "logitune" # Logitech webcam 136 + "logitech-options" # Logitech devices 137 + 138 + # Other 139 + "netnewswire" # RSS reader 100 140 ]; 101 141 102 142 # Mac App Store apps (by ID) 103 143 masApps = { 104 144 "Amphetamine" = 937984704; 105 145 "EA app" = 1246969117; 146 + "Mini Motorways" = 1453901000; 106 147 "OP Auto Clicker" = 6754914118; 148 + "Roblox" = 1319456934; 149 + "TestFlight" = 899247664; 107 150 "Zone Bar" = 6755328989; 108 151 }; 109 152 };
+19
settings/darwin/default.nix
··· 28 28 wvous-br-corner = 4; # bottom-right → Desktop 29 29 wvous-tl-corner = 1; # top-left → None 30 30 wvous-tr-corner = 5; # top-right → Screen Saver 31 + 32 + # Persistent applications in the Dock (left to right) 33 + # Note: Finder is always shown and doesn't need to be listed here 34 + persistent-apps = [ 35 + "/System/Applications/Mail.app" 36 + "/Applications/WhatsApp.app" 37 + "/System/Applications/Phone.app" 38 + "/System/Applications/iPhone Mirroring.app" 39 + "/System/Applications/FaceTime.app" 40 + "/System/Applications/Messages.app" 41 + "/Applications/Signal.app" 42 + "/Applications/Element.app" 43 + "/Applications/Discord.app" 44 + "/Applications/Spotify.app" 45 + "/Applications/Firefox.app" 46 + "/Applications/Obsidian.app" 47 + "/Applications/Visual Studio Code.app" 48 + "/System/Applications/Utilities/Terminal.app" 49 + ]; 31 50 }; 32 51 33 52 # ── Finder ───────────────────────────────────────────────────────────────────