diff --git a/modules/darwin/common.nix b/modules/darwin/common.nix index 134e780..69490a3 100644 --- a/modules/darwin/common.nix +++ b/modules/darwin/common.nix @@ -15,7 +15,11 @@ in # the nix daemon itself and conflicts with nix-darwin's native management. nix.enable = false; - nix.settings.auto-optimise-store = true; + # With nix.enable = false, nix-darwin writes no /etc/nix/nix.conf at all, so + # every `nix.settings.*` here is silently discarded (verified: the darwin + # config emits no environment.etc."nix/nix.conf"). Daemon settings such as + # auto-optimise-store belong in Determinate's own config instead: + # /etc/nix/nix.custom.conf launchd.daemons.nix-collect-garbage = { serviceConfig = { diff --git a/modules/darwin/gatekeeper.nix b/modules/darwin/gatekeeper.nix index a477848..af5c123 100644 --- a/modules/darwin/gatekeeper.nix +++ b/modules/darwin/gatekeeper.nix @@ -1,54 +1,58 @@ -{ config, lib, pkgs, ... }: - ############################################################################## # Gatekeeper Management for macOS -# -# Automatically removes quarantine attributes from Homebrew-installed apps -# and detects apps with invalid code signatures. -# -# Invalid signatures usually mean the app needs to be reinstalled. -# Run: brew reinstall --cask +# +# Removes quarantine attributes from Homebrew-installed apps so they open +# without the "downloaded from the internet" prompt, and can optionally +# report apps whose code signature no longer validates. +# +# Invalid signatures usually mean the app needs to be reinstalled: +# brew reinstall --cask +# +# NOTE: this must hang off `system.activationScripts.postActivation`. +# nix-darwin only runs a fixed set of activation-script names; an entry under +# any other name (this module previously used `removeQuarantine`) is still +# evaluated and built, but never executed. See modules/darwin/common.nix. ############################################################################## +{ + config, + lib, + ... +}: +let + cfg = config.myConfig; + gk = cfg.darwin.gatekeeper; + # Activation scripts run as root, so $HOME is root's home, not the user's. + userHome = "/Users/${cfg.user.username}"; +in { - system.activationScripts.removeQuarantine.text = lib.mkAfter '' - echo "Removing quarantine attributes from applications..." >&2 - - # Remove quarantine from Homebrew Cask apps in /Applications - if [ -d "/Applications" ]; then - for app in /Applications/*.app; do - if [ -d "$app" ]; then + system.activationScripts.postActivation.text = lib.mkIf gk.enable ( + lib.mkAfter '' + echo "Removing quarantine attributes from applications..." >&2 + + for apps_dir in /Applications "${userHome}/Applications" "${userHome}/Applications/Home Manager Apps"; do + [ -d "$apps_dir" ] || continue + for app in "$apps_dir"/*.app; do + [ -d "$app" ] || continue xattr -dr com.apple.quarantine "$app" 2>/dev/null || true - # Also ensure the app is executable - chmod -R +x "$app/Contents/MacOS"/* 2>/dev/null || true - fi + done done - fi - - # Also check ~/Applications and Home Manager Apps - for apps_dir in "$HOME/Applications" "$HOME/Applications/Home Manager Apps"; do - if [ -d "$apps_dir" ]; then - for app in "$apps_dir"/*.app; do - if [ -d "$app" ]; then - xattr -dr com.apple.quarantine "$app" 2>/dev/null || true - chmod -R +x "$app/Contents/MacOS"/* 2>/dev/null || true + + echo "Quarantine attributes removed" >&2 + + ${lib.optionalString gk.checkSignatures '' + # Off by default: spctl shells out per app and adds seconds to every + # rebuild. Enable myConfig.darwin.gatekeeper.checkSignatures when an app + # is actually refusing to launch. + echo "Checking code signatures..." >&2 + for app in /Applications/*.app; do + [ -d "$app" ] || continue + if spctl -a -vv "$app" 2>&1 | grep -qi "invalid"; then + echo "WARNING: $(basename "$app") has an invalid signature and may not open" >&2 + echo " Fix: brew reinstall --cask " >&2 fi done - fi - done - - echo "Quarantine attributes removed successfully" >&2 - - # Check for apps with invalid signatures - echo "Checking code signatures..." >&2 - for app in /Applications/*.app; do - if [ -d "$app" ]; then - if spctl -a -vv "$app" 2>&1 | grep -qi "invalid"; then - app_name=$(basename "$app") - echo "WARNING: $app_name has invalid signature and may not open" >&2 - echo " Fix: brew reinstall --cask " >&2 - fi - fi - done - ''; + ''} + '' + ); } diff --git a/modules/darwin/settings/default.nix b/modules/darwin/settings/default.nix index 76d1897..3c76559 100644 --- a/modules/darwin/settings/default.nix +++ b/modules/darwin/settings/default.nix @@ -1,4 +1,4 @@ -{ ... }: +{ config, ... }: ############################################################################## # macOS system.defaults — intentional settings only. # @@ -12,6 +12,11 @@ # CustomUserPreferences is reserved for keys that have no native option yet. # ############################################################################## +let + cfg = config.myConfig; + # home-manager stages GUI apps here; path must track myConfig.user.username. + hmApps = "/Users/${cfg.user.username}/Applications/Home Manager Apps"; +in { # ── Dock ───────────────────────────────────────────────────────────────────── system.defaults.dock = { @@ -49,13 +54,13 @@ { folder = "/System/Applications/Calendar.app"; } { folder = "/System/Applications/Reminders.app"; } { folder = "/Applications/Obsidian.app"; } - { folder = "/Users/ewan/Applications/Home Manager Apps/Visual Studio Code.app"; } + { folder = "${hmApps}/Visual Studio Code.app"; } { folder = "/Applications/Claude.app"; } # ── Media ───────────────────────────────────────────── { folder = "/Applications/Spotify.app"; } { folder = "/Applications/Firefox.app"; } # ── System ───────────────────────────────────────────────────── - { folder = "/Users/ewan/Applications/Home Manager Apps/Ghostty.app"; } + { folder = "${hmApps}/Ghostty.app"; } ]; }; diff --git a/modules/options.nix b/modules/options.nix index 8e2a24d..4fedcc1 100644 --- a/modules/options.nix +++ b/modules/options.nix @@ -889,6 +889,23 @@ in default = true; }; + gatekeeper = { + enable = mkOption { + type = bool; + default = true; + description = "Strip com.apple.quarantine from installed .app bundles on activation."; + }; + checkSignatures = mkOption { + type = bool; + default = false; + description = '' + Additionally run `spctl` over /Applications on every activation and + warn about invalid code signatures. Off by default — it shells out + once per app and noticeably slows down darwin-rebuild. + ''; + }; + }; + security.touchIdForSudo = mkOption { type = bool; default = true;