summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--doc/known-files/5d23e6d7015756c6f300f8cd558ec4d9234ca61deefd4f2478e91a49760b07479
-rw-r--r--doc/known-files/d07015be6875f134976fce84c6c7a77b512079c1c5f9594dfa65c70b7968b65f7
-rw-r--r--doc/manual/default.nix2
-rw-r--r--modules/meta.nix2
-rw-r--r--modules/module-list.nix7
-rw-r--r--modules/nix/default.nix11
-rw-r--r--modules/nix/linux-builder.nix75
-rw-r--r--modules/programs/direnv.nix136
-rw-r--r--modules/programs/zsh/default.nix4
-rw-r--r--modules/security/sudo.nix30
-rw-r--r--modules/services/github-runner/default.nix6
-rw-r--r--modules/services/github-runner/options.nix269
-rw-r--r--modules/services/github-runner/service.nix181
-rw-r--r--modules/services/ipfs.nix7
-rw-r--r--modules/services/nix-optimise/default.nix73
-rw-r--r--modules/services/trezord.nix47
-rw-r--r--modules/system/activation-scripts.nix1
-rw-r--r--modules/system/checks.nix12
-rw-r--r--modules/system/defaults-write.nix12
-rw-r--r--modules/system/defaults/NSGlobalDomain.nix8
-rw-r--r--modules/system/defaults/dock.nix13
-rw-r--r--modules/system/nvram.nix40
-rw-r--r--modules/system/startup.nix31
-rw-r--r--modules/users/default.nix4
-rw-r--r--pkgs/darwin-uninstaller/default.nix2
-rw-r--r--release.nix2
-rw-r--r--tests/fixtures/system-defaults-write/activate-user.txt338
-rw-r--r--tests/fixtures/system-defaults-write/activate.txt10
-rw-r--r--tests/services-github-runners.nix20
-rw-r--r--tests/services-nix-optimise.nix25
-rw-r--r--tests/system-defaults-write.nix86
32 files changed, 1376 insertions, 96 deletions
diff --git a/README.md b/README.md
index d2f17b5..cc98aea 100644
--- a/README.md
+++ b/README.md
@@ -172,7 +172,7 @@ export NIX_PATH=darwin=$HOME/.nix-defexpr/darwin:darwin-config=$HOME/.nixpkgs/da
cp ~/.nix-defexpr/darwin/modules/examples/simple.nix ~/.nixpkgs/darwin-configuration.nix
# you can also use this to rebootstrap nix-darwin in case
-# darwin-rebuild is to old to activate the system.
+# darwin-rebuild is too old to activate the system.
$(nix-build '<darwin>' -A system --no-out-link)/sw/bin/darwin-rebuild build
$(nix-build '<darwin>' -A system --no-out-link)/sw/bin/darwin-rebuild switch
diff --git a/doc/known-files/5d23e6d7015756c6f300f8cd558ec4d9234ca61deefd4f2478e91a49760b0747 b/doc/known-files/5d23e6d7015756c6f300f8cd558ec4d9234ca61deefd4f2478e91a49760b0747
new file mode 100644
index 0000000..55a2da1
--- /dev/null
+++ b/doc/known-files/5d23e6d7015756c6f300f8cd558ec4d9234ca61deefd4f2478e91a49760b0747
@@ -0,0 +1,9 @@
+# Generated by https://github.com/DeterminateSystems/nix-installer.
+# See `/nix/nix-installer --version` for the version details.
+
+build-users-group = nixbld
+experimental-features = nix-command flakes repl-flake
+bash-prompt-prefix = (nix:$name)\040
+max-jobs = auto
+extra-nix-path = nixpkgs=flake:nixpkgs
+upgrade-nix-store-path-url = https://install.determinate.systems/nix-upgrade/stable/universal
diff --git a/doc/known-files/d07015be6875f134976fce84c6c7a77b512079c1c5f9594dfa65c70b7968b65f b/doc/known-files/d07015be6875f134976fce84c6c7a77b512079c1c5f9594dfa65c70b7968b65f
new file mode 100644
index 0000000..7a676da
--- /dev/null
+++ b/doc/known-files/d07015be6875f134976fce84c6c7a77b512079c1c5f9594dfa65c70b7968b65f
@@ -0,0 +1,7 @@
+
+# Set up Nix only on SSH connections
+# See: https://github.com/DeterminateSystems/nix-installer/pull/714
+if [ -e '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh' ] && [ -n "${SSH_CONNECTION}" ] && [ "${SHLVL}" -eq 1 ]; then
+ . '/nix/var/nix/profiles/default/etc/profile.d/nix-daemon.sh'
+fi
+# End Nix
diff --git a/doc/manual/default.nix b/doc/manual/default.nix
index 5a0072a..abe126b 100644
--- a/doc/manual/default.nix
+++ b/doc/manual/default.nix
@@ -71,7 +71,6 @@ in rec {
mkdir -p $dst
cp $styles/style.css $dst
- cp $styles/overrides.css $dst
cp -r ${pkgs.documentation-highlighter} $dst/highlightjs
substitute ${./manual.md} manual.md \
@@ -86,7 +85,6 @@ in rec {
--revision ${lib.escapeShellArg revision} \
--generator "nixos-render-docs ${lib.version}" \
--stylesheet style.css \
- --stylesheet overrides.css \
--stylesheet highlightjs/mono-blue.css \
--script ./highlightjs/highlight.pack.js \
--script ./highlightjs/loader.js \
diff --git a/modules/meta.nix b/modules/meta.nix
index 0adc3fb..f076161 100644
--- a/modules/meta.nix
+++ b/modules/meta.nix
@@ -34,7 +34,7 @@ in
type = listOfMaintainers;
internal = true;
default = [];
- example = [ lib.maintainers.all ];
+ example = [ lib.maintainers.lnl7 ];
description = lib.mdDoc ''
List of maintainers of each module. This option should be defined at
most once per module.
diff --git a/modules/module-list.nix b/modules/module-list.nix
index 9e43d6c..ab7f0de 100644
--- a/modules/module-list.nix
+++ b/modules/module-list.nix
@@ -7,6 +7,7 @@
./security/pam.nix
./security/pki
./security/sandbox
+ ./security/sudo.nix
./system
./system/base.nix
./system/checks.nix
@@ -34,8 +35,10 @@
./system/etc.nix
./system/keyboard.nix
./system/launchd.nix
+ ./system/nvram.nix
./system/patches.nix
./system/shells.nix
+ ./system/startup.nix
./system/version.nix
./time
./networking
@@ -54,6 +57,7 @@
./services/dnsmasq.nix
./services/emacs.nix
./services/eternal-terminal.nix
+ ./services/github-runner
./services/gitlab-runner.nix
./services/hercules-ci-agent
./services/ipfs.nix
@@ -67,6 +71,7 @@
./services/netbird.nix
./services/nix-daemon.nix
./services/nix-gc
+ ./services/nix-optimise
./services/ofborg
./services/postgresql
./services/privoxy
@@ -78,10 +83,12 @@
./services/synapse-bt.nix
./services/synergy
./services/tailscale.nix
+ ./services/trezord.nix
./services/wg-quick.nix
./services/yabai
./services/nextdns
./programs/bash
+ ./programs/direnv.nix
./programs/fish.nix
./programs/gnupg.nix
./programs/man.nix
diff --git a/modules/nix/default.nix b/modules/nix/default.nix
index ae7eb91..ef5ce6c 100644
--- a/modules/nix/default.nix
+++ b/modules/nix/default.nix
@@ -62,13 +62,17 @@ let
if pkgs.stdenv.hostPlatform != pkgs.stdenv.buildPlatform then ''
echo "Ignoring validation for cross-compilation"
''
- else ''
+ else
+ let
+ showCommand = if isNixAtLeast "2.20pre" then "config show" else "show-config";
+ in
+ ''
echo "Validating generated nix.conf"
ln -s $out ./nix.conf
set -e
set +o pipefail
NIX_CONF_DIR=$PWD \
- ${cfg.package}/bin/nix show-config ${optionalString (isNixAtLeast "2.3pre") "--no-net"} \
+ ${cfg.package}/bin/nix ${showCommand} ${optionalString (isNixAtLeast "2.3pre") "--no-net"} \
${optionalString (isNixAtLeast "2.4pre") "--option experimental-features nix-command"} \
|& sed -e 's/^warning:/error:/' \
| (! grep '${if cfg.checkConfig then "^error:" else "^error: unknown setting"}')
@@ -672,7 +676,8 @@ in
"ff08c12813680da98c4240328f828647b67a65ba7aa89c022bd8072cba862cf1" # official Nix installer as of 2.4
"f3e03d851c240c1aa7daccd144ee929f0f5971982424c868c434eb6030e961d4" # DeterminateSystems Nix installer 0.10.0
"c6080216f2a170611e339c3f46e4e1d61aaf0d8b417ad93ade8d647da1382c11" # DeterminateSystems Nix installer 0.14.0
- "97f4135d262ca22d65c9554aad795c10a4491fa61b67d9c2430f4d82bbfec9a2" # DeterminateSystems Nix installer 0.15.1+
+ "97f4135d262ca22d65c9554aad795c10a4491fa61b67d9c2430f4d82bbfec9a2" # DeterminateSystems Nix installer 0.15.1
+ "5d23e6d7015756c6f300f8cd558ec4d9234ca61deefd4f2478e91a49760b0747" # DeterminateSystems Nix installer 0.16.0+
];
environment.etc."nix/registry.json".text = builtins.toJSON {
diff --git a/modules/nix/linux-builder.nix b/modules/nix/linux-builder.nix
index d487800..ecaf686 100644
--- a/modules/nix/linux-builder.nix
+++ b/modules/nix/linux-builder.nix
@@ -60,27 +60,95 @@ in
'';
};
+ mandatoryFeatures = mkOption {
+ type = types.listOf types.str;
+ default = [];
+ defaultText = literalExpression ''[]'';
+ example = literalExpression ''[ "big-parallel" ]'';
+ description = lib.mdDoc ''
+ A list of features mandatory for the Linux builder. The builder will
+ be ignored for derivations that don't require all features in
+ this list. All mandatory features are automatically included in
+ {var}`supportedFeatures`.
+
+ This sets the corresponding `nix.buildMachines.*.mandatoryFeatures` option.
+ '';
+ };
+
maxJobs = mkOption {
type = types.ints.positive;
default = 1;
example = 4;
description = lib.mdDoc ''
- This option specifies the maximum number of jobs to run on the Linux builder at once.
+ The number of concurrent jobs the Linux builder machine supports. The
+ build machine will enforce its own limits, but this allows hydra
+ to schedule better since there is no work-stealing between build
+ machines.
This sets the corresponding `nix.buildMachines.*.maxJobs` option.
'';
};
+ protocol = mkOption {
+ type = types.str;
+ default = "ssh-ng";
+ defaultText = literalExpression ''"ssh-ng"'';
+ example = literalExpression ''"ssh"'';
+ description = lib.mdDoc ''
+ The protocol used for communicating with the build machine. Use
+ `ssh-ng` if your remote builder and your local Nix version support that
+ improved protocol.
+
+ Use `null` when trying to change the special localhost builder without a
+ protocol which is for example used by hydra.
+ '';
+ };
+
+ speedFactor = mkOption {
+ type = types.ints.positive;
+ default = 1;
+ defaultText = literalExpression ''1'';
+ description = lib.mdDoc ''
+ The relative speed of the Linux builder. This is an arbitrary integer
+ that indicates the speed of this builder, relative to other
+ builders. Higher is faster.
+
+ This sets the corresponding `nix.buildMachines.*.speedFactor` option.
+ '';
+ };
+
supportedFeatures = mkOption {
type = types.listOf types.str;
default = [ "kvm" "benchmark" "big-parallel" ];
+ defaultText = literalExpression ''[ "kvm" "benchmark" "big-parallel" ]'';
+ example = literalExpression ''[ "kvm" "big-parallel" ]'';
description = lib.mdDoc ''
- This option specifies the list of features supported by the Linux builder.
+ A list of features supported by the Linux builder. The builder will
+ be ignored for derivations that require features not in this
+ list.
This sets the corresponding `nix.buildMachines.*.supportedFeatures` option.
'';
};
+ systems = mkOption {
+ type = types.listOf types.str;
+ default = [ "${stdenv.hostPlatform.uname.processor}-linux" ];
+ defaultText = literalExpression ''[ "''${stdenv.hostPlatform.uname.processor}-linux" ]'';
+ example = literalExpression ''
+ [
+ "x86_64-linux"
+ "aarch64-linux"
+ ]
+ '';
+ description = lib.mdDoc ''
+ This option specifies system types the build machine can execute derivations on.
+
+ This sets the corresponding `nix.buildMachines.*.systems` option.
+ '';
+ };
+
+
workingDirectory = mkOption {
type = types.str;
default = "/var/lib/darwin-builder";
@@ -139,9 +207,8 @@ in
hostName = "linux-builder";
sshUser = "builder";
sshKey = "/etc/nix/builder_ed25519";
- system = "${stdenv.hostPlatform.uname.processor}-linux";
publicHostKey = "c3NoLWVkMjU1MTkgQUFBQUMzTnphQzFsWkRJMU5URTVBQUFBSUpCV2N4Yi9CbGFxdDFhdU90RStGOFFVV3JVb3RpQzVxQkorVXVFV2RWQ2Igcm9vdEBuaXhvcwo=";
- inherit (cfg) maxJobs supportedFeatures;
+ inherit (cfg) mandatoryFeatures maxJobs protocol speedFactor supportedFeatures systems;
}];
nix.settings.builders-use-substitutes = true;
diff --git a/modules/programs/direnv.nix b/modules/programs/direnv.nix
new file mode 100644
index 0000000..648b3f9
--- /dev/null
+++ b/modules/programs/direnv.nix
@@ -0,0 +1,136 @@
+{
+ lib,
+ config,
+ pkgs,
+ ...
+}: let
+ cfg = config.programs.direnv;
+in {
+ meta.maintainers = [
+ lib.maintainers.mattpolzin or "mattpolzin"
+ ];
+ options.programs.direnv = {
+
+ enable = lib.mkEnableOption (lib.mdDoc ''
+ direnv integration. Takes care of both installation and
+ setting up the sourcing of the shell. Additionally enables nix-direnv
+ integration.
+ '');
+
+ package = lib.mkPackageOptionMD pkgs "direnv" {};
+
+ direnvrcExtra = lib.mkOption {
+ type = lib.types.lines;
+ default = "";
+ example = ''
+ export FOO="foo"
+ echo "loaded direnv!"
+ '';
+ description = lib.mdDoc ''
+ Extra lines to append to the sourced direnvrc
+ '';
+ };
+
+ silent = lib.mkEnableOption (lib.mdDoc ''
+ the hiding of direnv logging
+ '');
+
+ loadInNixShell =
+ lib.mkEnableOption (lib.mdDoc ''
+ loading direnv in `nix-shell` `nix shell` or `nix develop`
+ '')
+ // {
+ default = true;
+ };
+
+ nix-direnv = {
+ enable =
+ (lib.mkEnableOption (lib.mdDoc ''
+ a faster, persistent implementation of use_nix and use_flake, to replace the built-in one
+ ''))
+ // {
+ default = true;
+ };
+
+ package = lib.mkPackageOptionMD pkgs "nix-direnv" {};
+ };
+ };
+
+ config = lib.mkIf cfg.enable {
+
+ programs = {
+ zsh.interactiveShellInit = ''
+ if ${lib.boolToString cfg.loadInNixShell} || printenv PATH | grep -vqc '/nix/store'; then
+ eval "$(${lib.getExe cfg.package} hook zsh)"
+ fi
+ '';
+
+ #$NIX_GCROOT for "nix develop" https://github.com/NixOS/nix/blob/6db66ebfc55769edd0c6bc70fcbd76246d4d26e0/src/nix/develop.cc#L530
+ #$IN_NIX_SHELL for "nix-shell"
+ bash.interactiveShellInit = ''
+ if ${lib.boolToString cfg.loadInNixShell} || [ -z "$IN_NIX_SHELL$NIX_GCROOT$(printenv PATH | grep '/nix/store')" ] ; then
+ eval "$(${lib.getExe cfg.package} hook bash)"
+ fi
+ '';
+
+ fish.interactiveShellInit = ''
+ if ${lib.boolToString cfg.loadInNixShell};
+ or printenv PATH | grep -vqc '/nix/store';
+ ${lib.getExe cfg.package} hook fish | source
+ end
+ '';
+ };
+
+ environment = {
+ systemPackages =
+ if cfg.loadInNixShell then [cfg.package]
+ else [
+ #direnv has a fish library which sources direnv for some reason
+ (cfg.package.overrideAttrs (old: {
+ installPhase =
+ (old.installPhase or "")
+ + ''
+ rm -rf $out/share/fish
+ '';
+ }))
+ ];
+
+ variables = {
+ DIRENV_CONFIG = "/etc/direnv";
+ DIRENV_LOG_FORMAT = lib.mkIf cfg.silent "";
+ };
+
+ etc = {
+ "direnv/direnvrc".text = ''
+ ${lib.optionalString cfg.nix-direnv.enable ''
+ #Load nix-direnv
+ source ${cfg.nix-direnv.package}/share/nix-direnv/direnvrc
+ ''}
+
+ #Load direnvrcExtra
+ ${cfg.direnvrcExtra}
+
+ #Load user-configuration if present (~/.direnvrc or ~/.config/direnv/direnvrc)
+ direnv_config_dir_home="''${DIRENV_CONFIG_HOME:-''${XDG_CONFIG_HOME:-$HOME/.config}/direnv}"
+ if [[ -f $direnv_config_dir_home/direnvrc ]]; then
+ source "$direnv_config_dir_home/direnvrc" >&2
+ elif [[ -f $HOME/.direnvrc ]]; then
+ source "$HOME/.direnvrc" >&2
+ fi
+
+ unset direnv_config_dir_home
+ '';
+
+ "direnv/lib/zz-user.sh".text = ''
+ direnv_config_dir_home="''${DIRENV_CONFIG_HOME:-''${XDG_CONFIG_HOME:-$HOME/.config}/direnv}"
+
+ for lib in "$direnv_config_dir_home/lib/"*.sh; do
+ source "$lib"
+ done
+
+ unset direnv_config_dir_home
+ '';
+ };
+ };
+ };
+}
diff --git a/modules/programs/zsh/default.nix b/modules/programs/zsh/default.nix
index 615589a..cce645c 100644
--- a/modules/programs/zsh/default.nix
+++ b/modules/programs/zsh/default.nix
@@ -219,5 +219,9 @@ in
"2af1b563e389d11b76a651b446e858116d7a20370d9120a7e9f78991f3e5f336" # DeterminateSystems installer
];
+ environment.etc."zshenv".knownSha256Hashes = [
+ "d07015be6875f134976fce84c6c7a77b512079c1c5f9594dfa65c70b7968b65f" # DeterminateSystems installer
+ ];
+
};
}
diff --git a/modules/security/sudo.nix b/modules/security/sudo.nix
new file mode 100644
index 0000000..c0d9597
--- /dev/null
+++ b/modules/security/sudo.nix
@@ -0,0 +1,30 @@
+{ config, lib, ... }:
+
+with lib;
+
+let
+ cfg = config.security.sudo;
+in
+{
+ meta.maintainers = [
+ lib.maintainers.samasaur or "samasaur"
+ ];
+
+ options = {
+ security.sudo.extraConfig = mkOption {
+ type = types.nullOr types.lines;
+ default = null;
+ description = mdDoc ''
+ Extra configuration text appended to {file}`sudoers`.
+ '';
+ };
+ };
+
+ config = {
+ environment.etc = {
+ "sudoers.d/10-nix-darwin-extra-config" = mkIf (cfg.extraConfig != null) {
+ text = cfg.extraConfig;
+ };
+ };
+ };
+}
diff --git a/modules/services/github-runner/default.nix b/modules/services/github-runner/default.nix
new file mode 100644
index 0000000..e860eca
--- /dev/null
+++ b/modules/services/github-runner/default.nix
@@ -0,0 +1,6 @@
+{
+ imports = [
+ ./options.nix
+ ./service.nix
+ ];
+}
diff --git a/modules/services/github-runner/options.nix b/modules/services/github-runner/options.nix
new file mode 100644
index 0000000..300ca32
--- /dev/null
+++ b/modules/services/github-runner/options.nix
@@ -0,0 +1,269 @@
+{ lib
+, pkgs
+, ...
+}:
+
+with lib;
+{
+ options.services.github-runners = mkOption {
+ description = mdDoc ''
+ Multiple GitHub Runners.
+
+ If `user` and `group` are set to `null`, the module will configure nix-darwin to
+ manage the `_github-runner` user and group. Note that multiple runner
+ configurations share the same user/group, which means they can access
+ resources from other runners. Make each runner use its own user and group if
+ this is not what you want. In this case, you will have to do the user and
+ group creation yourself. If only `user` is set, while `group` is set to
+ `null`, the service will infer the primary group of the `user`.
+
+ For each GitHub runner, the system activation script creates the following
+ directories:
+
+ * `/var/lib/github-runners/<name>`:
+ State directory to store the runner registration credentials
+ * `/var/log/github-runners/<name>`:
+ The launchd service writes the stdout and stderr streams to this
+ directory.
+ * `/var/run/github-runners/<name>`:
+ Working directory for workflow files. The runner only uses this
+ directory if `workDir` is `null` (see the `workDir` option for details).
+ '';
+ example = {
+ runner1 = {
+ enable = true;
+ url = "https://github.com/owner/repo";
+ name = "runner1";
+ tokenFile = "/secrets/token1";
+ };
+
+ runner2 = {
+ enable = true;
+ url = "https://github.com/owner/repo";
+ name = "runner2";
+ tokenFile = "/secrets/token2";
+ };
+ };
+ default = { };
+ type = types.attrsOf (types.submodule ({ name, ... }: {
+ options = {
+ enable = mkOption {
+ default = false;
+ example = true;
+ description = mdDoc ''
+ Whether to enable GitHub Actions runner.
+
+ Note: GitHub recommends using self-hosted runners with private repositories only. Learn more here:
+ [About self-hosted runners](https://docs.github.com/en/actions/hosting-your-own-runners/about-self-hosted-runners).
+ '';
+ type = types.bool;
+ };
+
+ url = mkOption {
+ type = types.str;
+ description = mdDoc ''
+ Repository to add the runner to.
+
+ Changing this option triggers a new runner registration.
+
+ IMPORTANT: If your token is org-wide (not per repository), you need to
+ provide a github org link, not a single repository, so do it like this
+ `https://github.com/nixos`, not like this
+ `https://github.com/nixos/nixpkgs`.
+ Otherwise, you are going to get a `404 NotFound`
+ from `POST https://api.github.com/actions/runner-registration`
+ in the configure script.
+ '';
+ example = "https://github.com/nixos/nixpkgs";
+ };
+
+ tokenFile = mkOption {
+ type = types.path;
+ description = mdDoc ''
+ The full path to a file which contains either
+
+ * a fine-grained personal access token (PAT),
+ * a classic PAT
+ * or a runner registration token
+
+ Changing this option or the `tokenFile`’s content triggers a new runner registration.
+
+ We suggest using the fine-grained PATs. A runner registration token is valid
+ only for 1 hour after creation, so the next time the runner configuration changes
+ this will give you hard-to-debug HTTP 404 errors in the configure step.
+
+ The file should contain exactly one line with the token without any newline.
+ (Use `echo -n '…token…' > …token file…` to make sure no newlines sneak in.)
+
+ If the file contains a PAT, the service creates a new registration token
+ on startup as needed.
+ If a registration token is given, it can be used to re-register a runner of the same
+ name but is time-limited as noted above.
+
+ For fine-grained PATs:
+
+ Give it "Read and Write access to organization/repository self hosted runners",
+ depending on whether it is organization wide or per-repository. You might have to
+ experiment a little, fine-grained PATs are a `beta` Github feature and still subject
+ to change; nonetheless they are the best option at the moment.
+
+ For classic PATs:
+
+ Make sure the PAT has a scope of `admin:org` for organization-wide registrations
+ or a scope of `repo` for a single repository.
+
+ For runner registration tokens:
+
+ Nothing special needs to be done, but updating will break after one hour,
+ so these are not recommended.
+ '';
+ example = "/run/secrets/github-runner/nixos.token";
+ };
+
+ name = mkOption {
+ type = types.nullOr types.str;
+ description = mdDoc ''
+ Name of the runner to configure. If null, defaults to the hostname.
+
+ Changing this option triggers a new runner registration.
+ '';
+ example = "nixos";
+ default = name;
+ };
+
+ runnerGroup = mkOption {
+ type = types.nullOr types.str;
+ description = mdDoc ''
+ Name of the runner group to add this runner to (defaults to the default runner group).
+
+ Changing this option triggers a new runner registration.
+ '';
+ default = null;
+ };
+
+ extraLabels = mkOption {
+ type = types.listOf types.str;
+ description = mdDoc ''
+ Extra labels in addition to the default (unless disabled through the `noDefaultLabels` option).
+
+ Changing this option triggers a new runner registration.
+ '';
+ example = literalExpression ''[ "nixos" ]'';
+ default = [ ];
+ };
+
+ noDefaultLabels = mkOption {
+ type = types.bool;
+ description = mdDoc ''
+ Disables adding the default labels. Also see the `extraLabels` option.
+
+ Changing this option triggers a new runner registration.
+ '';
+ default = false;
+ };
+
+ replace = mkOption {
+ type = types.bool;
+ description = mdDoc ''
+ Replace any existing runner with the same name.
+
+ Without this flag, registering a new runner with the same name fails.
+ '';
+ default = false;
+ };
+
+ extraPackages = mkOption {
+ type = types.listOf types.package;
+ description = mdDoc ''
+ Extra packages to add to `PATH` of the service to make them available to workflows.
+ '';
+ default = [ ];
+ };
+
+ extraEnvironment = mkOption {
+ type = types.attrs;
+ description = mdDoc ''
+ Extra environment variables to set for the runner, as an attrset.
+ '';
+ example = {
+ GIT_CONFIG = "/path/to/git/config";
+ };
+ default = { };
+ };
+
+ serviceOverrides = mkOption {
+ type = types.attrs;
+ description = mdDoc ''
+ Modify the service. Can be used to, e.g., adjust the sandboxing options.
+ '';
+ default = { };
+ };
+
+ package = mkPackageOptionMD pkgs "github-runner" { };
+
+ ephemeral = mkOption {
+ type = types.bool;
+ description = mdDoc ''
+ If enabled, causes the following behavior:
+
+ - Passes the `--ephemeral` flag to the runner configuration script
+ - De-registers and stops the runner with GitHub after it has processed one job
+ - Restarts the service after its successful exit
+ - On start, wipes the state directory and configures a new runner
+
+ You should only enable this option if `tokenFile` points to a file which contains a
+ personal access token (PAT). If you're using the option with a registration token, restarting the
+ service will fail as soon as the registration token expired.
+
+ Changing this option triggers a new runner registration.
+ '';
+ default = false;
+ };
+
+ user = mkOption {
+ type = types.nullOr types.str;
+ description = mdDoc ''
+ User under which to run the service.
+
+ If this option and the `group` option is set to `null`, nix-darwin creates
+ the `github-runner` user and group.
+ '';
+ defaultText = literalExpression "username";
+ default = null;
+ };
+
+ group = mkOption {
+ type = types.nullOr types.str;
+ description = mdDoc ''
+ Group under which to run the service.
+
+ If this option and the `user` option is set to `null`, nix-darwin creates
+ the `github-runner` user and group.
+ '';
+ defaultText = literalExpression "groupname";
+ default = null;
+ };
+
+ workDir = mkOption {
+ type = with types; nullOr str;
+ description = mdDoc ''
+ Working directory, available as `$GITHUB_WORKSPACE` during workflow runs
+ and used as a default for [repository checkouts](https://github.com/actions/checkout).
+ The service cleans this directory on every service start.
+
+ Changing this option triggers a new runner registration.
+ '';
+ default = null;
+ };
+
+ nodeRuntimes = mkOption {
+ type = with types; nonEmptyListOf (enum [ "node20" ]);
+ default = [ "node20" ];
+ description = mdDoc ''
+ List of Node.js runtimes the runner should support.
+ '';
+ };
+ };
+ }));
+ };
+}
diff --git a/modules/services/github-runner/service.nix b/modules/services/github-runner/service.nix
new file mode 100644
index 0000000..53f2cdd
--- /dev/null
+++ b/modules/services/github-runner/service.nix
@@ -0,0 +1,181 @@
+{ config, lib, pkgs, ... }:
+with lib;
+let
+ mkSvcName = name: "github-runner-${name}";
+ mkStateDir = cfg: "/var/lib/github-runners/${cfg.name}";
+ mkLogDir = cfg: "/var/log/github-runners/${cfg.name}";
+ mkWorkDir = cfg: if (cfg.workDir != null) then cfg.workDir else "/var/run/github-runners/${cfg.name}";
+in
+{
+ config.assertions = flatten (
+ flip mapAttrsToList config.services.github-runners (name: cfg: map (mkIf cfg.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";
+ }
+ {
+ assertion = !cfg.noDefaultLabels || (cfg.extraLabels != [ ]);
+ message = "`services.github-runners.${name}`: The `extraLabels` option is mandatory if `noDefaultLabels` is set";
+ }
+ ])
+ );
+
+ config.warnings = flatten (
+ flip mapAttrsToList config.services.github-runners (name: cfg: map (mkIf cfg.enable) [
+ (
+ mkIf (hasPrefix builtins.storeDir cfg.tokenFile)
+ "`services.github-runners.${name}`: `tokenFile` contains a secret but points to the world-readable Nix store."
+ )
+ ])
+ );
+
+ # Create the necessary directories and make the service user/group their owner
+ # This has to happen *after* nix-darwin user creation and *before* any launchd service gets started.
+ config.system.activationScripts = mkMerge (flip mapAttrsToList config.services.github-runners (name: cfg:
+ let
+ user = config.launchd.daemons.${mkSvcName name}.serviceConfig.UserName;
+ group =
+ if config.launchd.daemons.${mkSvcName name}.serviceConfig.GroupName != null
+ then config.launchd.daemons.${mkSvcName name}.serviceConfig.GroupName
+ else "";
+ in
+ {
+ launchd = mkIf cfg.enable {
+ text = mkBefore (''
+ echo >&2 "setting up GitHub Runner '${cfg.name}'..."
+
+ ${pkgs.coreutils}/bin/mkdir -p -m 0750 ${escapeShellArg (mkStateDir cfg)}
+ ${pkgs.coreutils}/bin/chown ${user}:${group} ${escapeShellArg (mkStateDir cfg)}
+
+ ${pkgs.coreutils}/bin/mkdir -p -m 0750 ${escapeShellArg (mkLogDir cfg)}
+ ${pkgs.coreutils}/bin/chown ${user}:${group} ${escapeShellArg (mkLogDir cfg)}
+ '' + optionalString (cfg.workDir == null) ''
+ ${pkgs.coreutils}/bin/mkdir -p -m 0750 ${escapeShellArg (mkWorkDir cfg)}
+ ${pkgs.coreutils}/bin/chown ${user}:${group} ${escapeShellArg (mkWorkDir cfg)}
+ '');
+ };
+ }));
+
+ config.launchd.daemons = flip mapAttrs' config.services.github-runners (name: cfg:
+ let
+ package = cfg.package.override (old: optionalAttrs (hasAttr "nodeRuntimes" old) { inherit (cfg) nodeRuntimes; });
+ stateDir = mkStateDir cfg;
+ logDir = mkLogDir cfg;
+ workDir = mkWorkDir cfg;
+ in
+ nameValuePair
+ (mkSvcName name)
+ (mkIf cfg.enable {
+ environment = {
+ HOME = stateDir;
+ RUNNER_ROOT = stateDir;
+ } // cfg.extraEnvironment;
+
+ # Minimal package set for `actions/checkout`
+ path = (with pkgs; [
+ bash
+ coreutils
+ git
+ gnutar
+ gzip
+ ]) ++ [
+ config.nix.package
+ ] ++ cfg.extraPackages;
+
+ script =
+ let
+ configure = pkgs.writeShellApplication {
+ name = "configure-github-runner-${name}";
+ text = ''
+ export RUNNER_ROOT
+
+ args=(
+ --unattended
+ --disableupdate
+ --work ${escapeShellArg workDir}
+ --url ${escapeShellArg cfg.url}
+ --labels ${escapeShellArg (concatStringsSep "," cfg.extraLabels)}
+ ${optionalString (cfg.name != null ) "--name ${escapeShellArg cfg.name}"}
+ ${optionalString cfg.replace "--replace"}
+ ${optionalString (cfg.runnerGroup != null) "--runnergroup ${escapeShellArg cfg.runnerGroup}"}
+ ${optionalString cfg.ephemeral "--ephemeral"}
+ ${optionalString cfg.noDefaultLabels "--no-default-labels"}
+ )
+ # If the token file contains a PAT (i.e., it starts with "ghp_" or "github_pat_"), we have to use the --pat option,
+ # if it is not a PAT, we assume it contains a registration token and use the --token option
+ token=$(<"${cfg.tokenFile}")
+ if [[ "$token" =~ ^ghp_* ]] || [[ "$token" =~ ^github_pat_* ]]; then
+ args+=(--pat "$token")
+ else
+ args+=(--token "$token")
+ fi
+ ${package}/bin/config.sh "''${args[@]}"
+ '';
+ };
+ in
+ ''
+ echo "Configuring GitHub Actions Runner"
+
+ # Always clean the working directory
+ ${pkgs.findutils}/bin/find ${escapeShellArg workDir} -mindepth 1 -delete
+
+ # Clean the $RUNNER_ROOT if we are in ephemeral mode
+ if ${boolToString cfg.ephemeral}; then
+ echo "Cleaning $RUNNER_ROOT"
+ ${pkgs.findutils}/bin/find "$RUNNER_ROOT" -mindepth 1 -delete
+ fi
+
+ # If the `.runner` file does not exist, we assume the runner is not configured
+ if [[ ! -f "$RUNNER_ROOT/.runner" ]]; then
+ ${getExe configure}
+ fi
+
+ # Start the service
+ ${package}/bin/Runner.Listener run --startuptype service
+ '';
+
+ serviceConfig = mkMerge [
+ {
+ GroupName = cfg.group;
+ KeepAlive = {
+ Crashed = false;
+ } // mkIf cfg.ephemeral {
+ SuccessfulExit = true;
+ };
+ ProcessType = "Interactive";
+ RunAtLoad = true;
+ StandardErrorPath = "${logDir}/launchd-stderr.log";
+ StandardOutPath = "${logDir}/launchd-stdout.log";
+ ThrottleInterval = 30;
+ UserName = if (cfg.user != null) then cfg.user else "_github-runner";
+ WatchPaths = [
+ "/etc/resolv.conf"
+ "/Library/Preferences/SystemConfiguration/NetworkInterfaces.plist"
+ cfg.tokenFile
+ ];
+ WorkingDirectory = stateDir;
+ }
+ cfg.serviceOverrides
+ ];
+ }));
+
+ # If any GitHub runner configuration has set both `user` and `group` set to `null`,
+ # manage the user and group `_github-runner` through nix-darwin.
+ config.users = mkIf (any (cfg: cfg.enable && cfg.user == null && cfg.group == null) (attrValues config.services.github-runners)) {
+ users."_github-runner" = {
+ createHome = false;
+ description = "GitHub Runner service user";
+ gid = config.users.groups."_github-runner".gid;
+ home = "/var/lib/github-runners";
+ shell = "/bin/bash";
+ uid = mkDefault 533;
+ };
+ knownUsers = [ "_github-runner" ];
+
+ groups."_github-runner" = {
+ gid = mkDefault 533;
+ description = "GitHub Runner service user group";
+ };
+ knownGroups = [ "_github-runner" ];
+ };
+}
diff --git a/modules/services/ipfs.nix b/modules/services/ipfs.nix
index 8087ba4..6cfcc49 100644
--- a/modules/services/ipfs.nix
+++ b/modules/services/ipfs.nix
@@ -18,7 +18,7 @@ in
};
package = mkOption {
- type = types.path;
+ type = types.package;
default = pkgs.kubo;
# defaultText = "pkgs.kubo";
description = lib.mdDoc ''
@@ -29,7 +29,7 @@ in
logFile = mkOption {
type = types.nullOr types.path;
default = null;
- example = "/var/tmp/lorri.log";
+ example = "/var/tmp/ipfs.log";
description = lib.mdDoc ''
The logfile to use for the ipfs service. Alternatively
{command}`sudo launchctl debug system/org.nixos.ipfs --stderr`
@@ -52,9 +52,8 @@ in
};
config = mkIf cfg.enable {
- environment.systemPackages = [ pkgs.kubo ];
+ environment.systemPackages = [ cfg.package ];
launchd.user.agents.ipfs = {
- # command = with pkgs; "${ipfs}/bin/ipfs daemon";
serviceConfig = {
ProgramArguments = [ "${cfg.package}/bin/ipfs" "daemon" ]
++ optionals (cfg.enableGarbageCollection) [ "--enable-gc" ];
diff --git a/modules/services/nix-optimise/default.nix b/modules/services/nix-optimise/default.nix
new file mode 100644
index 0000000..5462bae
--- /dev/null
+++ b/modules/services/nix-optimise/default.nix
@@ -0,0 +1,73 @@
+# Based off:
+# https://github.com/NixOS/nixpkgs/blob/master/nixos/modules/services/misc/nix-optimise.nix
+# When making changes please try to keep it in sync.
+{ config, lib, ... }:
+
+
+let
+ inherit (lib)
+ mdDoc
+ mkIf
+ mkOption
+ mkRemovedOptionModule
+ optionalString
+ types
+ ;
+
+ cfg = config.nix.optimise;
+in
+
+{
+ imports = [
+ (mkRemovedOptionModule [ "nix" "optimise" "dates" ] "Use `nix.optimise.interval` instead.")
+ ];
+
+ ###### interface
+
+ options = {
+
+ nix.optimise = {
+
+ automatic = mkOption {
+ type = types.bool;
+ default = false;
+ description = mdDoc "Automatically run the nix store optimiser at a specific time.";
+ };
+
+ # Not in NixOS module
+ user = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ description = mdDoc "User that runs the store optimisation.";
+ };
+
+ interval = mkOption {
+ type = types.attrs;
+ default = { Hour = 3; Minute = 15; };
+ description = mdDoc "The time interval at which the optimiser will run.";
+ };
+
+ };
+
+ };
+
+
+ ###### implementation
+
+ config = mkIf cfg.automatic {
+
+ launchd.daemons.nix-optimise = {
+ environment.NIX_REMOTE = optionalString config.nix.useDaemon "daemon";
+ serviceConfig = {
+ ProgramArguments = [
+ "/bin/sh" "-c"
+ "/bin/wait4path ${config.nix.package} &amp;&amp; exec ${config.nix.package}/bin/nix-store --optimise"
+ ];
+ RunAtLoad = false;
+ StartCalendarInterval = [ cfg.interval ];
+ UserName = cfg.user;
+ };
+ };
+
+ };
+}
diff --git a/modules/services/trezord.nix b/modules/services/trezord.nix
new file mode 100644
index 0000000..97db519
--- /dev/null
+++ b/modules/services/trezord.nix
@@ -0,0 +1,47 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+let
+ cfg = config.services.trezord;
+in {
+ # Options copied from:
+ # https://github.com/NixOS/nixpkgs/blob/9d6e454b857fb472fa35fc8b098fa5ac307a0d7d/nixos/modules/services/hardware/trezord.nix#L16
+ options = {
+ services.trezord = {
+ enable = mkOption {
+ type = types.bool;
+ default = false;
+ description = lib.mdDoc ''
+ Enable Trezor bridge daemon, for use with Trezor hardware wallets.
+ '';
+ };
+
+ emulator.enable = mkOption {
+ type = types.bool;
+ default = false;
+ description = lib.mdDoc ''
+ Enable Trezor emulator support.
+ '';
+ };
+
+ emulator.port = mkOption {
+ type = types.port;
+ default = 21324;
+ description = lib.mdDoc ''
+ Listening port for the Trezor emulator.
+ '';
+ };
+ };
+ };
+
+ config = mkIf cfg.enable {
+ launchd.user.agents.trezord = {
+ serviceConfig = {
+ ProgramArguments = [ "${pkgs.trezord}/bin/trezord-go" ]
+ ++ optionals cfg.emulator.enable [ "-e" (builtins.toString cfg.emulator.port) ];
+ KeepAlive = true;
+ RunAtLoad = true;
+ };
+ };
+ };
+}
diff --git a/modules/system/activation-scripts.nix b/modules/system/activation-scripts.nix
index 67d69be..68e01b5 100644
--- a/modules/system/activation-scripts.nix
+++ b/modules/system/activation-scripts.nix
@@ -69,6 +69,7 @@ in
${cfg.activationScripts.networking.text}
${cfg.activationScripts.keyboard.text}
${cfg.activationScripts.fonts.text}
+ ${cfg.activationScripts.nvram.text}
${cfg.activationScripts.postActivation.text}
diff --git a/modules/system/checks.nix b/modules/system/checks.nix
index 27188e3..5989dc4 100644
--- a/modules/system/checks.nix
+++ b/modules/system/checks.nix
@@ -191,6 +191,17 @@ let
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.optimiser.user = \"$USER\";" >&2
+ echo >&2
+ exit 2
+ fi
+ '';
in
{
@@ -230,6 +241,7 @@ in
(mkIf (!config.nix.useDaemon) singleUser)
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)
nixInstaller
(mkIf cfg.verifyNixPath nixPath)
diff --git a/modules/system/defaults-write.nix b/modules/system/defaults-write.nix
index 2e56d74..7e1fc44 100644
--- a/modules/system/defaults-write.nix
+++ b/modules/system/defaults-write.nix
@@ -5,18 +5,8 @@ with lib;
let
cfg = config.system.defaults;
- boolValue = x: if x then "YES" else "NO";
-
- writeValue = value:
- if isBool value then "-bool ${boolValue value}" else
- if isInt value then "-int ${toString value}" else
- if isFloat value then "-float ${strings.floatToString value}" else
- if isString value then "-string '${value}'" else
- if isList value then "-array ${concatStringsSep " " (map (v: writeValue v)value)}" else
- throw "invalid value type";
-
writeDefault = domain: key: value:
- "defaults write ${domain} '${key}' ${writeValue value}";
+ "defaults write ${domain} '${key}' $'${strings.escape [ "'" ] (generators.toPlist { } value)}'";
defaultsToList = domain: attrs: mapAttrsToList (writeDefault domain) (filterAttrs (n: v: v != null) attrs);
diff --git a/modules/system/defaults/NSGlobalDomain.nix b/modules/system/defaults/NSGlobalDomain.nix
index 4f08d4a..03a7da2 100644
--- a/modules/system/defaults/NSGlobalDomain.nix
+++ b/modules/system/defaults/NSGlobalDomain.nix
@@ -225,6 +225,14 @@ in {
'';
};
+ system.defaults.NSGlobalDomain.NSWindowShouldDragOnGesture = mkOption {
+ type = types.nullOr types.bool;
+ default = null;
+ description = lib.mdDoc ''
+ Whether to enable moving window by holding anywhere on it like on Linux. The default is false.
+ '';
+ };
+
system.defaults.NSGlobalDomain.InitialKeyRepeat = mkOption {
type = types.nullOr types.int;
default = null;
diff --git a/modules/system/defaults/dock.nix b/modules/system/defaults/dock.nix
index 7fda0da..9d54f75 100644
--- a/modules/system/defaults/dock.nix
+++ b/modules/system/defaults/dock.nix
@@ -123,6 +123,19 @@ in {
'';
};
+ system.defaults.dock.persistent-apps = mkOption {
+ type = types.nullOr (types.listOf (types.either types.path types.str));
+ default = null;
+ example = [ "/Applications/Safari.app" "/System/Applications/Utilities/Terminal.app" ];
+ description = lib.mdDoc ''
+ Persistent applications in the dock.
+ '';
+ apply = value:
+ if !(isList value)
+ then value
+ else map (app: { tile-data = { file-data = { _CFURLString = app; _CFURLStringType = 0; }; }; }) value;
+ };
+
system.defaults.dock.show-process-indicators = mkOption {
type = types.nullOr types.bool;
default = null;
diff --git a/modules/system/nvram.nix b/modules/system/nvram.nix
new file mode 100644
index 0000000..efc9c99
--- /dev/null
+++ b/modules/system/nvram.nix
@@ -0,0 +1,40 @@
+{ config, lib, pkgs, ... }:
+
+let
+ cfg = config.system;
+
+ mkNvramVariables =
+ lib.attrsets.mapAttrsToList
+ (name: value: "nvram ${lib.escapeShellArg name}=${lib.escapeShellArg value}")
+ cfg.nvram.variables;
+in
+
+{
+ meta.maintainers = [
+ lib.maintainers.samasaur or "samasaur"
+ ];
+
+ options = {
+ system.nvram.variables = lib.mkOption {
+ type = with lib.types; attrsOf str;
+ default = {};
+ internal = true;
+ example = {
+ "StartupMute" = "%01";
+ };
+ description = lib.mdDoc ''
+ Non-volatile RAM variables to set. Removing a key-value pair from this
+ list will **not** return the variable to its previous value, but will
+ no longer set its value on system configuration activations.
+ '';
+ };
+ };
+
+ config = {
+ system.activationScripts.nvram.text = ''
+ echo "setting nvram variables..." >&2
+
+ ${builtins.concatStringsSep "\n" mkNvramVariables}
+ '';
+ };
+}
diff --git a/modules/system/startup.nix b/modules/system/startup.nix
new file mode 100644
index 0000000..ecbef46
--- /dev/null
+++ b/modules/system/startup.nix
@@ -0,0 +1,31 @@
+{ config, lib, pkgs, ... }:
+
+let
+ cfg = config.system.startup;
+in
+
+{
+ meta.maintainers = [
+ lib.maintainers.samasaur or "samasaur"
+ ];
+
+ options = {
+ system.startup.chime = lib.mkOption {
+ type = with lib.types; nullOr bool;
+ default = null;
+ example = false;
+ description = lib.mdDoc ''
+ Whether to enable the startup chime.
+
+ By default, this option does not affect your system configuration in any way.
+ However, this means that after it has been set once, unsetting it will not
+ return to the old behavior. It will allow the setting to be controlled in
+ System Settings, though.
+ '';
+ };
+ };
+
+ config = {
+ system.nvram.variables."StartupMute" = lib.mkIf (cfg.chime != null) (if cfg.chime then "%00" else "%01");
+ };
+}
diff --git a/modules/users/default.nix b/modules/users/default.nix
index 9648274..25cc97e 100644
--- a/modules/users/default.nix
+++ b/modules/users/default.nix
@@ -100,7 +100,7 @@ in
${optionalString cfg.forceRecreate ''
g=$(dscl . -read '/Groups/${v.name}' PrimaryGroupID 2> /dev/null) || true
g=''${g#PrimaryGroupID: }
- if [ "$g" -eq ${toString v.gid} ]; then
+ if [[ "$g" -eq ${toString v.gid} ]]; then
echo "deleting group ${v.name}..." >&2
dscl . -delete '/Groups/${v.name}' 2> /dev/null
else
@@ -149,7 +149,7 @@ in
${optionalString cfg.forceRecreate ''
u=$(dscl . -read '/Users/${v.name}' UniqueID 2> /dev/null) || true
u=''${u#UniqueID: }
- if [ "$u" -eq ${toString v.uid} ]; then
+ if [[ "$u" -eq ${toString v.uid} ]]; then
echo "deleting user ${v.name}..." >&2
dscl . -delete '/Users/${v.name}' 2> /dev/null
else
diff --git a/pkgs/darwin-uninstaller/default.nix b/pkgs/darwin-uninstaller/default.nix
index 94c0749..3eb2c24 100644
--- a/pkgs/darwin-uninstaller/default.nix
+++ b/pkgs/darwin-uninstaller/default.nix
@@ -7,7 +7,7 @@ let
./configuration.nix
{
nixpkgs.source = pkgs.path;
- nixpkgs.hostPlatform = pkgs.system;
+ nixpkgs.hostPlatform = pkgs.stdenv.hostPlatform.system;
system.includeUninstaller = false;
}
];
diff --git a/release.nix b/release.nix
index ffdfc38..98a58e7 100644
--- a/release.nix
+++ b/release.nix
@@ -119,12 +119,14 @@ let
tests.services-activate-system = makeTest ./tests/services-activate-system.nix;
tests.services-activate-system-changed-label-prefix = makeTest ./tests/services-activate-system-changed-label-prefix.nix;
tests.services-buildkite-agent = makeTest ./tests/services-buildkite-agent.nix;
+ tests.services-github-runners = makeTest ./tests/services-github-runners.nix;
tests.services-lorri = makeTest ./tests/services-lorri.nix;
tests.services-nix-daemon = makeTest ./tests/services-nix-daemon.nix;
tests.sockets-nix-daemon = makeTest ./tests/sockets-nix-daemon.nix;
tests.services-dnsmasq = makeTest ./tests/services-dnsmasq.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;
tests.services-nextdns = makeTest ./tests/services-nextdns.nix;
tests.services-ofborg = makeTest ./tests/services-ofborg.nix;
tests.services-offlineimap = makeTest ./tests/services-offlineimap.nix;
diff --git a/tests/fixtures/system-defaults-write/activate-user.txt b/tests/fixtures/system-defaults-write/activate-user.txt
new file mode 100644
index 0000000..1021ab3
--- /dev/null
+++ b/tests/fixtures/system-defaults-write/activate-user.txt
@@ -0,0 +1,338 @@
+defaults write -g 'AppleEnableMouseSwipeNavigateWithScrolls' $'<?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">
+<false/>
+</plist>'
+defaults write -g 'AppleEnableSwipeNavigateWithScrolls' $'<?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">
+<false/>
+</plist>'
+defaults write -g 'AppleFontSmoothing' $'<?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">
+<integer>1</integer>
+</plist>'
+defaults write -g 'AppleICUForce24HourTime' $'<?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">
+<true/>
+</plist>'
+defaults write -g 'AppleKeyboardUIMode' $'<?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">
+<integer>3</integer>
+</plist>'
+defaults write -g 'ApplePressAndHoldEnabled' $'<?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">
+<true/>
+</plist>'
+defaults write -g 'AppleScrollerPagingBehavior' $'<?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">
+<true/>
+</plist>'
+defaults write -g 'AppleShowAllExtensions' $'<?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">
+<true/>
+</plist>'
+defaults write -g 'AppleShowAllFiles' $'<?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">
+<true/>
+</plist>'
+defaults write -g 'AppleShowScrollBars' $'<?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">
+<string>Always</string>
+</plist>'
+defaults write -g 'AppleWindowTabbingMode' $'<?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">
+<string>always</string>
+</plist>'
+defaults write -g 'InitialKeyRepeat' $'<?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">
+<integer>10</integer>
+</plist>'
+defaults write -g 'KeyRepeat' $'<?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">
+<integer>1</integer>
+</plist>'
+defaults write -g 'NSAutomaticCapitalizationEnabled' $'<?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">
+<false/>
+</plist>'
+defaults write -g 'NSAutomaticDashSubstitutionEnabled' $'<?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">
+<false/>
+</plist>'
+defaults write -g 'NSAutomaticPeriodSubstitutionEnabled' $'<?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">
+<false/>
+</plist>'
+defaults write -g 'NSAutomaticQuoteSubstitutionEnabled' $'<?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">
+<false/>
+</plist>'
+defaults write -g 'NSAutomaticSpellingCorrectionEnabled' $'<?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">
+<false/>
+</plist>'
+defaults write -g 'NSAutomaticWindowAnimationsEnabled' $'<?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">
+<false/>
+</plist>'
+defaults write -g 'NSDisableAutomaticTermination' $'<?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">
+<true/>
+</plist>'
+defaults write -g 'NSDocumentSaveNewDocumentsToCloud' $'<?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">
+<false/>
+</plist>'
+defaults write -g 'NSNavPanelExpandedStateForSaveMode' $'<?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">
+<true/>
+</plist>'
+defaults write -g 'NSNavPanelExpandedStateForSaveMode2' $'<?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">
+<true/>
+</plist>'
+defaults write -g 'NSScrollAnimationEnabled' $'<?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">
+<true/>
+</plist>'
+defaults write -g 'NSTableViewDefaultSizeMode' $'<?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">
+<integer>2</integer>
+</plist>'
+defaults write -g 'NSTextShowsControlCharacters' $'<?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">
+<true/>
+</plist>'
+defaults write -g 'NSUseAnimatedFocusRing' $'<?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">
+<false/>
+</plist>'
+defaults write -g 'NSWindowResizeTime' $'<?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">
+<real>0.010000</real>
+</plist>'
+defaults write -g 'NSWindowShouldDragOnGesture' $'<?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">
+<true/>
+</plist>'
+defaults write -g 'PMPrintingExpandedStateForPrint' $'<?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">
+<true/>
+</plist>'
+defaults write -g 'PMPrintingExpandedStateForPrint2' $'<?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">
+<true/>
+</plist>'
+defaults write -g 'com.apple.keyboard.fnState' $'<?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">
+<true/>
+</plist>'
+defaults write -g 'com.apple.mouse.tapBehavior' $'<?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">
+<integer>1</integer>
+</plist>'
+defaults write -g 'com.apple.springing.delay' $'<?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">
+<real>0.000000</real>
+</plist>'
+defaults write -g 'com.apple.springing.enabled' $'<?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">
+<true/>
+</plist>'
+defaults write -g 'com.apple.swipescrolldirection' $'<?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">
+<true/>
+</plist>'
+defaults write -g 'com.apple.trackpad.enableSecondaryClick' $'<?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">
+<true/>
+</plist>'
+defaults write -g 'com.apple.trackpad.trackpadCornerClickBehavior' $'<?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">
+<integer>1</integer>
+</plist>'
+
+defaults write .GlobalPreferences 'com.apple.sound.beep.sound' $'<?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">
+<string>/System/Library/Sounds/Funk.aiff</string>
+</plist>'
+
+defaults write com.apple.menuextra.clock 'Show24Hour' $'<?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">
+<false/>
+</plist>'
+defaults write com.apple.menuextra.clock 'ShowDate' $'<?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">
+<integer>2</integer>
+</plist>'
+defaults write com.apple.menuextra.clock 'ShowDayOfWeek' $'<?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">
+<true/>
+</plist>'
+defaults write com.apple.dock 'appswitcher-all-displays' $'<?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">
+<false/>
+</plist>'
+defaults write com.apple.dock 'autohide-delay' $'<?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">
+<real>0.240000</real>
+</plist>'
+defaults write com.apple.dock 'orientation' $'<?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">
+<string>left</string>
+</plist>'
+defaults write com.apple.dock 'persistent-apps' $'<?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">
+<array>
+ <dict>
+ <key>tile-data</key>
+ <dict>
+ <key>file-data</key>
+ <dict>
+ <key>_CFURLString</key>
+ <string>MyApp.app</string>
+ <key>_CFURLStringType</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ </dict>
+ <dict>
+ <key>tile-data</key>
+ <dict>
+ <key>file-data</key>
+ <dict>
+ <key>_CFURLString</key>
+ <string>Cool.app</string>
+ <key>_CFURLStringType</key>
+ <integer>0</integer>
+ </dict>
+ </dict>
+ </dict>
+</array>
+</plist>'
+
+
+
+defaults write com.apple.screencapture 'location' $'<?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">
+<string>/tmp</string>
+</plist>'
+defaults write com.apple.screensaver 'askForPassword' $'<?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">
+<true/>
+</plist>'
+defaults write com.apple.screensaver 'askForPasswordDelay' $'<?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">
+<integer>5</integer>
+</plist>'
+
+
+
+defaults write com.apple.universalaccess 'closeViewScrollWheelToggle' $'<?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">
+<true/>
+</plist>'
+defaults write com.apple.universalaccess 'closeViewZoomFollowsFocus' $'<?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">
+<true/>
+</plist>'
+defaults write com.apple.universalaccess 'mouseDriverCursorSize' $'<?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">
+<real>1.500000</real>
+</plist>'
+defaults write com.apple.universalaccess 'reduceMotion' $'<?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">
+<true/>
+</plist>'
+defaults write com.apple.universalaccess 'reduceTransparency' $'<?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">
+<true/>
+</plist>'
+defaults write com.apple.ActivityMonitor 'IconType' $'<?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">
+<integer>3</integer>
+</plist>'
+defaults write com.apple.ActivityMonitor 'OpenMainWindow' $'<?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">
+<true/>
+</plist>'
+defaults write com.apple.ActivityMonitor 'ShowCategory' $'<?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">
+<integer>103</integer>
+</plist>'
+defaults write com.apple.ActivityMonitor 'SortColumn' $'<?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">
+<string>CPUUsage</string>
+</plist>'
+defaults write com.apple.ActivityMonitor 'SortDirection' $'<?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">
+<integer>0</integer>
+</plist>'
+defaults write NSGlobalDomain 'TISRomanSwitchState' $'<?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">
+<integer>1</integer>
+</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">
+<true/>
+</plist>'
diff --git a/tests/fixtures/system-defaults-write/activate.txt b/tests/fixtures/system-defaults-write/activate.txt
new file mode 100644
index 0000000..b22bc6d
--- /dev/null
+++ b/tests/fixtures/system-defaults-write/activate.txt
@@ -0,0 +1,10 @@
+defaults write /Library/Preferences/SystemConfiguration/com.apple.smb.server 'NetBIOSName' $'<?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">
+<string>IMAC-000000</string>
+</plist>'
+defaults write /Library/Preferences/SystemConfiguration/com.apple.smb.server 'ServerDescription' $'<?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">
+<string>Darwin\\\\U2019\'s iMac</string>
+</plist>'
diff --git a/tests/services-github-runners.nix b/tests/services-github-runners.nix
new file mode 100644
index 0000000..5578750
--- /dev/null
+++ b/tests/services-github-runners.nix
@@ -0,0 +1,20 @@
+{ config, pkgs, ... }:
+{
+ services.github-runners."a-runner" = {
+ enable = true;
+ url = "https://github.com/nixos/nixpkgs";
+ tokenFile = "/secret/path/to/a/github/token";
+ # We need an overridable derivation but cannot use the actual github-runner package
+ # since it still relies on Node.js 16 which is marked as insecure.
+ package = pkgs.hello;
+ };
+
+ test = ''
+ echo >&2 "checking github-runner service in /Library/LaunchDaemons"
+ grep "org.nixos.github-runner-a-runner" ${config.out}/Library/LaunchDaemons/org.nixos.github-runner-a-runner.plist
+ grep "<string>_github-runner</string>" ${config.out}/Library/LaunchDaemons/org.nixos.github-runner-a-runner.plist
+
+ echo >&2 "checking for user in /activate"
+ grep "GitHub Runner service user" ${config.out}/activate
+ '';
+}
diff --git a/tests/services-nix-optimise.nix b/tests/services-nix-optimise.nix
new file mode 100644
index 0000000..b0ecf18
--- /dev/null
+++ b/tests/services-nix-optimise.nix
@@ -0,0 +1,25 @@
+{ config, pkgs, ... }:
+
+let
+ nix = pkgs.runCommand "nix-2.2" {} "mkdir -p $out";
+in
+
+{
+ nix.optimise.automatic = true;
+ nix.optimise.user = "nixuser";
+ nix.package = nix;
+
+ test = ''
+ echo checking nix-optimise service in /Library/LaunchDaemons >&2
+ grep "<string>org.nixos.nix-optimise</string>" \
+ ${config.out}/Library/LaunchDaemons/org.nixos.nix-optimise.plist
+ grep "<string>/bin/wait4path ${nix} &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)
+ '';
+}
diff --git a/tests/system-defaults-write.nix b/tests/system-defaults-write.nix
index e3f69fe..9840298 100644
--- a/tests/system-defaults-write.nix
+++ b/tests/system-defaults-write.nix
@@ -1,4 +1,4 @@
-{ config, pkgs, ... }:
+{ config, pkgs, lib, ... }:
{
system.defaults.NSGlobalDomain.AppleShowAllFiles = true;
@@ -27,6 +27,7 @@
system.defaults.NSGlobalDomain.NSUseAnimatedFocusRing = false;
system.defaults.NSGlobalDomain.NSScrollAnimationEnabled = true;
system.defaults.NSGlobalDomain.NSWindowResizeTime = 0.01;
+ system.defaults.NSGlobalDomain.NSWindowShouldDragOnGesture = true;
system.defaults.NSGlobalDomain.InitialKeyRepeat = 10;
system.defaults.NSGlobalDomain.KeyRepeat = 1;
system.defaults.NSGlobalDomain.PMPrintingExpandedStateForPrint = true;
@@ -45,11 +46,12 @@
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.screencapture.location = "/tmp";
system.defaults.screensaver.askForPassword = true;
system.defaults.screensaver.askForPasswordDelay = 5;
system.defaults.smb.NetBIOSName = "IMAC-000000";
- system.defaults.smb.ServerDescription = ''Darwin\\\\U2019s iMac'';
+ system.defaults.smb.ServerDescription = ''Darwin\\\\U2019's iMac'';
system.defaults.universalaccess.mouseDriverCursorSize = 1.5;
system.defaults.universalaccess.reduceMotion = true;
system.defaults.universalaccess.reduceTransparency = true;
@@ -67,69 +69,19 @@
true;
};
};
- test = ''
- echo >&2 "checking defaults write in /activate"
- grep "defaults write /Library/Preferences/SystemConfiguration/com.apple.smb.server 'NetBIOSName' -string 'IMAC-000000'" ${config.out}/activate
- grep "defaults write /Library/Preferences/SystemConfiguration/com.apple.smb.server 'ServerDescription' -string 'Darwin.*s iMac'" ${config.out}/activate
-
- echo >&2 "checking defaults write in /activate-user"
- grep "defaults write -g 'AppleShowAllFiles' -bool YES" ${config.out}/activate-user
- grep "defaults write -g 'AppleEnableMouseSwipeNavigateWithScrolls' -bool NO" ${config.out}/activate-user
- grep "defaults write -g 'AppleEnableSwipeNavigateWithScrolls' -bool NO" ${config.out}/activate-user
- grep "defaults write -g 'AppleFontSmoothing' -int 1" ${config.out}/activate-user
- grep "defaults write -g 'AppleICUForce24HourTime' -bool YES" ${config.out}/activate-user
- grep "defaults write -g 'AppleKeyboardUIMode' -int 3" ${config.out}/activate-user
- grep "defaults write -g 'ApplePressAndHoldEnabled' -bool YES" ${config.out}/activate-user
- grep "defaults write -g 'AppleShowAllExtensions' -bool YES" ${config.out}/activate-user
- grep "defaults write -g 'AppleShowScrollBars' -string 'Always'" ${config.out}/activate-user
- grep "defaults write -g 'AppleScrollerPagingBehavior' -bool YES" ${config.out}/activate-user
- grep "defaults write -g 'NSAutomaticCapitalizationEnabled' -bool NO" ${config.out}/activate-user
- grep "defaults write -g 'NSAutomaticDashSubstitutionEnabled' -bool NO" ${config.out}/activate-user
- grep "defaults write -g 'NSAutomaticPeriodSubstitutionEnabled' -bool NO" ${config.out}/activate-user
- grep "defaults write -g 'NSAutomaticQuoteSubstitutionEnabled' -bool NO" ${config.out}/activate-user
- grep "defaults write -g 'NSAutomaticSpellingCorrectionEnabled' -bool NO" ${config.out}/activate-user
- grep "defaults write -g 'NSAutomaticWindowAnimationsEnabled' -bool NO" ${config.out}/activate-user
- grep "defaults write -g 'NSDisableAutomaticTermination' -bool YES" ${config.out}/activate-user
- grep "defaults write -g 'NSDocumentSaveNewDocumentsToCloud' -bool NO" ${config.out}/activate-user
- grep "defaults write -g 'AppleWindowTabbingMode' -string 'always'" ${config.out}/activate-user
- grep "defaults write -g 'NSNavPanelExpandedStateForSaveMode' -bool YES" ${config.out}/activate-user
- grep "defaults write -g 'NSNavPanelExpandedStateForSaveMode2' -bool YES" ${config.out}/activate-user
- grep "defaults write -g 'NSTableViewDefaultSizeMode' -int 2" ${config.out}/activate-user
- grep "defaults write -g 'NSTextShowsControlCharacters' -bool YES" ${config.out}/activate-user
- grep "defaults write -g 'NSUseAnimatedFocusRing' -bool NO" ${config.out}/activate-user
- grep "defaults write -g 'NSScrollAnimationEnabled' -bool YES" ${config.out}/activate-user
- grep "defaults write -g 'NSWindowResizeTime' -float 0.01" ${config.out}/activate-user
- grep "defaults write -g 'InitialKeyRepeat' -int 10" ${config.out}/activate-user
- grep "defaults write -g 'KeyRepeat' -int 1" ${config.out}/activate-user
- grep "defaults write -g 'PMPrintingExpandedStateForPrint' -bool YES" ${config.out}/activate-user
- grep "defaults write -g 'PMPrintingExpandedStateForPrint2' -bool YES" ${config.out}/activate-user
- grep "defaults write -g 'com.apple.keyboard.fnState' -bool YES" ${config.out}/activate-user
- grep "defaults write -g 'com.apple.mouse.tapBehavior' -int 1" ${config.out}/activate-user
- grep "defaults write -g 'com.apple.trackpad.enableSecondaryClick' -bool YES" ${config.out}/activate-user
- grep "defaults write -g 'com.apple.trackpad.trackpadCornerClickBehavior' -int 1" ${config.out}/activate-user
- grep "defaults write -g 'com.apple.springing.enabled' -bool YES" ${config.out}/activate-user
- grep "defaults write -g 'com.apple.springing.delay' -float 0.0" ${config.out}/activate-user
- grep "defaults write -g 'com.apple.swipescrolldirection' -bool YES" ${config.out}/activate-user
- grep "defaults write .GlobalPreferences 'com.apple.sound.beep.sound' -string '/System/Library/Sounds/Funk.aiff'" ${config.out}/activate-user
- grep "defaults write com.apple.menuextra.clock 'Show24Hour' -bool NO" ${config.out}/activate-user
- grep "defaults write com.apple.menuextra.clock 'ShowDayOfWeek' -bool YES" ${config.out}/activate-user
- grep "defaults write com.apple.menuextra.clock 'ShowDate' -int 2" ${config.out}/activate-user
- grep "defaults write com.apple.dock 'autohide-delay' -float 0.24" ${config.out}/activate-user
- grep "defaults write com.apple.dock 'appswitcher-all-displays' -bool NO" ${config.out}/activate-user
- grep "defaults write com.apple.dock 'orientation' -string 'left'" ${config.out}/activate-user
- grep "defaults write com.apple.screencapture 'location' -string '/tmp'" ${config.out}/activate-user
- grep "defaults write com.apple.screensaver 'askForPassword' -bool YES" ${config.out}/activate-user
- grep "defaults write com.apple.screensaver 'askForPasswordDelay' -int 5" ${config.out}/activate-user
- grep "defaults write com.apple.universalaccess 'mouseDriverCursorSize' -float 1.5" ${config.out}/activate-user
- grep "defaults write com.apple.universalaccess 'reduceMotion' -bool YES" ${config.out}/activate-user
- grep "defaults write com.apple.universalaccess 'reduceTransparency' -bool YES" ${config.out}/activate-user
- grep "defaults write com.apple.universalaccess 'closeViewScrollWheelToggle' -bool YES" ${config.out}/activate-user
- grep "defaults write com.apple.universalaccess 'closeViewZoomFollowsFocus' -bool YES" ${config.out}/activate-user
- grep "defaults write com.apple.ActivityMonitor 'ShowCategory' -int 103" ${config.out}/activate-user
- grep "defaults write com.apple.ActivityMonitor 'IconType' -int 3" ${config.out}/activate-user
- grep "defaults write com.apple.ActivityMonitor 'SortColumn' -string 'CPUUsage'" ${config.out}/activate-user
- grep "defaults write com.apple.ActivityMonitor 'SortDirection' -int 0" ${config.out}/activate-user
- grep "defaults write com.apple.ActivityMonitor 'OpenMainWindow' -bool YES" ${config.out}/activate-user
- grep "defaults write NSGlobalDomain 'TISRomanSwitchState' -int 1" ${config.out}/activate-user
- '';
+ test = lib.strings.concatMapStringsSep "\n" (x: ''
+ echo >&2 "checking defaults write in /${x}"
+ ${pkgs.python3}/bin/python3 <<EOL
+import sys
+from pathlib import Path
+fixture = '${./fixtures/system-defaults-write}/${x}.txt'
+out = '${config.out}/${x}'
+if Path(fixture).read_text() not in Path(out).read_text():
+ print("Did not find content from %s in %s" % (fixture, out), file=sys.stderr)
+ sys.exit(1)
+EOL
+ '') [
+ "activate"
+ "activate-user"
+ ];
}