1
0
Fork 0
mirror of https://github.com/LnL7/nix-darwin.git synced 2025-03-31 04:04:45 +00:00

Merge branch 'LnL7:master' into master

This commit is contained in:
Oliver Wiegers 2025-03-19 15:33:45 +01:00 committed by GitHub
commit 9e6b09635f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
50 changed files with 948 additions and 595 deletions

2
.git-blame-ignore-revs Normal file
View file

@ -0,0 +1,2 @@
# nixpkgs: format with `nixfmt`
dc1c716ded39758062ed7e6bc410ad274119de9f

View file

@ -7,7 +7,6 @@ on:
env:
NIXPKGS_BRANCH: nixpkgs-unstable
NIX_DARWIN_BRANCH: master
NIX_VERSION: 2.24.11
jobs:
@ -40,33 +39,40 @@ jobs:
nix_path: nixpkgs=channel:${{ env.NIXPKGS_BRANCH }}
- name: Install channels
run: |
nix-channel --add https://github.com/LnL7/nix-darwin/archive/${{ env.NIX_DARWIN_BRANCH }}.tar.gz darwin
nix-channel --add https://nixos.org/channels/${{ env.NIXPKGS_BRANCH }} nixpkgs
nix-channel --update
- name: Install nix-darwin
run: |
export NIX_PATH=$HOME/.nix-defexpr/channels
mkdir -p ~/.config/nix-darwin
cp modules/examples/simple.nix ~/.config/nix-darwin/configuration.nix
sudo mkdir -p /etc/nix-darwin
sudo cp modules/examples/simple.nix /etc/nix-darwin/configuration.nix
nixConfHash=$(shasum -a 256 /etc/nix/nix.conf | cut -d ' ' -f 1)
/usr/bin/sed -i.bak \
"s/# programs.fish.enable = true;/nix.settings.access-tokens = [ \"github.com=\${{ secrets.GITHUB_TOKEN }}\" ]; environment.etc.\"nix\/nix.conf\".knownSha256Hashes = [ \"$nixConfHash\" ];/" \
~/.config/nix-darwin/configuration.nix
sudo /usr/bin/sed -i.bak \
"s/# programs.fish.enable = true;/ \
imports = [ \
({ options, ... }: { \
nix.settings.access-tokens = [ \"github.com=\${{ secrets.GITHUB_TOKEN }}\" ]; \
environment.etc.\"nix\/nix.conf\".knownSha256Hashes = [ \"$nixConfHash\" ]; \
nix.nixPath = \
[ { darwin = \"${PWD////\/}\"; } ] \
++ options.nix.nixPath.default; \
}) \
]; \
/" \
/etc/nix-darwin/configuration.nix
nix run .#darwin-rebuild \
-- switch \
-I darwin-config=$HOME/.config/nix-darwin/configuration.nix
nix run .#darwin-rebuild -- switch \
-I darwin=. \
-I darwin-config=/etc/nix-darwin/configuration.nix
- name: Switch to new configuration
run: |
. /etc/bashrc
/usr/bin/sed -i.bak \
sudo /usr/bin/sed -i.bak \
"s/pkgs.vim/pkgs.hello/" \
~/.config/nix-darwin/configuration.nix
/etc/nix-darwin/configuration.nix
darwin-rebuild switch -I darwin=.
darwin-rebuild switch
hello
- name: Test uninstallation of nix-darwin
@ -91,31 +97,33 @@ jobs:
install_url: https://releases.nixos.org/nix/nix-${{ env.NIX_VERSION }}/install
- name: Install nix-darwin
run: |
mkdir -p ~/.config/nix-darwin
sudo mkdir -p /etc/nix-darwin
darwin=$(pwd)
pushd ~/.config/nix-darwin
nix flake init -t $darwin
pushd /etc/nix-darwin
sudo nix flake init -t $darwin
nixConfHash=$(shasum -a 256 /etc/nix/nix.conf | cut -d ' ' -f 1)
/usr/bin/sed -i.bak \
sudo /usr/bin/sed -i.bak \
"s/# programs.fish.enable = true;/nix.settings.access-tokens = [ \"github.com=\${{ secrets.GITHUB_TOKEN }}\" ]; environment.etc.\"nix\/nix.conf\".knownSha256Hashes = [ \"$nixConfHash\" ];/" \
flake.nix
/usr/bin/sed -i.bak \
sudo /usr/bin/sed -i.bak \
's/darwinConfigurations."simple"/darwinConfigurations."'$(scutil --get LocalHostName)'"/g' \
flake.nix
sudo /usr/bin/sed -i.bak \
's/nixpkgs.hostPlatform = "aarch64-darwin";/nixpkgs.hostPlatform = "'$(nix eval --expr builtins.currentSystem --impure --raw)'";/' \
flake.nix
popd
nix run .#darwin-rebuild -- \
switch --flake ~/.config/nix-darwin#simple \
nix run .#darwin-rebuild -- switch \
--override-input nix-darwin . \
--override-input nixpkgs nixpkgs/${{ env.NIXPKGS_BRANCH }}
- name: Switch to new configuration
run: |
. /etc/bashrc
/usr/bin/sed -i.bak \
sudo /usr/bin/sed -i.bak \
"s/pkgs.vim/pkgs.hello/" \
~/.config/nix-darwin/flake.nix
/etc/nix-darwin/flake.nix
darwin-rebuild switch --flake ~/.config/nix-darwin#simple \
darwin-rebuild switch \
--override-input nix-darwin . \
--override-input nixpkgs nixpkgs/${{ env.NIXPKGS_BRANCH }}

View file

@ -1,3 +1,23 @@
2025-01-29
- There is now a `nix.enable` toggle to disable management of the Nix
installation. Nix installation management has been made more
opinionated as a consequence; nix-darwin now only supports managing a
multiuser daemon installation of Nix, and unconditionally takes
ownership of the nix-daemon launchd daemon and the `_nixbld*` build
users when Nix installation management is enabled.
If the new constraints do not work with your setup, you can disable
the `nix.enable` option to opt out of Nix installation management
entirely; see the option documentation for caveats.
2025-01-18
- The default configuration path for all new installations
is `/etc/nix-darwin`. This was already the undocumented
default for `darwin-rebuild switch` when using flakes. This
is implemented by setting `environment.darwinConfig` to
`"/etc/nix-darwin/configuration.nix"` by default when
`system.stateVersion` ≥ 6.
2024-09-10
- The default Nix build user group ID is now set to 350 when
`system.stateVersion` ≥ 5, to reflect the default for new Nix

View file

@ -11,11 +11,19 @@ nix-darwin is built up around [Nixpkgs](https://github.com/NixOS/nixpkgs), quite
## Prerequisites
The only prerequisite is a Nix implementation, both Nix and Lix are supported.
The only prerequisite is a Nix implementation; both Nix and Lix are supported.
As the official Nix installer does not include an automated uninstaller, and manual uninstallation on macOS is a complex process, we recommend using one of the following installers instead:
- The [Nix installer from Determinate Systems](https://github.com/DeterminateSystems/nix-installer?tab=readme-ov-file#determinate-nix-installer) is only recommended for use with flake-based setups. **Make sure you use it without the `--determinate` flag**. The `--determinate` flag installs the Determinate Nix distribution which does not work out of the box with nix-darwin.
* The [Nix installer from Determinate Systems](https://github.com/DeterminateSystems/nix-installer?tab=readme-ov-file#determinate-nix-installer) is only recommended for use with flake-based setups.
It can install one of two distributions of Nix:
* To install the **recommended** vanilla upstream [Nix](https://nixos.org), you will need to explicitly say `no` when prompted to install `Determinate Nix`.
* When run with the `--determinate` flag, it will install the [Determinate](https://docs.determinate.systems/) distribution.
As Determinate manages the Nix installation itself, you will need to set `nix.enable = false;` in your configuration to disable nix-darwins own Nix management.
Some nix-darwin functionality that relies on managing the Nix installation, like the `nix.*` options to adjust Nix settings or configure a Linux builder, will be unavailable.
* The [Lix installer](https://lix.systems/install/#on-any-other-linuxmacos-system) supports both flake-based and channel-based setups.
@ -33,11 +41,12 @@ Despite being an experimental feature in Nix currently, nix-darwin recommends th
<summary>Getting started from scratch</summary>
<p></p>
If you don't have an existing `configuration.nix`, you can run the following commands to generate a basic `flake.nix` inside `~/.config/nix-darwin`:
If you don't have an existing `configuration.nix`, you can run the following commands to generate a basic `flake.nix` inside `/etc/nix-darwin`:
```bash
mkdir -p ~/.config/nix-darwin
cd ~/.config/nix-darwin
sudo mkdir -p /etc/nix-darwin
sudo chown $(id -nu):$(id -ng) /etc/nix-darwin
cd /etc/nix-darwin
# To use Nixpkgs unstable:
nix flake init -t nix-darwin/master
@ -88,7 +97,10 @@ Make sure to set `nixpkgs.hostPlatform` in your `configuration.nix` to either `x
Unlike NixOS, `nix-darwin` does not have an installer, you can just run `darwin-rebuild switch` to install nix-darwin. As `darwin-rebuild` won't be installed in your `PATH` yet, you can use the following command:
```bash
nix run nix-darwin -- switch --flake ~/.config/nix-darwin
# To use Nixpkgs unstable:
nix run nix-darwin/master#darwin-rebuild -- switch
# To use Nixpkgs 24.11:
nix run nix-darwin/nix-darwin-24.11#darwin-rebuild -- switch
```
### Step 3. Using `nix-darwin`
@ -96,7 +108,7 @@ nix run nix-darwin -- switch --flake ~/.config/nix-darwin
After installing, you can run `darwin-rebuild` to apply changes to your system:
```bash
darwin-rebuild switch --flake ~/.config/nix-darwin
darwin-rebuild switch
```
#### Using flake inputs
@ -124,7 +136,7 @@ nix-darwin.lib.darwinSystem {
### Step 1. Creating `configuration.nix`
Copy the [simple](./modules/examples/simple.nix) example to `~/.config/nix-darwin/configuration.nix`.
Copy the [simple](./modules/examples/simple.nix) example to `/etc/nix-darwin/configuration.nix`.
### Step 2. Adding `nix-darwin` channel
@ -142,12 +154,8 @@ sudo nix-channel --update
To install `nix-darwin`, you can just run `darwin-rebuild switch` to install nix-darwin. As `darwin-rebuild` won't be installed in your `PATH` yet, you can use the following command:
```bash
# If you use Nixpkgs unstable (the default):
nix-build https://github.com/LnL7/nix-darwin/archive/master.tar.gz -A darwin-rebuild
# If you use Nixpkgs 24.11:
nix-build https://github.com/LnL7/nix-darwin/archive/nix-darwin-24.11.tar.gz -A darwin-rebuild
./result/bin/darwin-rebuild switch -I darwin-config=$HOME/.config/nix-darwin/configuration.nix
nix-build '<darwin>' -A darwin-rebuild
./result/bin/darwin-rebuild switch -I darwin-config=/etc/nix-darwin/configuration.nix
```
### Step 4. Using `nix-darwin`

View file

@ -67,8 +67,24 @@ in
};
environment.darwinConfig = mkOption {
type = types.either types.path types.str;
default = "$HOME/.nixpkgs/darwin-configuration.nix";
type = types.nullOr (types.either types.path types.str);
default =
if config.nixpkgs.flake.setNixPath then
# Dont set this for flakebased systems.
null
else if config.system.stateVersion >= 6 then
"/etc/nix-darwin/configuration.nix"
else
"$HOME/.nixpkgs/darwin-configuration.nix";
defaultText = literalExpression ''
if config.nixpkgs.flake.setNixPath then
# Dont set this for flakebased systems.
null
else if config.system.stateVersion >= 6 then
"/etc/nix-darwin/configuration.nix"
else
"$HOME/.nixpkgs/darwin-configuration.nix"
'';
description = ''
The path of the darwin configuration.nix used to configure the system,
this updates the default darwin-config entry in NIX_PATH. Since this

View file

@ -27,7 +27,7 @@
# Used for backwards compatibility, please read the changelog before changing.
# $ darwin-rebuild changelog
system.stateVersion = 5;
system.stateVersion = 6;
# The platform the configuration will be used on.
nixpkgs.hostPlatform = "aarch64-darwin";

View file

@ -43,5 +43,5 @@ in
echo "ok"
'';
system.stateVersion = 5;
system.stateVersion = 6;
}

View file

@ -199,7 +199,7 @@
programs.zsh.enableFzfGit = true;
programs.zsh.enableFzfHistory = true;
programs.zsh.variables.cfg = "$HOME/.config/nixpkgs/darwin/configuration.nix";
programs.zsh.variables.cfg = "/etc/nix-darwin/configuration.nix";
programs.zsh.variables.darwin = "$HOME/.nix-defexpr/darwin";
programs.zsh.variables.nixpkgs = "$HOME/.nix-defexpr/nixpkgs";
@ -319,8 +319,7 @@
# path = /etc/per-user/lnl/gitconfig
# environment.etc."per-user/lnl/gitconfig".text = builtins.readFile "${inputs.dotfiles}/git/gitconfig";
nix.configureBuildUsers = true;
nix.nrBuildUsers = 32;
system.stateVersion = 5;
system.stateVersion = 6;
}

View file

@ -7,13 +7,10 @@
[ pkgs.vim
];
# Use custom location for configuration.nix.
environment.darwinConfig = "$HOME/.config/nix-darwin/configuration.nix";
# Enable alternative shell support in nix-darwin.
# programs.fish.enable = true;
# Used for backwards compatibility, please read the changelog before changing.
# $ darwin-rebuild changelog
system.stateVersion = 5;
system.stateVersion = 6;
}

View file

@ -137,7 +137,7 @@ let
config = {
brewBundleCmd = concatStringsSep " " (
optional (!config.autoUpdate) "HOMEBREW_NO_AUTO_UPDATE=1"
++ [ "brew bundle --file='${brewfileFile}' --no-lock" ]
++ [ "brew bundle --file='${brewfileFile}'" ]
++ optional (!config.upgrade) "--no-upgrade"
++ optional (config.cleanup == "uninstall") "--cleanup"
++ optional (config.cleanup == "zap") "--cleanup --zap"
@ -708,9 +708,6 @@ in
description = ''
Applications to install from Mac App Store using {command}`mas`.
When this option is used, `"mas"` is automatically added to
[](#opt-homebrew.brews).
Note that you need to be signed into the Mac App Store for {command}`mas` to
successfully install and upgrade applications, and that unfortunately apps removed from this
option will not be uninstalled automatically even if
@ -768,8 +765,7 @@ in
];
homebrew.brews =
optional (cfg.masApps != { }) "mas"
++ optional (cfg.whalebrews != [ ]) "whalebrew";
optional (cfg.whalebrews != [ ]) "whalebrew";
homebrew.brewfile =
"# Created by `nix-darwin`'s `homebrew` module\n\n"
@ -789,7 +785,8 @@ in
# Homebrew Bundle
echo >&2 "Homebrew bundle..."
if [ -f "${cfg.brewPrefix}/brew" ]; then
PATH="${cfg.brewPrefix}":$PATH ${cfg.onActivation.brewBundleCmd}
PATH="${cfg.brewPrefix}:${lib.makeBinPath [ pkgs.mas ]}:$PATH" \
${cfg.onActivation.brewBundleCmd}
else
echo -e "\e[1;31merror: Homebrew is not installed, skipping...\e[0m" >&2
fi

View file

@ -39,11 +39,13 @@ in
ids.uids = {
nixbld = lib.mkDefault 350;
_prometheus-node-exporter = 534;
_dnscrypt-proxy = 535;
};
ids.gids = {
nixbld = lib.mkDefault (if config.system.stateVersion < 5 then 30000 else 350);
_prometheus-node-exporter = 534;
_dnscrypt-proxy = 535;
};
};

View file

@ -62,6 +62,7 @@
./services/chunkwm.nix
./services/cachix-agent.nix
./services/dnsmasq.nix
./services/dnscrypt-proxy.nix
./services/emacs.nix
./services/eternal-terminal.nix
./services/github-runner

View file

@ -132,6 +132,11 @@ in
${optionalString (cfg.wakeOnLan.enable != null) ''
systemsetup -setWakeOnNetworkAccess '${onOff cfg.wakeOnLan.enable}' &> /dev/null
''}
if [ -e /etc/hosts.before-nix-darwin ]; then
echo "restoring /etc/hosts..." >&2
sudo mv /etc/hosts{.before-nix-darwin,}
fi
'';
};

View file

@ -12,6 +12,8 @@ let
isNixAtLeast = versionAtLeast (getVersion nixPackage);
configureBuildUsers = !(config.nix.settings.auto-allocate-uids or false);
makeNixBuildUser = nr: {
name = "_nixbld${toString nr}";
value = {
@ -49,13 +51,16 @@ let
mkKeyValuePairs = attrs: concatStringsSep "\n" (mapAttrsToList mkKeyValue attrs);
isExtra = key: hasPrefix "extra-" key;
in
pkgs.writeTextFile {
name = "nix.conf";
text = ''
# WARNING: this file is generated from the nix.* options in
# your nix-darwin configuration. Do not edit it!
${mkKeyValuePairs cfg.settings}
${mkKeyValuePairs (filterAttrs (key: value: !(isExtra key)) cfg.settings)}
${mkKeyValuePairs (filterAttrs (key: value: isExtra key) cfg.settings)}
${cfg.extraOptions}
'';
checkPhase =
@ -134,6 +139,34 @@ let
namedPaths ++ searchPaths;
};
handleUnmanaged = managedConfig: mkMerge [
(mkIf cfg.enable managedConfig)
(mkIf (!cfg.enable) {
system.activationScripts.nix-daemon.text = ''
# Restore unmanaged Nix daemon if present
unmanagedNixProfile=/nix/var/nix/profiles/default
if [[
-e /run/current-system/Library/LaunchDaemons/org.nixos.nix-daemon.plist
&& -e $unmanagedNixProfile/Library/LaunchDaemons/org.nixos.nix-daemon.plist
]]; then
printf >&2 'restoring unmanaged Nix daemon...\n'
cp \
"$unmanagedNixProfile/Library/LaunchDaemons/org.nixos.nix-daemon.plist" \
/Library/LaunchDaemons
launchctl load -w /Library/LaunchDaemons/org.nixos.nix-daemon.plist
fi
'';
})
];
managedDefault = name: default: {
default = if cfg.enable then default else throw ''
${name}: accessed when `nix.enable` is off; this is a bug in
nix-darwin or a thirdparty module
'';
defaultText = default;
};
in
{
@ -144,7 +177,6 @@ in
in
[
# Only ever in NixOS
(mkRemovedOptionModule [ "nix" "enable" ] "No `nix-darwin` equivalent to this NixOS option.")
(mkRemovedOptionModule [ "nix" "daemonCPUSchedPolicy" ] (altOption "nix.daemonProcessType"))
(mkRemovedOptionModule [ "nix" "daemonIOSchedClass" ] (altOption "nix.daemonProcessType"))
(mkRemovedOptionModule [ "nix" "daemonIOSchedPriority" ] (altOption "nix.daemonIOLowPriority"))
@ -157,6 +189,14 @@ in
(mkRenamedOptionModule [ "users" "nix" "nrBuildUsers" ] [ "nix" "nrBuildUsers" ])
(mkRenamedOptionModule [ "nix" "daemonIONice" ] [ "nix" "daemonIOLowPriority" ])
(mkRemovedOptionModule [ "nix" "daemonNiceLevel" ] (consider "nix.daemonProcessType"))
(mkRemovedOptionModule [ "nix" "useDaemon" ] ''
nix-darwin now only supports managing multiuser daemon
installations of Nix.
'')
(mkRemovedOptionModule [ "nix" "configureBuildUsers" ] ''
nix-darwin now manages build users unconditionally when
`nix.enable` is on.
'')
] ++ mapAttrsToList (oldConf: newConf: mkRenamedOptionModule [ "nix" oldConf ] [ "nix" "settings" newConf ]) legacyConfMappings;
###### interface
@ -165,29 +205,43 @@ in
nix = {
enable = lib.mkOption {
type = lib.types.bool;
default = true;
description = ''
Whether to enable Nix.
Disabling this will stop nix-darwin from managing the
installed version of Nix, the nix-daemon launchd daemon, and
the settings in {file}`/etc/nix/nix.conf`.
This allows you to use nix-darwin without it taking over your
system installation of Nix. Some nix-darwin functionality
that relies on managing the Nix installation, like the
`nix.*` options to adjust Nix settings or configure a Linux
builder, will be unavailable. You will also have to upgrade
Nix yourself, as nix-darwin will no longer do so.
::: {.warning}
If you have already removed your global system installation
of Nix, this will break nix-darwin and you will have to
reinstall Nix to fix it.
:::
'';
};
package = mkOption {
type = types.package;
default = pkgs.nix;
inherit (managedDefault "nix.package" pkgs.nix) default;
defaultText = literalExpression "pkgs.nix";
description = ''
This option specifies the Nix package instance to use throughout the system.
'';
};
# Not in NixOS module
useDaemon = mkOption {
type = types.bool;
default = false;
description = ''
If set, Nix will use the daemon to perform operations.
Use this instead of services.nix-daemon.enable if you don't want the
daemon service to be managed for you.
'';
};
distributedBuilds = mkOption {
type = types.bool;
default = false;
inherit (managedDefault "nix.distributedBuilds" false) default defaultText;
description = ''
Whether to distribute builds to the machines listed in
{option}`nix.buildMachines`.
@ -197,7 +251,7 @@ in
# Not in NixOS module
daemonProcessType = mkOption {
type = types.enum [ "Background" "Standard" "Adaptive" "Interactive" ];
default = "Standard";
inherit (managedDefault "nix.daemonProcessType" "Standard") default defaultText;
description = ''
Nix daemon process resource limits class. These limits propagate to
build processes. `Standard` is the default process type
@ -212,7 +266,7 @@ in
# Not in NixOS module
daemonIOLowPriority = mkOption {
type = types.bool;
default = false;
inherit (managedDefault "nix.daemonIOLowPriority" false) default defaultText;
description = ''
Whether the Nix daemon process should considered to be low priority when
doing file system I/O.
@ -340,7 +394,7 @@ in
};
};
});
default = [ ];
inherit (managedDefault "nix.buildMachines" [ ]) default defaultText;
description = ''
This option lists the machines to be used if distributed builds are
enabled (see {option}`nix.distributedBuilds`).
@ -354,21 +408,13 @@ in
envVars = mkOption {
type = types.attrs;
internal = true;
default = { };
inherit (managedDefault "nix.envVars" { }) default defaultText;
description = "Environment variables used by Nix.";
};
# Not in NixOS module
configureBuildUsers = mkOption {
type = types.bool;
default = false;
description = ''
Enable configuration for nixbld group and users.
'';
};
nrBuildUsers = mkOption {
type = types.int;
inherit (managedDefault "nix.nrBuildUsers" 0) default defaultText;
description = ''
Number of `nixbld` user accounts created to
perform secure concurrent builds. If you receive an error
@ -396,11 +442,13 @@ in
# Definition differs substantially from NixOS module
nixPath = mkOption {
type = nixPathType;
default = lib.optionals cfg.channel.enable [
# Include default path <darwin-config>.
{ darwin-config = "${config.environment.darwinConfig}"; }
"/nix/var/nix/profiles/per-user/root/channels"
];
inherit (managedDefault "nix.nixPath" (
lib.optionals cfg.channel.enable [
# Include default path <darwin-config>.
{ darwin-config = "${config.environment.darwinConfig}"; }
"/nix/var/nix/profiles/per-user/root/channels"
]
)) default;
defaultText = lib.literalExpression ''
lib.optionals cfg.channel.enable [
@ -422,7 +470,7 @@ in
checkConfig = mkOption {
type = types.bool;
default = true;
inherit (managedDefault "nix.checkConfig" true) default defaultText;
description = ''
If enabled (the default), checks for data type mismatches and that Nix
can parse the generated nix.conf.
@ -483,7 +531,7 @@ in
};
}
));
default = { };
inherit (managedDefault "nix.registry" { }) default defaultText;
description = ''
A system-wide flake registry.
'';
@ -491,7 +539,7 @@ in
extraOptions = mkOption {
type = types.lines;
default = "";
inherit (managedDefault "nix.extraOptions" "") default defaultText;
example = ''
keep-outputs = true
keep-derivations = true
@ -660,7 +708,7 @@ in
};
};
};
default = { };
inherit (managedDefault "nix.settings" { }) default defaultText;
description = ''
Configuration for Nix, see
<https://nixos.org/manual/nix/stable/#sec-conf-file>
@ -678,7 +726,7 @@ in
###### implementation
config = {
config = handleUnmanaged {
environment.systemPackages =
[
nixPackage
@ -759,7 +807,7 @@ in
# Not in NixOS module
{ assertion = elem "nixbld" config.users.knownGroups -> elem "nixbld" createdGroups; message = "refusing to delete group nixbld in users.knownGroups, this would break nix"; }
{ assertion = elem "_nixbld1" config.users.knownGroups -> elem "_nixbld1" createdUsers; message = "refusing to delete user _nixbld1 in users.knownUsers, this would break nix"; }
{ assertion = elem "_nixbld1" config.users.knownUsers -> elem "_nixbld1" createdUsers; message = "refusing to delete user _nixbld1 in users.knownUsers, this would break nix"; }
{ assertion = config.users.groups ? "nixbld" -> config.users.groups.nixbld.members != []; message = "refusing to remove all members from nixbld group, this would break nix"; }
{
@ -785,21 +833,11 @@ in
# Set up the environment variables for running Nix.
environment.variables = cfg.envVars // { NIX_PATH = cfg.nixPath; };
environment.extraInit = mkMerge [
(mkIf cfg.channel.enable ''
if [ -e "$HOME/.nix-defexpr/channels" ]; then
export NIX_PATH="$HOME/.nix-defexpr/channels''${NIX_PATH:+:$NIX_PATH}"
fi
'')
# Not in NixOS module
''
# Set up secure multi-user builds: non-root users build through the
# Nix daemon.
if [ ! -w /nix/var/nix/db ]; then
export NIX_REMOTE=daemon
fi
''
];
environment.extraInit = mkIf cfg.channel.enable ''
if [ -e "$HOME/.nix-defexpr/channels" ]; then
export NIX_PATH="$HOME/.nix-defexpr/channels''${NIX_PATH:+:$NIX_PATH}"
fi
'';
environment.extraSetup = mkIf (!cfg.channel.enable) ''
rm --force $out/bin/nix-channel
@ -807,10 +845,10 @@ in
nix.nrBuildUsers = mkDefault (max 32 (if cfg.settings.max-jobs == "auto" then 0 else cfg.settings.max-jobs));
users.users = mkIf cfg.configureBuildUsers nixbldUsers;
users.users = mkIf configureBuildUsers nixbldUsers;
# Not in NixOS module
users.groups.nixbld = mkIf cfg.configureBuildUsers {
users.groups.nixbld = mkIf configureBuildUsers {
description = "Nix build group for nix-daemon";
gid = config.ids.gids.nixbld;
members = attrNames nixbldUsers;
@ -818,11 +856,11 @@ in
users.knownUsers =
let nixbldUserNames = attrNames nixbldUsers;
in
mkIf cfg.configureBuildUsers (mkMerge [
mkMerge [
nixbldUserNames
(map (removePrefix "_") nixbldUserNames) # delete old style nixbld users
]);
users.knownGroups = mkIf cfg.configureBuildUsers [ "nixbld" ];
];
users.knownGroups = [ "nixbld" ];
# The Determinate Systems installer puts userspecified settings in
# `/etc/nix/nix.custom.conf` since v0.33.0. Supplement the
@ -873,7 +911,7 @@ in
if [[ -e /etc/nix/nix.custom.conf ]]; then
mv /etc/nix/nix.custom.conf{,.before-nix-darwin}
fi
'' + optionalString cfg.useDaemon ''
if ! diff /etc/nix/nix.conf /run/current-system/etc/nix/nix.conf &> /dev/null || ! diff /etc/nix/machines /run/current-system/etc/nix/machines &> /dev/null; then
echo "reloading nix-daemon..." >&2
launchctl kill HUP system/org.nixos.nix-daemon
@ -890,6 +928,9 @@ in
trusted-users = [ "root" ];
substituters = mkAfter [ "https://cache.nixos.org/" ];
# Not in NixOS module
build-users-group = "nixbld";
# Not implemented yet
# system-features = mkDefault (
# [ "nixos-test" "benchmark" "big-parallel" "kvm" ] ++
@ -905,8 +946,6 @@ in
(mkIf (isNixAtLeast "2.3pre") { sandbox-fallback = false; })
# Not in NixOS module
(mkIf cfg.useDaemon { build-users-group = "nixbld"; })
];
};

View file

@ -160,6 +160,13 @@ in
};
config = mkIf cfg.enable {
assertions = [
{
assertion = config.nix.enable;
message = ''`nix.linux-builder.enable` requires `nix.enable`'';
}
];
system.activationScripts.preActivation.text = ''
mkdir -p ${cfg.workingDirectory}
'';

View file

@ -4,44 +4,49 @@ let
nix-tools = pkgs.callPackage ../../pkgs/nix-tools {
inherit (config.system) profile;
inherit (config.environment) systemPath;
nixPath = lib.concatStringsSep ":" config.nix.nixPath;
nixPath = lib.optionalString config.nix.enable (lib.concatStringsSep ":" config.nix.nixPath);
};
darwin-uninstaller = pkgs.callPackage ../../pkgs/darwin-uninstaller { };
inherit (nix-tools) darwin-option darwin-rebuild darwin-version;
mkToolModule = { name, package ? nix-tools.${name} }: { config, ... }: {
options.system.tools.${name}.enable = lib.mkEnableOption "${name} script" // {
default = config.system.tools.enable;
};
config = lib.mkIf config.system.tools.${name}.enable {
environment.systemPackages = [ package ];
};
};
in
{
options.system = {
disableInstallerTools = lib.mkOption {
type = lib.types.bool;
internal = true;
default = false;
description = ''
Disable darwin-rebuild and darwin-option. This is useful to shrink
systems which are not expected to rebuild or reconfigure themselves.
Use at your own risk!
'';
};
includeUninstaller = lib.mkOption {
tools.enable = lib.mkOption {
type = lib.types.bool;
internal = true;
default = true;
description = ''
Disable internal tools, such as darwin-rebuild and darwin-option. This
is useful to shrink systems which are not expected to rebuild or
reconfigure themselves. Use at your own risk!
'';
};
};
config = {
environment.systemPackages =
[ darwin-version ]
++ lib.optionals (!config.system.disableInstallerTools) [
darwin-option
darwin-rebuild
] ++ lib.optional config.system.includeUninstaller darwin-uninstaller;
imports = [
(lib.mkRenamedOptionModule [ "system" "includeUninstaller" ] [ "system" "tools" "darwin-uninstaller" "enable" ])
(lib.mkRemovedOptionModule [ "system" "disableInstallerTools" ] "Please use system.tools.enable instead")
(mkToolModule { name = "darwin-option"; })
(mkToolModule { name = "darwin-rebuild"; })
(mkToolModule { name = "darwin-version"; })
(mkToolModule { name = "darwin-uninstaller"; package = darwin-uninstaller; })
];
config = {
system.build = {
inherit darwin-option darwin-rebuild darwin-version;
inherit (nix-tools) darwin-option darwin-rebuild darwin-version;
};
};
}

View file

@ -37,8 +37,8 @@ in
setNixPath = mkOption {
type = types.bool;
default = cfg.source != null;
defaultText = "config.nixpkgs.flake.source != null";
default = config.nix.enable && cfg.source != null;
defaultText = literalExpression ''config.nix.enable && nixpkgs.flake.source != null'';
description = ''
Whether to set {env}`NIX_PATH` to include `nixpkgs=flake:nixpkgs` such that `<nixpkgs>`
@ -57,8 +57,8 @@ in
setFlakeRegistry = mkOption {
type = types.bool;
default = cfg.source != null;
defaultText = "config.nixpkgs.flake.source != null";
default = config.nix.enable && cfg.source != null;
defaultText = literalExpression ''config.nix.enable && config.nixpkgs.flake.source != null'';
description = ''
Whether to pin nixpkgs in the system-wide flake registry (`/etc/nix/registry.json`) to the
@ -85,6 +85,18 @@ in
be set, since it is implemented in terms of indirection through the flake registry.
'';
}
# TODO: Upstream these to NixOS.
{
assertion = cfg.setNixPath -> config.nix.enable;
message = ''`nixpkgs.flake.setNixPath` requires `nix.enable`'';
}
{
assertion = cfg.setFlakeRegistry -> config.nix.enable;
message = ''`nixpkgs.flake.setFlakeRegistry` requires `nix.enable`'';
}
];
}
(mkIf cfg.setFlakeRegistry {

View file

@ -1,89 +1,96 @@
{ config, options, lib, pkgs, ... }:
with lib;
{
config,
options,
lib,
pkgs,
...
}:
let
cfg = config.nixpkgs;
opt = options.nixpkgs;
isConfig = x:
builtins.isAttrs x || lib.isFunction x;
isConfig = x: builtins.isAttrs x || lib.isFunction x;
optCall = f: x:
if lib.isFunction f
then f x
else f;
optCall = f: x: if lib.isFunction f then f x else f;
mergeConfig = lhs_: rhs_:
mergeConfig =
lhs_: rhs_:
let
lhs = optCall lhs_ { inherit pkgs; };
rhs = optCall rhs_ { inherit pkgs; };
in
recursiveUpdate lhs rhs //
optionalAttrs (lhs ? packageOverrides) {
packageOverrides = pkgs:
optCall lhs.packageOverrides pkgs //
optCall (attrByPath [ "packageOverrides" ] { } rhs) pkgs;
} //
optionalAttrs (lhs ? perlPackageOverrides) {
perlPackageOverrides = pkgs:
optCall lhs.perlPackageOverrides pkgs //
optCall (attrByPath [ "perlPackageOverrides" ] { } rhs) pkgs;
lib.recursiveUpdate lhs rhs
// lib.optionalAttrs (lhs ? packageOverrides) {
packageOverrides =
pkgs:
optCall lhs.packageOverrides pkgs // optCall (lib.attrByPath [ "packageOverrides" ] { } rhs) pkgs;
}
// lib.optionalAttrs (lhs ? perlPackageOverrides) {
perlPackageOverrides =
pkgs:
optCall lhs.perlPackageOverrides pkgs
// optCall (lib.attrByPath [ "perlPackageOverrides" ] { } rhs) pkgs;
};
configType = mkOptionType {
configType = lib.mkOptionType {
name = "nixpkgs-config";
description = "nixpkgs config";
check = x:
let traceXIfNot = c:
if c x then true
else lib.traceSeqN 1 x false;
in traceXIfNot isConfig;
merge = args: foldr (def: mergeConfig def.value) {};
check =
x:
let
traceXIfNot = c: if c x then true else lib.traceSeqN 1 x false;
in
traceXIfNot isConfig;
merge = args: lib.foldr (def: mergeConfig def.value) { };
};
overlayType = mkOptionType {
overlayType = lib.mkOptionType {
name = "nixpkgs-overlay";
description = "nixpkgs overlay";
check = lib.isFunction;
merge = lib.mergeOneOption;
};
pkgsType = types.pkgs // {
pkgsType = lib.types.pkgs // {
# This type is only used by itself, so let's elaborate the description a bit
# for the purpose of documentation.
description = "An evaluation of Nixpkgs; the top level attribute set of packages";
};
hasBuildPlatform = opt.buildPlatform.highestPrio < (mkOptionDefault {}).priority;
hasBuildPlatform = opt.buildPlatform.highestPrio < (lib.mkOptionDefault { }).priority;
hasHostPlatform = opt.hostPlatform.isDefined;
hasPlatform = hasHostPlatform || hasBuildPlatform;
# Context for messages
hostPlatformLine = optionalString hasHostPlatform "${showOptionWithDefLocs opt.hostPlatform}";
buildPlatformLine = optionalString hasBuildPlatform "${showOptionWithDefLocs opt.buildPlatform}";
hostPlatformLine = lib.optionalString hasHostPlatform "${lib.showOptionWithDefLocs opt.hostPlatform}";
buildPlatformLine = lib.optionalString hasBuildPlatform "${lib.showOptionWithDefLocs opt.buildPlatform}";
legacyOptionsDefined =
optional (opt.system.highestPrio < (mkDefault {}).priority) opt.system
;
legacyOptionsDefined = lib.optional (
opt.system.highestPrio < (lib.mkDefault { }).priority
) opt.system;
defaultPkgs =
if opt.hostPlatform.isDefined
then
let isCross = cfg.buildPlatform != cfg.hostPlatform;
systemArgs =
if isCross
then {
if opt.hostPlatform.isDefined then
let
isCross = cfg.buildPlatform != cfg.hostPlatform;
systemArgs =
if isCross then
{
localSystem = cfg.buildPlatform;
crossSystem = cfg.hostPlatform;
}
else {
else
{
localSystem = cfg.hostPlatform;
};
in
import cfg.source ({
inherit (cfg) config overlays;
} // systemArgs)
import cfg.source (
{
inherit (cfg) config overlays;
}
// systemArgs
)
else
import cfg.source {
inherit (cfg) config overlays;
@ -96,9 +103,9 @@ in
{
options.nixpkgs = {
pkgs = mkOption {
pkgs = lib.mkOption {
type = pkgsType;
example = literalExpression "import <nixpkgs> {}";
example = lib.literalExpression "import <nixpkgs> {}";
description = ''
If set, the pkgs argument to all nix-darwin modules is the value of
this option, extended with `nixpkgs.overlays`, if
@ -120,53 +127,48 @@ in
'';
};
config = mkOption {
default = {};
example = literalExpression
''
{ allowBroken = true; allowUnfree = true; }
'';
config = lib.mkOption {
default = { };
example = lib.literalExpression ''
{ allowBroken = true; allowUnfree = true; }
'';
type = configType;
description = ''
The configuration of the Nix Packages collection. (For
details, see the Nixpkgs documentation.) It allows you to set
package configuration options.
Global configuration for Nixpkgs.
The complete list of [Nixpkgs configuration options](https://nixos.org/manual/nixpkgs/unstable/#sec-config-options-reference) is in the [Nixpkgs manual section on global configuration](https://nixos.org/manual/nixpkgs/unstable/#chap-packageconfig).
Ignored when `nixpkgs.pkgs` is set.
Ignored when {option}`nixpkgs.pkgs` is set.
'';
};
overlays = mkOption {
default = [];
example = literalExpression
''
[
(self: super: {
openssh = super.openssh.override {
hpnSupport = true;
kerberos = self.libkrb5;
};
})
]
'';
type = types.listOf overlayType;
overlays = lib.mkOption {
default = [ ];
example = lib.literalExpression ''
[
(self: super: {
openssh = super.openssh.override {
hpnSupport = true;
kerberos = self.libkrb5;
};
})
]
'';
type = lib.types.listOf overlayType;
description = ''
List of overlays to use with the Nix Packages collection.
(For details, see the Nixpkgs documentation.) It allows
you to override packages globally. Each function in the list
takes as an argument the *original* Nixpkgs.
The first argument should be used for finding dependencies, and
the second should be used for overriding recipes.
List of overlays to apply to Nixpkgs.
This option allows modifying the Nixpkgs package set accessed through the `pkgs` module argument.
If `nixpkgs.pkgs` is set, overlays specified here
will be applied after the overlays that were already present
in `nixpkgs.pkgs`.
For details, see the [Overlays chapter in the Nixpkgs manual](https://nixos.org/manual/nixpkgs/stable/#chap-overlays).
If the {option}`nixpkgs.pkgs` option is set, overlays specified using `nixpkgs.overlays` will be applied after the overlays that were already included in `nixpkgs.pkgs`.
'';
};
hostPlatform = mkOption {
type = types.either types.str types.attrs; # TODO utilize lib.systems.parsedPlatform
example = { system = "aarch64-darwin"; config = "aarch64-apple-darwin"; };
hostPlatform = lib.mkOption {
type = lib.types.either lib.types.str lib.types.attrs; # TODO utilize lib.systems.parsedPlatform
example = {
system = "aarch64-darwin";
};
# Make sure that the final value has all fields for sake of other modules
# referring to this. TODO make `lib.systems` itself use the module system.
apply = lib.systems.elaborate;
@ -179,15 +181,24 @@ in
'';
};
buildPlatform = mkOption {
type = types.either types.str types.attrs; # TODO utilize lib.systems.parsedPlatform
buildPlatform = lib.mkOption {
type = lib.types.either lib.types.str lib.types.attrs; # TODO utilize lib.systems.parsedPlatform
default = cfg.hostPlatform;
example = { system = "x86_64-darwin"; config = "x86_64-apple-darwin"; };
example = {
system = "x86_64-darwin";
};
# Make sure that the final value has all fields for sake of other modules
# referring to this.
apply = lib.systems.elaborate;
defaultText = literalExpression
''config.nixpkgs.hostPlatform'';
apply =
inputBuildPlatform:
let
elaborated = lib.systems.elaborate inputBuildPlatform;
in
if lib.systems.equals elaborated cfg.hostPlatform then
cfg.hostPlatform # make identical, so that `==` equality works; see https://github.com/NixOS/nixpkgs/issues/278001
else
elaborated;
defaultText = lib.literalExpression ''config.nixpkgs.hostPlatform'';
description = ''
Specifies the platform on which nix-darwin should be built.
By default, nix-darwin is built on the system where it runs, but you can
@ -202,12 +213,11 @@ in
'';
};
system = mkOption {
type = types.str;
system = lib.mkOption {
type = lib.types.str;
example = "x86_64-darwin";
default =
if opt.hostPlatform.isDefined
then
if opt.hostPlatform.isDefined then
throw ''
Neither ${opt.system} nor any other option in nixpkgs.* is meant
to be read by modules and configurations.
@ -232,9 +242,9 @@ in
# nix-darwin only
source = mkOption {
type = types.path;
defaultText = literalMD ''
source = lib.mkOption {
type = lib.types.path;
defaultText = lib.literalMD ''
`<nixpkgs>` or nix-darwin's `nixpkgs` flake input
'';
description = ''
@ -247,8 +257,8 @@ in
'';
};
constructedByUs = mkOption {
type = types.bool;
constructedByUs = lib.mkOption {
type = lib.types.bool;
internal = true;
description = ''
Whether `pkgs` was constructed by this module. This is false when any of
@ -266,40 +276,51 @@ in
# which is somewhat costly for Nixpkgs. With an explicit priority, we only
# evaluate the wrapper to find out that the priority is lower, and then we
# don't need to evaluate `finalPkgs`.
lib.mkOverride lib.modules.defaultOverridePriority
finalPkgs.__splicedPackages;
lib.mkOverride lib.modules.defaultOverridePriority finalPkgs.__splicedPackages;
};
nixpkgs.constructedByUs =
# We set it with default priority and it can not be merged, so if the
# pkgs module argument has that priority, it's from us.
(lib.modules.mergeAttrDefinitionsWithPrio options._module.args).pkgs.highestPrio
== lib.modules.defaultOverridePriority
== lib.modules.defaultOverridePriority
# Although, if nixpkgs.pkgs is set, we did forward it, but we did not construct it.
&& !opt.pkgs.isDefined;
&& !opt.pkgs.isDefined;
assertions = [
(
let
pkgsSystem = finalPkgs.stdenv.targetPlatform.system;
in {
in
{
assertion = cfg.constructedByUs -> !hasPlatform -> cfg.system == pkgsSystem;
message = "The nix-darwin nixpkgs.pkgs option was set to a Nixpkgs invocation that compiles to target system ${pkgsSystem} but nix-darwin was configured for system ${darwinExpectedSystem} via nix-darwin option nixpkgs.system. The nix-darwin system settings must match the Nixpkgs target system.";
message = "The nix-darwin nixpkgs.pkgs option was set to a Nixpkgs invocation that compiles to target system ${pkgsSystem} but nix-darwin was configured for system ${config.nixpkgs.system} via nix-darwin option nixpkgs.system. The nix-darwin system settings must match the Nixpkgs target system.";
}
)
{
assertion = cfg.constructedByUs -> hasPlatform -> legacyOptionsDefined == [];
assertion = cfg.constructedByUs -> hasPlatform -> legacyOptionsDefined == [ ];
message = ''
Your system configures nixpkgs with the platform parameter${optionalString hasBuildPlatform "s"}:
${hostPlatformLine
}${buildPlatformLine
}
Your system configures nixpkgs with the platform parameter${lib.optionalString hasBuildPlatform "s"}:
${hostPlatformLine}${buildPlatformLine}
However, it also defines the legacy options:
${concatMapStrings showOptionWithDefLocs legacyOptionsDefined}
${lib.concatMapStrings lib.showOptionWithDefLocs legacyOptionsDefined}
For a future proof system configuration, we recommend to remove
the legacy definitions.
'';
}
{
assertion = opt.pkgs.isDefined -> cfg.config == { };
message = ''
Your system configures nixpkgs with an externally created instance.
`nixpkgs.config` options should be passed when creating the instance instead.
Current value:
${lib.generators.toPretty { multiline = true; } cfg.config}
Defined in:
${lib.concatMapStringsSep "\n" (file: " - ${file}") opt.config.files}
'';
}
];
};
}

View file

@ -1,69 +1,106 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.security.pam;
# Implementation Notes
#
# We don't use `environment.etc` because this would require that the user manually delete
# `/etc/pam.d/sudo` which seems unwise given that applying the nix-darwin configuration requires
# sudo. We also can't use `system.patchs` since it only runs once, and so won't patch in the
# changes again after OS updates (which remove modifications to this file).
#
# As such, we resort to line addition/deletion in place using `sed`. We add a comment to the
# added line that includes the name of the option, to make it easier to identify the line that
# should be deleted when the option is disabled.
mkSudoTouchIdAuthScript = isEnabled:
let
file = "/etc/pam.d/sudo";
option = "security.pam.enableSudoTouchIdAuth";
sed = "${pkgs.gnused}/bin/sed";
in ''
${if isEnabled then ''
# Enable sudo Touch ID authentication, if not already enabled
if ! grep 'pam_tid.so' ${file} > /dev/null; then
${sed} -i '2i\
auth sufficient pam_tid.so # nix-darwin: ${option}
' ${file}
fi
'' else ''
# Disable sudo Touch ID authentication, if added by nix-darwin
if grep '${option}' ${file} > /dev/null; then
${sed} -i '/${option}/d' ${file}
fi
''}
'';
cfg = config.security.pam.services.sudo_local;
in
{
imports = [
(lib.mkRemovedOptionModule [ "security" "pam" "enableSudoTouchIdAuth" ] ''
This option has been renamed to `security.pam.services.sudo_local.touchIdAuth` for consistency with NixOS.
'')
];
options = {
security.pam.enableSudoTouchIdAuth = mkEnableOption "" // {
description = ''
Enable sudo authentication with Touch ID.
security.pam.services.sudo_local = {
enable = lib.mkEnableOption "managing {file}`/etc/pam.d/sudo_local` with nix-darwin" // {
default = true;
example = false;
};
When enabled, this option adds the following line to
{file}`/etc/pam.d/sudo`:
text = lib.mkOption {
type = lib.types.lines;
default = "";
description = ''
Contents of {file}`/etc/pam.d/sudo_local`
'';
};
```
auth sufficient pam_tid.so
```
touchIdAuth = lib.mkEnableOption "" // {
description = ''
Whether to enable Touch ID with sudo.
::: {.note}
macOS resets this file when doing a system update. As such, sudo
authentication with Touch ID won't work after a system update
until the nix-darwin configuration is reapplied.
:::
'';
This will also allow your Apple Watch to be used for sudo. If this doesn't work,
you can go into `System Settings > Touch ID & Password` and toggle the switch for
your Apple Watch.
'';
};
watchIdAuth = lib.mkEnableOption "" // {
description = ''
Use Apple Watch for sudo authentication, for devices without Touch ID or
laptops with lids closed, consider using this.
When enabled, you can use your Apple Watch to authenticate sudo commands.
If this doesn't work, you can go into `System Settings > Touch ID & Password`
and toggle the switch for your Apple Watch.
'';
};
reattach = lib.mkEnableOption "" // {
description = ''
Whether to enable reattaching a program to the user's bootstrap session.
This fixes Touch ID for sudo not working inside tmux and screen.
This allows programs like tmux and screen that run in the background to
survive across user sessions to work with PAM services that are tied to the
bootstrap session.
'';
};
};
};
config = {
system.activationScripts.pam.text = ''
security.pam.services.sudo_local.text = lib.concatLines (
(lib.optional cfg.reattach "auth optional ${pkgs.pam-reattach}/lib/pam/pam_reattach.so")
++ (lib.optional cfg.touchIdAuth "auth sufficient pam_tid.so")
++ (lib.optional cfg.watchIdAuth "auth sufficient ${pkgs.pam-watchid}/lib/pam_watchid.so")
);
environment.etc."pam.d/sudo_local" = {
inherit (cfg) enable text;
};
system.activationScripts.pam.text =
let
file = "/etc/pam.d/sudo";
marker = "security.pam.services.sudo_local";
deprecatedOption = "security.pam.enableSudoTouchIdAuth";
sed = lib.getExe pkgs.gnused;
in
''
# PAM settings
echo >&2 "setting up pam..."
${mkSudoTouchIdAuthScript cfg.enableSudoTouchIdAuth}
# REMOVEME when macOS 13 no longer supported as macOS automatically
# nukes this file on system upgrade
# Always clear out older implementation if it is present
if grep '${deprecatedOption}' ${file} > /dev/null; then
${sed} -i '/${deprecatedOption}/d' ${file}
fi
${if cfg.enable then ''
# REMOVEME when macOS 13 no longer supported
# `sudo_local` is automatically included after macOS 14
if ! grep 'sudo_local' ${file} > /dev/null; then
${sed} -i '2iauth include sudo_local # nix-darwin: ${marker}' ${file}
fi
'' else ''
# Remove include line if we added it
if grep '${marker}' ${file} > /dev/null; then
${sed} -i '/${marker}/d' ${file}
fi
''}
'';
};
}

View file

@ -21,14 +21,15 @@
ln -sfn $(cat ${config.system.profile}/systemConfig) /run/current-system
# Prevent the current configuration from being garbage-collected.
ln -sfn /run/current-system /nix/var/nix/gcroots/current-system
if [[ -d /nix/var/nix/gcroots ]]; then
ln -sfn /run/current-system /nix/var/nix/gcroots/current-system
fi
${config.system.activationScripts.etcChecks.text}
${config.system.activationScripts.etc.text}
${config.system.activationScripts.keyboard.text}
'';
serviceConfig.RunAtLoad = true;
serviceConfig.KeepAlive.SuccessfulExit = false;
};
};
}

View file

@ -227,8 +227,9 @@ in
{ path = cfg.runtimePackages ++ [ cfg.package pkgs.coreutils pkgs.darwin.DarwinTools ];
environment = {
HOME = cfg.dataDir;
NIX_REMOTE = "daemon";
inherit (config.environment.variables) NIX_SSL_CERT_FILE;
} // (if config.nix.useDaemon then { NIX_REMOTE = "daemon"; } else {});
};
## NB: maximum care is taken so that secrets (ssh keys and the CI token)
## don't end up in the Nix store.

View file

@ -51,6 +51,14 @@ in {
};
config = mkIf cfg.enable {
# TODO: Upstream this to NixOS.
assertions = [
{
assertion = config.nix.enable;
message = ''`services.cachix-agent.enable` requires `nix.enable`'';
}
];
launchd.daemons.cachix-agent = {
script = ''
. ${cfg.credentialsFile}

View file

@ -0,0 +1,81 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.dnscrypt-proxy;
format = pkgs.formats.toml { };
configFile = format.generate "dnscrypt-proxy.toml" cfg.settings;
in
{
options.services.dnscrypt-proxy = {
enable = lib.mkEnableOption "the dnscrypt-proxy service.";
package = lib.mkPackageOption pkgs "dnscrypt-proxy" { };
settings = lib.mkOption {
description = ''
Attrset that is converted and passed as TOML config file.
For available params, see: <https://github.com/DNSCrypt/dnscrypt-proxy/blob/${pkgs.dnscrypt-proxy.version}/dnscrypt-proxy/example-dnscrypt-proxy.toml>
'';
example = lib.literalExpression ''
{
sources.public-resolvers = {
urls = [ "https://download.dnscrypt.info/resolvers-list/v2/public-resolvers.md" ];
cache_file = "public-resolvers.md";
minisign_key = "RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3";
refresh_delay = 72;
};
}
'';
type = format.type;
default = { };
};
};
config = lib.mkIf cfg.enable {
users.users._dnscrypt-proxy = {
uid = config.ids.uids._dnscrypt-proxy;
gid = config.ids.gids._dnscrypt-proxy;
home = "/var/lib/dnscrypt-proxy";
createHome = true;
shell = "/usr/bin/false";
description = "System user for dnscrypt-proxy";
};
users.groups._dnscrypt-proxy = {
gid = config.ids.gids._dnscrypt-proxy;
description = "System group for dnscrypt-proxy";
};
users.knownUsers = [ "_dnscrypt-proxy" ];
users.knownGroups = [ "_dnscrypt-proxy" ];
launchd.daemons.dnscrypt-proxy = {
script = ''
${lib.getExe' cfg.package "dnscrypt-proxy"} -config ${configFile}
'';
serviceConfig =
let
logPath = config.users.users._dnscrypt-proxy.home + "/dnscrypt-proxy.log";
in
{
RunAtLoad = true;
KeepAlive = true;
StandardOutPath = logPath;
StandardErrorPath = logPath;
GroupName = "_dnscrypt-proxy";
UserName = "_dnscrypt-proxy";
};
};
};
}

View file

@ -13,6 +13,11 @@ in
{
config.assertions = flatten (
flip mapAttrsToList config.services.github-runners (name: cfg: map (mkIf cfg.enable) [
# TODO: Upstream this to NixOS.
{
assertion = config.nix.enable;
message = ''`services.github-runners.${name}.enable` requires `nix.enable`'';
}
{
assertion = (cfg.user == null && cfg.group == null) || (cfg.user != null);
message = "`services.github-runners.${name}`: Either set `user` and `group` to `null` to have nix-darwin manage them or set at least `user` explicitly";
@ -52,22 +57,19 @@ in
text = mkBefore (''
echo >&2 "setting up GitHub Runner '${cfg.name}'..."
(
umask -S u=rwx,g=rx,o= > /dev/null
# shellcheck disable=SC2174
${getExe' pkgs.coreutils "mkdir"} -p -m u=rwx,g=rx,o= ${escapeShellArg (mkStateDir cfg)}
${getExe' pkgs.coreutils "chown"} ${user}:${group} ${escapeShellArg (mkStateDir cfg)}
${getExe' pkgs.coreutils "mkdir"} -p ${escapeShellArg (mkStateDir cfg)}
${getExe' pkgs.coreutils "chown"} ${user}:${group} ${escapeShellArg (mkStateDir cfg)}
# shellcheck disable=SC2174
${getExe' pkgs.coreutils "mkdir"} -p -m u=rwx,g=rx,o= ${escapeShellArg (mkLogDir cfg)}
${getExe' pkgs.coreutils "chown"} ${user}:${group} ${escapeShellArg (mkLogDir cfg)}
${getExe' pkgs.coreutils "mkdir"} -p ${escapeShellArg (mkLogDir cfg)}
# launchd will fail to start the service if the outer direction doesn't have sufficient permissions
${getExe' pkgs.coreutils "chmod"} o+rx ${escapeShellArg (mkLogDir { name = ""; })}
${getExe' pkgs.coreutils "chown"} ${user}:${group} ${escapeShellArg (mkLogDir cfg)}
${optionalString (cfg.workDir == null) ''
${getExe' pkgs.coreutils "mkdir"} -p ${escapeShellArg (mkWorkDir cfg)}
${getExe' pkgs.coreutils "chown"} ${user}:${group} ${escapeShellArg (mkWorkDir cfg)}
''}
)
${optionalString (cfg.workDir == null) ''
# shellcheck disable=SC2174
${getExe' pkgs.coreutils "mkdir"} -p -m u=rwx,g=rx,o= ${escapeShellArg (mkWorkDir cfg)}
${getExe' pkgs.coreutils "chown"} ${user}:${group} ${escapeShellArg (mkWorkDir cfg)}
''}
'');
};
}));

View file

@ -551,8 +551,9 @@ in
launchd.daemons.gitlab-runner = {
environment = { #config.networking.proxy.envVars // {
HOME = "${config.users.users.gitlab-runner.home}";
NIX_REMOTE = "daemon";
NIX_SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
} // (if config.nix.useDaemon then { NIX_REMOTE = "daemon"; } else {});
};
path = with pkgs; [
bash
gawk

View file

@ -22,6 +22,14 @@ in
};
config = mkIf cfg.enable {
# TODO: Upstream this to NixOS.
assertions = [
{
assertion = config.nix.enable;
message = ''`services.hercules-ci-agent.enable` requires `nix.enable`'';
}
];
launchd.daemons.hercules-ci-agent = {
script = "exec ${cfg.package}/bin/hercules-ci-agent --config ${cfg.tomlFile}";
@ -74,7 +82,7 @@ in
darwin.label = config.system.darwinLabel;
darwin.revision = config.system.darwinRevision;
darwin.version = config.system.darwinVersion;
darwin.nix.daemon = config.nix.useDaemon;
darwin.nix.daemon = true;
darwin.nix.sandbox = config.nix.settings.sandbox;
};
};

View file

@ -29,6 +29,14 @@ in
};
config = mkIf cfg.enable {
# TODO: Upstream this to NixOS.
assertions = [
{
assertion = config.nix.enable;
message = ''`services.lorri.enable` requires `nix.enable`'';
}
];
environment.systemPackages = [ pkgs.lorri ];
launchd.user.agents.lorri = {
command = with pkgs; "${lorri}/bin/lorri daemon";
@ -43,4 +51,4 @@ in
};
};
};
}
}

View file

@ -30,8 +30,7 @@ in {
launchd.daemons.nextdns = {
path = [ nextdns ];
serviceConfig.ProgramArguments =
[ "${pkgs.nextdns}/bin/nextdns" "run" ] ++ cfg.arguments;
command = concatStringsSep " " (["${pkgs.nextdns}/bin/nextdns run"] ++ cfg.arguments);
serviceConfig.KeepAlive = true;
serviceConfig.RunAtLoad = true;
};

View file

@ -3,17 +3,18 @@
let
cfg = config.services.nix-daemon;
inherit (lib) mkDefault mkIf mkMerge mkOption types;
inherit (lib) mkRemovedOptionModule mkDefault mkIf mkMerge mkOption types;
in
{
options = {
services.nix-daemon.enable = mkOption {
type = types.bool;
default = true;
description = "Whether to enable the nix-daemon service.";
};
imports = [
(mkRemovedOptionModule [ "services" "nix-daemon" "enable" ] ''
nix-darwin now manages nix-daemon unconditionally when
`nix.enable` is on.
'')
];
options = {
services.nix-daemon.enableSocketListener = mkOption {
type = types.bool;
default = false;
@ -39,9 +40,7 @@ in
};
};
config = mkIf cfg.enable {
nix.useDaemon = true;
config = mkIf config.nix.enable {
launchd.daemons.nix-daemon = {
command = lib.getExe' config.nix.package "nix-daemon";

View file

@ -14,6 +14,7 @@ in
(mkRemovedOptionModule [ "nix" "gc" "dates" ] "Use `nix.gc.interval` instead.")
(mkRemovedOptionModule [ "nix" "gc" "randomizedDelaySec" ] "No `nix-darwin` equivalent to this NixOS option.")
(mkRemovedOptionModule [ "nix" "gc" "persistent" ] "No `nix-darwin` equivalent to this NixOS option.")
(mkRemovedOptionModule [ "nix" "gc" "user" ] "The garbage collection service now always runs as `root`.")
];
###### interface
@ -28,13 +29,6 @@ in
description = "Automatically run the garbage collector at a specific time.";
};
# Not in NixOS module
user = mkOption {
type = types.nullOr types.str;
default = null;
description = "User that runs the garbage collector.";
};
interval = mkOption {
type = launchdTypes.StartCalendarInterval;
default = [{ Weekday = 7; Hour = 3; Minute = 15; }];
@ -62,15 +56,18 @@ in
###### implementation
config = mkIf cfg.automatic {
config = {
assertions = [
{
assertion = cfg.automatic -> config.nix.enable;
message = ''nix.gc.automatic requires nix.enable'';
}
];
launchd.daemons.nix-gc = {
launchd.daemons.nix-gc = mkIf cfg.automatic {
command = "${config.nix.package}/bin/nix-collect-garbage ${cfg.options}";
environment.NIX_REMOTE = optionalString config.nix.useDaemon "daemon";
serviceConfig.RunAtLoad = false;
serviceConfig.StartCalendarInterval = cfg.interval;
serviceConfig.UserName = cfg.user;
};
};
}

View file

@ -20,6 +20,7 @@ in
{
imports = [
(mkRemovedOptionModule [ "nix" "optimise" "dates" ] "Use `nix.optimise.interval` instead.")
(mkRemovedOptionModule [ "nix" "optimise" "user" ] "The store optimisation service now always runs as `root`.")
];
###### interface
@ -34,13 +35,6 @@ in
description = "Automatically run the nix store optimiser at a specific time.";
};
# Not in NixOS module
user = mkOption {
type = types.nullOr types.str;
default = null;
description = "User that runs the store optimisation.";
};
interval = mkOption {
type = launchdTypes.StartCalendarInterval;
default = [{ Weekday = 7; Hour = 4; Minute = 15; }];
@ -58,17 +52,20 @@ in
###### implementation
config = mkIf cfg.automatic {
config = {
assertions = [
{
assertion = cfg.automatic -> config.nix.enable;
message = ''nix.optimise.automatic requires nix.enable'';
}
];
launchd.daemons.nix-optimise = {
environment.NIX_REMOTE = optionalString config.nix.useDaemon "daemon";
launchd.daemons.nix-optimise = mkIf cfg.automatic {
command = "${lib.getExe' config.nix.package "nix-store"} --optimise";
serviceConfig = {
RunAtLoad = false;
StartCalendarInterval = cfg.interval;
UserName = cfg.user;
};
};
};
}

View file

@ -46,6 +46,13 @@ in
};
config = mkIf cfg.enable {
assertions = [
{
assertion = config.nix.enable;
message = ''`services.ofborg.enable` requires `nix.enable`'';
}
];
warnings = mkIf (isDerivation cfg.configFile) [
"services.ofborg.configFile is a derivation, credentials will be world readable"
];

View file

@ -13,6 +13,32 @@ let
mkTextDerivation = name: text: pkgs.writeScript "activate-${name}" text;
};
activationPath =
lib.makeBinPath [
pkgs.gnugrep
pkgs.coreutils
]
+ lib.optionalString (!config.nix.enable) ''
$(
# If `nix.enable` is off, there might be an unmanaged Nix
# installation (say in `/nix/var/nix/profiles/default`) that
# activation scripts (such as Home Manager) want to find on the
# `$PATH`. Search for it directly to avoid polluting the
# activation script environment with everything on the
# `environment.systemPath`.
if nixEnvPath=$(
PATH="${config.environment.systemPath}" command -v nix-env
); then
printf ':'
${lib.getExe' pkgs.coreutils "dirname"} -- "$(
${lib.getExe' pkgs.coreutils "readlink"} \
--canonicalize-missing \
-- "$nixEnvPath"
)"
fi
)''
+ ":@out@/sw/bin:/usr/bin:/bin:/usr/sbin:/sbin";
in
{
@ -40,13 +66,12 @@ in
#! ${stdenv.shell}
set -e
set -o pipefail
export PATH="${pkgs.gnugrep}/bin:${pkgs.coreutils}/bin:@out@/sw/bin:/usr/bin:/bin:/usr/sbin:/sbin"
PATH="${activationPath}"
export PATH
systemConfig=@out@
_status=0
trap "_status=1" ERR
# Ensure a consistent umask.
umask 0022
@ -81,9 +106,9 @@ in
ln -sfn "$(readlink -f "$systemConfig")" /run/current-system
# Prevent the current configuration from being garbage-collected.
ln -sfn /run/current-system /nix/var/nix/gcroots/current-system
exit $_status
if [[ -d /nix/var/nix/gcroots ]]; then
ln -sfn /run/current-system /nix/var/nix/gcroots/current-system
fi
'';
# FIXME: activationScripts.checks should be system level
@ -91,7 +116,9 @@ in
#! ${stdenv.shell}
set -e
set -o pipefail
export PATH="${pkgs.gnugrep}/bin:${pkgs.coreutils}/bin:@out@/sw/bin:/usr/bin:/bin"
PATH="${activationPath}"
export PATH
systemConfig=@out@

View file

@ -8,24 +8,8 @@ let
cfg = config.system.checks;
darwinChanges = ''
darwinChanges=/dev/null
if test -e /run/current-system/darwin-changes; then
darwinChanges=/run/current-system/darwin-changes
fi
darwinChanges=$(diff --changed-group-format='%>' --unchanged-group-format= /run/current-system/darwin-changes $systemConfig/darwin-changes 2> /dev/null) || true
if test -n "$darwinChanges"; then
echo >&2
echo "CHANGELOG" >&2
echo >&2
echo "$darwinChanges" >&2
echo >&2
fi
'';
macOSVersion = ''
IFS=. read -ra osVersion <<<"$(sw_vers --productVersion)"
IFS=. read -ra osVersion <<<"$(sw_vers -productVersion)"
if (( osVersion[0] < 11 || (osVersion[0] == 11 && osVersion[1] < 3) )); then
printf >&2 '\e[1;31merror: macOS version is less than 11.3, aborting activation\e[0m\n'
printf >&2 'Nixpkgs 25.05 requires macOS Big Sur 11.3 or newer, and 25.11 will\n'
@ -43,33 +27,35 @@ let
printf >&2 ' system.checks.verifyMacOSVersion = false;\n'
printf >&2 '\n'
printf >&2 'However, we are unable to provide support if you do so.\n'
exit 1
exit 2
fi
'';
oldBuildUsers = ''
if dscl . -list /Users | grep -q '^nixbld'; then
echo "error: Detected old style nixbld users, aborting activation" >&2
echo "These can cause migration problems when upgrading to certain macOS versions" >&2
echo "You can enable the following option to migrate to new style nixbld users" >&2
echo >&2
echo " nix.configureBuildUsers = true;" >&2
echo >&2
echo "or disable this check with" >&2
echo >&2
echo " system.checks.verifyBuildUsers = false;" >&2
echo >&2
exit 2
fi
'';
determinate = ''
if [[ -e /usr/local/bin/determinate-nixd ]]; then
printf >&2 '\e[1;31merror: Determinate detected, aborting activation\e[0m\n'
printf >&2 'Determinate uses its own daemon to manage the Nix installation that\n'
printf >&2 'conflicts with nix-darwins native Nix management.\n'
printf >&2 '\n'
printf >&2 'To turn off nix-darwins management of the Nix installation, set:\n'
printf >&2 '\n'
printf >&2 ' nix.enable = false;\n'
printf >&2 '\n'
printf >&2 'This will allow you to use nix-darwin with Determinate. Some nix-darwin\n'
printf >&2 'functionality that relies on managing the Nix installation, like the\n'
printf >&2 '`nix.*` options to adjust Nix settings or configure a Linux builder,\n'
printf >&2 'will be unavailable.\n'
exit 2
fi
'';
preSequoiaBuildUsers = ''
${lib.optionalString config.nix.configureBuildUsers ''
# Dont complain when were about to migrate oldstyle build users…
if ! dscl . -list /Users | grep -q '^nixbld'; then
''}
firstBuildUserID=$(dscl . -read /Users/_nixbld1 UniqueID | awk '{print $2}')
if [[ $firstBuildUserID != ${toString (config.ids.uids.nixbld + 1)} ]]; then
if
# Dont complain when were about to migrate oldstyle build users…
[[ $firstBuildUserID != ${toString (config.ids.uids.nixbld + 1)} ]] \
&& ! dscl . -list /Users | grep -q '^nixbld'
then
printf >&2 '\e[1;31merror: Build users have unexpected UIDs, aborting activation\e[0m\n'
printf >&2 'The default Nix build user ID range has been adjusted for\n'
printf >&2 'compatibility with macOS Sequoia 15. Your _nixbld1 user currently has\n'
@ -102,22 +88,6 @@ let
printf >&2 '\n'
exit 2
fi
${lib.optionalString config.nix.configureBuildUsers "fi"}
'';
buildUsers = ''
buildUser=$(dscl . -read /Groups/nixbld GroupMembership 2>&1 | awk '/^GroupMembership: / {print $2}') || true
if [[ -z "$buildUser" ]]; then
echo "error: Using the nix-daemon requires build users, aborting activation" >&2
echo "Create the build users or disable the daemon:" >&2
echo "$ darwin-install" >&2
echo >&2
echo "or set (this requires some manual intervention to restore permissions)" >&2
echo >&2
echo " services.nix-daemon.enable = false;" >&2
echo >&2
exit 2
fi
'';
buildGroupID = ''
@ -146,45 +116,21 @@ let
fi
'';
nixDaemon = if config.nix.useDaemon then ''
if ! dscl . -read /Groups/nixbld PrimaryGroupID &> /dev/null; then
printf >&2 'error: The daemon should not be enabled for single-user installs, aborting activation\n'
printf >&2 'Disable the nix-daemon service:\n'
nixDaemon = ''
if [[ "$(stat --format='%u' /nix)" != 0 ]]; then
printf >&2 'error: singleuser install detected, aborting activation\n'
printf >&2 'nix-darwin now only supports managing multiuser daemon installations\n'
printf >&2 'of Nix. You can uninstall nix-darwin and Nix and then reinstall both to\n'
printf >&2 'fix this.\n'
printf >&2 '\n'
printf >&2 ' services.nix-daemon.enable = false;\n'
printf >&2 'If you dont want to do that, you can disable management of the Nix\n'
printf >&2 'installation with:\n'
printf >&2 '\n'
printf >&2 'and remove `nix.useDaemon` from your configuration if it is present.\n'
printf >&2 ' nix.enable = false;\n'
printf >&2 '\n'
printf >&2 'See the `nix.enable` option documentation for caveats.\n'
exit 2
fi
'' else ''
if dscl . -read /Groups/nixbld PrimaryGroupID &> /dev/null; then
printf >&2 'error: The daemon should be enabled for multi-user installs, aborting activation\n'
printf >&2 'Enable the nix-daemon service:\n'
printf >&2 '\n'
printf >&2 ' services.nix-daemon.enable = true;\n'
printf >&2 '\n'
exit 2
fi
'';
nixChannels = ''
channelsLink=$(readlink "$HOME/.nix-defexpr/channels") || true
case "$channelsLink" in
*"$USER"*)
;;
"")
;;
*)
echo "error: The ~/.nix-defexpr/channels symlink does not point your users channels, aborting activation" >&2
echo "Running nix-channel will regenerate it" >&2
echo >&2
echo " rm ~/.nix-defexpr/channels" >&2
echo " nix-channel --update" >&2
echo >&2
exit 2
;;
esac
'';
nixInstaller = ''
@ -209,7 +155,7 @@ let
darwinConfig=$(NIX_PATH=$nixPath nix-instantiate --find-file darwin-config) || true
if ! test -e "$darwinConfig"; then
echo "error: Changed <darwin-config> but target does not exist, aborting activation" >&2
echo "Create ''${darwinConfig:-~/.nixpkgs/darwin-configuration.nix} or set environment.darwinConfig:" >&2
echo "Create ''${darwinConfig:-/etc/nix-darwin/configuration.nix} or set environment.darwinConfig:" >&2
echo >&2
echo " environment.darwinConfig = \"$(nix-instantiate --find-file darwin-config 2> /dev/null || echo '***')\";" >&2
echo >&2
@ -249,43 +195,6 @@ let
fi
'';
nixStore = ''
if test -w /nix/var/nix/db -a ! -O /nix/store; then
echo >&2 "error: the store is not owned by this user, but /nix/var/nix/db is writable"
echo >&2 "If you are using the daemon:"
echo >&2
echo >&2 " sudo chown -R root:wheel /nix/var/nix/db"
echo >&2
echo >&2 "Otherwise:"
echo >&2
echo >&2 " sudo chown -R $USER:staff /nix/store"
echo >&2
exit 2
fi
'';
nixGarbageCollector = ''
if test -O /nix/store; then
echo "error: A single-user install can't run gc as root, aborting activation" >&2
echo "Configure the garbage collector to run as the current user:" >&2
echo >&2
echo " nix.gc.user = \"$USER\";" >&2
echo >&2
exit 2
fi
'';
nixStoreOptimiser = ''
if test -O /nix/store; then
echo "error: A single-user install can't run optimiser as root, aborting activation" >&2
echo "Configure the optimiser to run as the current user:" >&2
echo >&2
echo " nix.optimise.user = \"$USER\";" >&2
echo >&2
exit 2
fi
'';
# TODO: Remove this a couple years down the line when we can assume
# that anyone who cares about security has upgraded.
oldSshAuthorizedKeysDirectory = ''
@ -331,24 +240,21 @@ let
in
{
imports = [
(mkRemovedOptionModule [ "system" "checks" "verifyNixChannels" ] "This check has been removed.")
];
options = {
system.checks.verifyNixPath = mkOption {
type = types.bool;
default = true;
default = config.nix.enable;
description = "Whether to run the NIX_PATH validation checks.";
};
system.checks.verifyNixChannels = mkOption {
type = types.bool;
default = config.nix.channel.enable;
description = "Whether to run the nix-channels validation checks.";
};
system.checks.verifyBuildUsers = mkOption {
type = types.bool;
default =
(config.nix.useDaemon && !(config.nix.settings.auto-allocate-uids or false))
|| config.nix.configureBuildUsers;
config.nix.enable && !(config.nix.settings.auto-allocate-uids or false);
description = "Whether to run the Nix build users validation checks.";
};
@ -368,17 +274,11 @@ in
config = {
system.checks.text = mkMerge [
darwinChanges
(mkIf cfg.verifyMacOSVersion macOSVersion)
(mkIf (cfg.verifyBuildUsers && !config.nix.configureBuildUsers) oldBuildUsers)
(mkIf cfg.verifyBuildUsers buildUsers)
(mkIf config.nix.enable determinate)
(mkIf cfg.verifyBuildUsers preSequoiaBuildUsers)
(mkIf config.nix.configureBuildUsers buildGroupID)
nixDaemon
nixStore
(mkIf (config.nix.gc.automatic && config.nix.gc.user == null) nixGarbageCollector)
(mkIf (config.nix.optimise.automatic && config.nix.optimise.user == null) nixStoreOptimiser)
(mkIf cfg.verifyNixChannels nixChannels)
(mkIf cfg.verifyBuildUsers buildGroupID)
(mkIf config.nix.enable nixDaemon)
nixInstaller
(mkIf cfg.verifyNixPath nixPath)
oldSshAuthorizedKeysDirectory

View file

@ -2,10 +2,25 @@
with lib;
{
let
valueType = with lib.types; nullOr (oneOf [
bool
int
float
str
path
(attrsOf valueType)
(listOf valueType)
]) // {
description = "plist value";
};
defaultsType = types.submodule {
freeformType = valueType;
};
in {
options = {
system.defaults.CustomUserPreferences = mkOption {
type = types.attrs;
type = defaultsType;
default = { };
example = {
"NSGlobalDomain" = { "TISRomanSwitchState" = 1; };
@ -20,7 +35,7 @@ with lib;
};
system.defaults.CustomSystemPreferences = mkOption {
type = types.attrs;
type = defaultsType;
default = { };
example = {
"NSGlobalDomain" = { "TISRomanSwitchState" = 1; };

View file

@ -128,16 +128,72 @@ in {
};
system.defaults.dock.persistent-apps = mkOption {
type = types.nullOr (types.listOf (types.either types.path types.str));
type = let
taggedType = types.attrTag {
app = mkOption {
description = "An application to be added to the dock.";
type = types.str;
};
file = mkOption {
description = "A file to be added to the dock.";
type = types.str;
};
folder = mkOption {
description = "A folder to be added to the dock.";
type = types.str;
};
spacer = mkOption {
description = "A spacer to be added to the dock. Can be small or regular size.";
type = types.submodule {
options.small = mkOption {
description = "Whether the spacer is small.";
type = types.bool;
default = false;
};
};
};
};
simpleType = types.either types.str types.path;
toTagged = path: { app = path; };
in
types.nullOr (types.listOf (types.coercedTo simpleType toTagged taggedType));
default = null;
example = [ "/Applications/Safari.app" "/System/Applications/Utilities/Terminal.app" ];
example = [
{ app = "/Applications/Safari.app"; }
{ spacer = { small = false; }; }
{ spacer = { small = true; }; }
{ folder = "/System/Applications/Utilities"; }
{ file = "/User/example/Downloads/test.csv"; }
];
description = ''
Persistent applications in the dock.
Persistent applications, spacers, files, and folders in the dock.
'';
apply = value:
if !(isList value)
then value
else map (app: { tile-data = { file-data = { _CFURLString = app; _CFURLStringType = 0; }; }; }) value;
apply =
let
toTile = item: if item ? app then {
tile-data.file-data = {
_CFURLString = item.app;
_CFURLStringType = 0;
};
} else if item ? spacer then {
tile-data = { };
tile-type = if item.spacer.small then "small-spacer-tile" else "spacer-tile";
} else if item ? folder then {
tile-data.file-data = {
_CFURLString = "file://" + item.folder;
_CFURLStringType = 15;
};
tile-type = "directory-tile";
} else if item ? file then {
tile-data.file-data = {
_CFURLString = "file://" + item.file;
_CFURLStringType = 15;
};
tile-type = "file-tile";
} else item;
in
value: if value == null then null else map toTile value;
};
system.defaults.dock.persistent-others = mkOption {

View file

@ -51,7 +51,7 @@ in
system.maxStateVersion = mkOption {
internal = true;
type = types.int;
default = 5;
default = 6;
};
system.darwinLabel = mkOption {

View file

@ -11,14 +11,14 @@ let
group = import ./group.nix;
user = import ./user.nix;
toGID = v: { "${toString v.gid}" = v.name; };
toUID = v: { "${toString v.uid}" = v.name; };
toGID = n: v: { "${toString v.gid}" = n; };
toUID = n: v: { "${toString v.uid}" = n; };
isCreated = list: name: elem name list;
isDeleted = attrs: name: ! elem name (mapAttrsToList (n: v: v.name) attrs);
gids = mapAttrsToList (n: toGID) (filterAttrs (n: v: isCreated cfg.knownGroups v.name) cfg.groups);
uids = mapAttrsToList (n: toUID) (filterAttrs (n: v: isCreated cfg.knownUsers v.name) cfg.users);
gids = mapAttrsToList toGID (filterAttrs (n: v: isCreated cfg.knownGroups v.name) cfg.groups);
uids = mapAttrsToList toUID (filterAttrs (n: v: isCreated cfg.knownUsers v.name) cfg.users);
createdGroups = mapAttrsToList (n: v: cfg.groups."${v}") cfg.gids;
createdUsers = mapAttrsToList (n: v: cfg.users."${v}") cfg.uids;
@ -112,14 +112,14 @@ in
in
!user.ignoreShellProgramCheck -> (s == shell || (shell == "bash" && s == "bash-interactive")) -> (config.programs.${shell}.enable == true);
message = ''
users.users.${user.name}.shell is set to ${shell}, but
users.users.${name}.shell is set to ${shell}, but
programs.${shell}.enable is not true. This will cause the ${shell}
shell to lack the basic Nix directories in its PATH and might make
logging in as that user impossible. You can fix it with:
programs.${shell}.enable = true;
If you know what you're doing and you are fine with the behavior,
set users.users.${user.name}.ignoreShellProgramCheck = true;
set users.users.${name}.ignoreShellProgramCheck = true;
instead.
'';
}) [
@ -147,7 +147,7 @@ in
homeDirectory=''${homeDirectory#NFSHomeDirectory: }
if ! sudo dscl . -change /Users/nobody NFSHomeDirectory "$homeDirectory" "$homeDirectory" &> /dev/null; then
if [[ -n "$SSH_CONNECTION" ]]; then
if [[ "$(launchctl managername)" != Aqua ]]; then
printf >&2 '\e[1;31merror: users cannot be %s over SSH without Full Disk Access, aborting activation\e[0m\n' "$2"
printf >&2 'The user %s could not be %s as `darwin-rebuild` was not executed with Full Disk Access over SSH.\n' "$1" "$2"
printf >&2 'You can either:\n'
@ -172,7 +172,7 @@ in
printf >&2 '`darwin-rebuild` requires permissions to administrate your computer,\n'
printf >&2 'please accept the dialog that pops up.\n'
printf >&2 '\n'
printf >&2 'If you do not wish to be prompted every time `darwin-rebuild updates your users,\n'
printf >&2 'If you do not wish to be prompted every time `darwin-rebuild` updates your users,\n'
printf >&2 'you can grant Full Disk Access to your terminal emulator in System Settings.\n'
printf >&2 '\n'
printf >&2 'This can be found in System Settings > Privacy & Security > Full Disk Access.\n'
@ -331,7 +331,7 @@ in
environment.systemPackages = systemShells;
environment.etc = mapAttrs' (name: { packages, ... }: {
name = "profiles/per-user/${name}";
name = "profiles/per-user/${cfg.users.${name}.name}";
value.source = pkgs.buildEnv {
name = "user-environment";
paths = packages;

View file

@ -12,8 +12,8 @@ with lib;
launchd.daemons = mkForce {};
launchd.user.agents = mkForce {};
# Don't try to reload `nix-daemon`
nix.useDaemon = mkForce false;
# Restore any unmanaged `nix-daemon`.
nix.enable = false;
system.activationScripts.postUserActivation.text = mkAfter ''
nix-channel --remove darwin || true
@ -30,14 +30,6 @@ with lib;
rm /etc/static
fi
# If the Nix Store is owned by root then we're on a multi-user system
if [[ -O /nix/store ]]; then
if [[ -e /nix/var/nix/profiles/default/Library/LaunchDaemons/org.nixos.nix-daemon.plist ]]; then
sudo cp /nix/var/nix/profiles/default/Library/LaunchDaemons/org.nixos.nix-daemon.plist /Library/LaunchDaemons/org.nixos.nix-daemon.plist
sudo launchctl load -w /Library/LaunchDaemons/org.nixos.nix-daemon.plist
fi
fi
# grep will return 1 when no lines matched which makes this line fail with `set -eo pipefail`
dscl . -list /Users UserShell | { grep "\s/run/" || true; } | awk '{print $1}' | while read -r user; do
shell=$(dscl . -read /Users/"$user" UserShell)

View file

@ -8,7 +8,7 @@ let
{
nixpkgs.source = path;
nixpkgs.hostPlatform = stdenv.hostPlatform.system;
system.includeUninstaller = false;
system.tools.darwin-uninstaller.enable = false;
}
];
};
@ -31,8 +31,11 @@ in writeShellApplication {
echo >&2 " - remove /Applications/Nix Apps symlink"
echo >&2 " - cleanup static /etc files"
echo >&2 " - disable and remove all launchd services managed by nix-darwin"
if [[ $(stat -f '%Su' /nix/store) == "root" ]]; then
echo >&2 " - restore nix-daemon service from nix installer as this is a multi-user install"
if [[
-e /run/current-system/Library/LaunchDaemons/org.nixos.nix-daemon.plist
&& -e /nix/var/nix/profiles/default/Library/LaunchDaemons/org.nixos.nix-daemon.plist
]]; then
echo >&2 " - restore nix-daemon service from the Nix installer"
fi
echo >&2
@ -87,7 +90,7 @@ in writeShellApplication {
launchctl print system/org.nixos.nix-daemon
pgrep -l nix-daemon
test -e /Library/LaunchDaemons/org.nixos.nix-daemon.plist
[[ "$(shasum -a 256 /Library/LaunchDaemons/org.nixos.nix-daemon.plist | awk '{print $1}')" == "$(shasum -a 256 /Library/LaunchDaemons/org.nixos.nix-daemon.plist | awk '{print $1}')" ]]
[[ "$(shasum -a 256 /Library/LaunchDaemons/org.nixos.nix-daemon.plist | awk '{print $1}')" == "$(shasum -a 256 /nix/var/nix/profiles/default/Library/LaunchDaemons/org.nixos.nix-daemon.plist | awk '{print $1}')" ]]
nix-store --store daemon -q --hash ${stdenv.shell}
fi
echo >&2 ok

View file

@ -80,7 +80,6 @@ in {
tests.activation-scripts = makeTest ./tests/activation-scripts.nix;
tests.autossh = makeTest ./tests/autossh.nix;
tests.checks-nix-gc = makeTest ./tests/checks-nix-gc.nix;
tests.environment-path = makeTest ./tests/environment-path.nix;
tests.environment-terminfo = makeTest ./tests/environment-terminfo.nix;
tests.homebrew = makeTest ./tests/homebrew.nix;
@ -88,6 +87,7 @@ in {
tests.launchd-setenv = makeTest ./tests/launchd-setenv.nix;
tests.networking-hostname = makeTest ./tests/networking-hostname.nix;
tests.networking-networkservices = makeTest ./tests/networking-networkservices.nix;
tests.nix-enable = makeTest ./tests/nix-enable.nix;
tests.nixpkgs-overlays = makeTest ./tests/nixpkgs-overlays.nix;
tests.programs-ssh = makeTest ./tests/programs-ssh.nix;
tests.programs-tmux = makeTest ./tests/programs-tmux.nix;
@ -103,6 +103,7 @@ in {
tests.sockets-nix-daemon = makeTest ./tests/sockets-nix-daemon.nix;
tests.services-aerospace = makeTest ./tests/services-aerospace.nix;
tests.services-dnsmasq = makeTest ./tests/services-dnsmasq.nix;
tests.services-dnscrypt-proxy = makeTest ./tests/services-dnscrypt-proxy.nix;
tests.services-eternal-terminal = makeTest ./tests/services-eternal-terminal.nix;
tests.services-nix-gc = makeTest ./tests/services-nix-gc.nix;
tests.services-nix-optimise = makeTest ./tests/services-nix-optimise.nix;

View file

@ -1,19 +0,0 @@
{ config, pkgs, ... }:
let
nix = pkgs.runCommand "nix-2.2" {} "mkdir -p $out";
in
{
nix.gc.automatic = true;
nix.package = nix;
test = ''
echo checking nix-gc validation >&2
grep "nix.gc.user = " ${config.out}/activate-user
echo checking nix-gc service in /Library/LaunchDaemons >&2
grep "<string>org.nixos.nix-gc</string>" ${config.out}/Library/LaunchDaemons/org.nixos.nix-gc.plist
(! grep "<key>UserName</key>" ${config.out}/Library/LaunchDaemons/org.nixos.nix-gc.plist)
'';
}

View file

@ -255,7 +255,7 @@ defaults write com.apple.dock 'persistent-apps' $'<?xml version="1.0" encoding="
<key>file-data</key>
<dict>
<key>_CFURLString</key>
<string>MyApp.app</string>
<string>/Applications/MyApp.app</string>
<key>_CFURLStringType</key>
<integer>0</integer>
</dict>
@ -267,12 +267,56 @@ defaults write com.apple.dock 'persistent-apps' $'<?xml version="1.0" encoding="
<key>file-data</key>
<dict>
<key>_CFURLString</key>
<string>Cool.app</string>
<string>/Applications/Cool.app</string>
<key>_CFURLStringType</key>
<integer>0</integer>
</dict>
</dict>
</dict>
<dict>
<key>tile-data</key>
<dict>
</dict>
<key>tile-type</key>
<string>small-spacer-tile</string>
</dict>
<dict>
<key>tile-data</key>
<dict>
</dict>
<key>tile-type</key>
<string>spacer-tile</string>
</dict>
<dict>
<key>tile-data</key>
<dict>
<key>file-data</key>
<dict>
<key>_CFURLString</key>
<string>file:///Applications/Utilities</string>
<key>_CFURLStringType</key>
<integer>15</integer>
</dict>
</dict>
<key>tile-type</key>
<string>directory-tile</string>
</dict>
<dict>
<key>tile-data</key>
<dict>
<key>file-data</key>
<dict>
<key>_CFURLString</key>
<string>file:///Users/example/Downloads/test.csv</string>
<key>_CFURLStringType</key>
<integer>15</integer>
</dict>
</dict>
<key>tile-type</key>
<string>file-tile</string>
</dict>
</array>
</plist>'
defaults write com.apple.dock 'persistent-others' $'<?xml version="1.0" encoding="UTF-8"?>
@ -499,6 +543,14 @@ defaults write NSGlobalDomain 'TISRomanSwitchState' $'<?xml version="1.0" encodi
<plist version="1.0">
<integer>1</integer>
</plist>'
defaults write com.apple.Safari 'NSUserKeyEquivalents' $'<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Quit Safari</key>
<string>@^q</string>
</dict>
</plist>'
defaults write com.apple.Safari 'com.apple.Safari.ContentPageGroupIdentifier.WebKit2DeveloperExtrasEnabled' $'<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">

16
tests/nix-enable.nix Normal file
View file

@ -0,0 +1,16 @@
{ config, ... }:
{
nix.enable = false;
test = ''
printf >&2 'checking for unexpected Nix binary in /sw/bin\n'
[[ -e ${config.out}/sw/bin/nix-env ]] && exit 1
printf >&2 'checking for unexpected nix-daemon plist in /Library/LaunchDaemons\n'
[[ -e ${config.out}/Library/LaunchDaemons/org.nixos.nix-daemon.plist ]] && exit 1
printf >&2 'checking for latebound Nix lookup in /activate\n'
grep nixEnvPath= ${config.out}/activate
'';
}

View file

@ -0,0 +1,23 @@
{
config,
pkgs,
...
}:
let
dnscrypt-proxy = pkgs.runCommand "dnscrypt-proxy-0.0.0" { } "mkdir $out";
in
{
services.dnscrypt-proxy.enable = true;
services.dnscrypt-proxy.package = dnscrypt-proxy;
test = ''
echo >&2 "checking dnscrypt-proxy service in /Library/LaunchDaemons"
grep -q "org.nixos.dnscrypt-proxy" -- ${config.out}/Library/LaunchDaemons/org.nixos.dnscrypt-proxy.plist
grep -q "dnscrypt-proxy-start" -- ${config.out}/Library/LaunchDaemons/org.nixos.dnscrypt-proxy.plist
echo >&2 "checking dnscrypt-proxy system user in /Library/LaunchDaemons"
grep -q "_dnscrypt-proxy" -- ${config.out}/Library/LaunchDaemons/org.nixos.dnscrypt-proxy.plist
'';
}

View file

@ -6,7 +6,6 @@ let
in
{
services.nix-daemon.enable = true;
nix.package = nix;
launchd.labelPrefix = "org.nix-darwin"; # should not have an effect on nix-daemon
@ -27,8 +26,5 @@ in
echo checking nix-daemon reload in /activate >&2
grep "launchctl kill HUP system/org.nixos.nix-daemon" ${config.out}/activate
echo checking NIX_REMOTE=daemon in setEnvironment >&2
grep "NIX_REMOTE=daemon" ${config.system.build.setEnvironment}
'';
}

View file

@ -7,19 +7,13 @@ in
{
nix.gc.automatic = true;
nix.gc.options = "--delete-older-than 30d";
nix.gc.user = "nixuser";
nix.package = nix;
test = ''
echo checking nix-gc service in /Library/LaunchDaemons >&2
grep "<string>org.nixos.nix-gc</string>" ${config.out}/Library/LaunchDaemons/org.nixos.nix-gc.plist
grep "<string>/bin/wait4path /nix/store &amp;&amp; exec ${nix}/bin/nix-collect-garbage --delete-older-than 30d</string>" ${config.out}/Library/LaunchDaemons/org.nixos.nix-gc.plist
grep "<key>UserName</key>" ${config.out}/Library/LaunchDaemons/org.nixos.nix-gc.plist
grep "<string>nixuser</string>" ${config.out}/Library/LaunchDaemons/org.nixos.nix-gc.plist
(! grep "<key>KeepAlive</key>" ${config.out}/Library/LaunchDaemons/org.nixos.nix-gc.plist)
echo checking nix-gc validation >&2
(! grep "nix.gc.user = " ${config.out}/activate-user)
'';
}

View file

@ -6,7 +6,6 @@ in
{
nix.optimise.automatic = true;
nix.optimise.user = "nixuser";
nix.package = nix;
test = ''
@ -15,11 +14,6 @@ in
${config.out}/Library/LaunchDaemons/org.nixos.nix-optimise.plist
grep "<string>/bin/wait4path /nix/store &amp;&amp; exec ${nix}/bin/nix-store --optimise</string>" \
${config.out}/Library/LaunchDaemons/org.nixos.nix-optimise.plist
grep "<key>UserName</key>" ${config.out}/Library/LaunchDaemons/org.nixos.nix-optimise.plist
grep "<string>nixuser</string>" ${config.out}/Library/LaunchDaemons/org.nixos.nix-optimise.plist
(! grep "<key>KeepAlive</key>" ${config.out}/Library/LaunchDaemons/org.nixos.nix-optimise.plist)
echo checking nix-optimise validation >&2
(! grep "nix.optimise.user = " ${config.out}/activate-user)
'';
}

View file

@ -5,7 +5,6 @@ let
in
{
services.nix-daemon.enable = true;
services.nix-daemon.enableSocketListener = true;
nix.package = nix;
launchd.labelPrefix = "org.nix-darwin"; # should not have an effect on nix-daemon

View file

@ -1,6 +1,25 @@
{ config, pkgs, lib, ... }:
{
imports = [
{
system.defaults.CustomUserPreferences = {
"NSGlobalDomain" = { "TISRomanSwitchState" = 1; };
"com.apple.Safari" = {
"com.apple.Safari.ContentPageGroupIdentifier.WebKit2DeveloperExtrasEnabled" =
true;
};
};
}
{
system.defaults.CustomUserPreferences = {
"com.apple.Safari" = {
"NSUserKeyEquivalents"."Quit Safari" = "@^q"; # Option-Cmd-Q
};
};
}
];
system.defaults.NSGlobalDomain.AppleShowAllFiles = true;
system.defaults.NSGlobalDomain.AppleEnableMouseSwipeNavigateWithScrolls = false;
system.defaults.NSGlobalDomain.AppleEnableSwipeNavigateWithScrolls = false;
@ -50,7 +69,14 @@
system.defaults.dock.appswitcher-all-displays = false;
system.defaults.dock.autohide-delay = 0.24;
system.defaults.dock.orientation = "left";
system.defaults.dock.persistent-apps = ["MyApp.app" "Cool.app"];
system.defaults.dock.persistent-apps = [
"/Applications/MyApp.app"
{ app = "/Applications/Cool.app"; }
{ spacer = { small = true; }; }
{ spacer = { small = false; }; }
{ folder = "/Applications/Utilities"; }
{ file = "/Users/example/Downloads/test.csv"; }
];
system.defaults.dock.persistent-others = ["~/Documents" "~/Downloads/file.txt"];
system.defaults.dock.scroll-to-open = false;
system.defaults.finder.AppleShowAllFiles = true;
@ -102,13 +128,6 @@
system.defaults.WindowManager.EnableTiledWindowMargins = true;
system.defaults.WindowManager.StandardHideWidgets = true;
system.defaults.WindowManager.StageManagerHideWidgets = true;
system.defaults.CustomUserPreferences = {
"NSGlobalDomain" = { "TISRomanSwitchState" = 1; };
"com.apple.Safari" = {
"com.apple.Safari.ContentPageGroupIdentifier.WebKit2DeveloperExtrasEnabled" =
true;
};
};
system.defaults.controlcenter.BatteryShowPercentage = true;
system.defaults.controlcenter.Sound = false;
system.defaults.controlcenter.Bluetooth = true;