about summary refs log tree commit diff
path: root/nixos
diff options
context:
space:
mode:
Diffstat (limited to 'nixos')
-rw-r--r--nixos/doc/manual/development/option-declarations.section.md4
-rw-r--r--nixos/doc/manual/from_md/development/option-declarations.section.xml12
-rw-r--r--nixos/lib/make-options-doc/mergeJSON.py9
-rw-r--r--nixos/modules/config/users-groups.nix4
-rw-r--r--nixos/modules/misc/documentation.nix2
-rw-r--r--nixos/modules/module-list.nix1
-rw-r--r--nixos/modules/programs/_1password-gui.nix2
-rw-r--r--nixos/modules/programs/_1password.nix2
-rw-r--r--nixos/modules/programs/flashrom.nix2
-rw-r--r--nixos/modules/programs/iay.nix37
-rw-r--r--nixos/modules/programs/skim.nix4
-rw-r--r--nixos/modules/programs/streamdeck-ui.nix2
-rw-r--r--nixos/modules/rename.nix2
-rw-r--r--nixos/modules/services/continuous-integration/gitlab-runner.nix90
-rw-r--r--nixos/modules/services/databases/dgraph.nix2
-rw-r--r--nixos/modules/services/mail/listmonk.nix2
-rw-r--r--nixos/modules/services/misc/input-remapper.nix2
-rw-r--r--nixos/modules/services/misc/polaris.nix2
-rw-r--r--nixos/modules/services/monitoring/apcupsd.nix17
-rw-r--r--nixos/modules/services/networking/openconnect.nix2
-rw-r--r--nixos/modules/services/networking/radicale.nix2
-rw-r--r--nixos/modules/services/networking/shellhub-agent.nix2
-rw-r--r--nixos/modules/services/networking/ssh/sshd.nix4
-rw-r--r--nixos/modules/services/networking/vdirsyncer.nix2
-rw-r--r--nixos/modules/services/networking/webhook.nix2
-rw-r--r--nixos/modules/services/torrent/transmission.nix6
-rw-r--r--nixos/modules/services/x11/desktop-managers/plasma5.nix4
-rw-r--r--nixos/modules/services/x11/picom.nix2
-rw-r--r--nixos/modules/services/x11/window-managers/katriawm.nix4
-rw-r--r--nixos/modules/services/x11/window-managers/qtile.nix2
-rw-r--r--nixos/modules/system/boot/systemd/initrd.nix2
-rw-r--r--nixos/tests/all-tests.nix1
-rw-r--r--nixos/tests/apcupsd.nix41
-rw-r--r--nixos/tests/wordpress.nix33
34 files changed, 235 insertions, 72 deletions
diff --git a/nixos/doc/manual/development/option-declarations.section.md b/nixos/doc/manual/development/option-declarations.section.md
index f89aae5730682..aa747f47c9c81 100644
--- a/nixos/doc/manual/development/option-declarations.section.md
+++ b/nixos/doc/manual/development/option-declarations.section.md
@@ -88,7 +88,7 @@ lib.mkOption {
 }
 ```
 
-### `mkPackageOption` {#sec-option-declarations-util-mkPackageOption}
+### `mkPackageOption`, `mkPackageOptionMD` {#sec-option-declarations-util-mkPackageOption}
 
 Usage:
 
@@ -106,6 +106,8 @@ The second argument is the name of the option, used in the description "The \<na
 
 You can omit the default path if the name of the option is also attribute path in nixpkgs.
 
+During the transition to CommonMark documentation `mkPackageOption` creates an option with a DocBook description attribute, once the transition is completed it will create a CommonMark description instead. `mkPackageOptionMD` always creates an option with a CommonMark description attribute and will be removed some time after the transition is completed.
+
 ::: {#ex-options-declarations-util-mkPackageOption .title}
 Examples:
 
diff --git a/nixos/doc/manual/from_md/development/option-declarations.section.xml b/nixos/doc/manual/from_md/development/option-declarations.section.xml
index 2e6a12d530953..cc4893939c280 100644
--- a/nixos/doc/manual/from_md/development/option-declarations.section.xml
+++ b/nixos/doc/manual/from_md/development/option-declarations.section.xml
@@ -138,7 +138,8 @@ lib.mkOption {
 }
 </programlisting>
       <section xml:id="sec-option-declarations-util-mkPackageOption">
-        <title><literal>mkPackageOption</literal></title>
+        <title><literal>mkPackageOption</literal>,
+        <literal>mkPackageOptionMD</literal></title>
         <para>
           Usage:
         </para>
@@ -172,6 +173,15 @@ mkPackageOption pkgs &quot;name&quot; { default = [ &quot;path&quot; &quot;in&qu
           You can omit the default path if the name of the option is
           also attribute path in nixpkgs.
         </para>
+        <para>
+          During the transition to CommonMark documentation
+          <literal>mkPackageOption</literal> creates an option with a
+          DocBook description attribute, once the transition is
+          completed it will create a CommonMark description instead.
+          <literal>mkPackageOptionMD</literal> always creates an option
+          with a CommonMark description attribute and will be removed
+          some time after the transition is completed.
+        </para>
         <anchor xml:id="ex-options-declarations-util-mkPackageOption" />
         <para>
           Examples:
diff --git a/nixos/lib/make-options-doc/mergeJSON.py b/nixos/lib/make-options-doc/mergeJSON.py
index 750cd24fc653d..7b14af40c313b 100644
--- a/nixos/lib/make-options-doc/mergeJSON.py
+++ b/nixos/lib/make-options-doc/mergeJSON.py
@@ -306,14 +306,17 @@ if hasDocBookErrors:
     print("Explanation: The documentation contains descriptions, examples, or defaults written in DocBook. " +
         "NixOS is in the process of migrating from DocBook to Markdown, and " +
         "DocBook is disallowed for in-tree modules. To change your contribution to "+
-        "use Markdown, apply mdDoc and literalMD. For example:\n" +
+        "use Markdown, apply mdDoc and literalMD and use the *MD variants of option creation " +
+        "functions where they are available. For example:\n" +
         "\n" +
         "  example.foo = mkOption {\n" +
         "    description = lib.mdDoc ''your description'';\n" +
         "    defaultText = lib.literalMD ''your description of default'';\n" +
-        "  }\n" +
+        "  };\n" +
         "\n" +
-        "  example.enable = mkEnableOption (lib.mdDoc ''your thing'');",
+        "  example.enable = mkEnableOption (lib.mdDoc ''your thing'');\n" +
+        "  example.package = mkPackageOptionMD pkgs \"your-package\" {};\n" +
+        "  imports = [ (mkAliasOptionModuleMD [ \"example\" \"args\" ] [ \"example\" \"settings\" ]) ];",
         file = sys.stderr)
 
 if hasErrors:
diff --git a/nixos/modules/config/users-groups.nix b/nixos/modules/config/users-groups.nix
index 19319b9309cd1..76092e738ebd4 100644
--- a/nixos/modules/config/users-groups.nix
+++ b/nixos/modules/config/users-groups.nix
@@ -444,8 +444,8 @@ let
 
 in {
   imports = [
-    (mkAliasOptionModule [ "users" "extraUsers" ] [ "users" "users" ])
-    (mkAliasOptionModule [ "users" "extraGroups" ] [ "users" "groups" ])
+    (mkAliasOptionModuleMD [ "users" "extraUsers" ] [ "users" "users" ])
+    (mkAliasOptionModuleMD [ "users" "extraGroups" ] [ "users" "groups" ])
     (mkRenamedOptionModule ["security" "initialRootPassword"] ["users" "users" "root" "initialHashedPassword"])
   ];
 
diff --git a/nixos/modules/misc/documentation.nix b/nixos/modules/misc/documentation.nix
index 64a8f7846b463..e44a9899772f1 100644
--- a/nixos/modules/misc/documentation.nix
+++ b/nixos/modules/misc/documentation.nix
@@ -50,7 +50,7 @@ let
           (name: value:
             let
               wholeName = "${namePrefix}.${name}";
-              guard = lib.warn "Attempt to evaluate package ${wholeName} in option documentation; this is not supported and will eventually be an error. Use `mkPackageOption` or `literalExpression` instead.";
+              guard = lib.warn "Attempt to evaluate package ${wholeName} in option documentation; this is not supported and will eventually be an error. Use `mkPackageOption{,MD}` or `literalExpression` instead.";
             in if isAttrs value then
               scrubDerivations wholeName value
               // optionalAttrs (isDerivation value) {
diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index 41b953dc34733..b2e80b10fc243 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -179,6 +179,7 @@
   ./programs/haguichi.nix
   ./programs/hamster.nix
   ./programs/htop.nix
+  ./programs/iay.nix
   ./programs/iftop.nix
   ./programs/i3lock.nix
   ./programs/iotop.nix
diff --git a/nixos/modules/programs/_1password-gui.nix b/nixos/modules/programs/_1password-gui.nix
index 83ef6037fb5a3..27c0d34a2eedf 100644
--- a/nixos/modules/programs/_1password-gui.nix
+++ b/nixos/modules/programs/_1password-gui.nix
@@ -27,7 +27,7 @@ in
         '';
       };
 
-      package = mkPackageOption pkgs "1Password GUI" {
+      package = mkPackageOptionMD pkgs "1Password GUI" {
         default = [ "_1password-gui" ];
       };
     };
diff --git a/nixos/modules/programs/_1password.nix b/nixos/modules/programs/_1password.nix
index 91246150755d5..8537484c7e67d 100644
--- a/nixos/modules/programs/_1password.nix
+++ b/nixos/modules/programs/_1password.nix
@@ -18,7 +18,7 @@ in
     programs._1password = {
       enable = mkEnableOption (lib.mdDoc "the 1Password CLI tool");
 
-      package = mkPackageOption pkgs "1Password CLI" {
+      package = mkPackageOptionMD pkgs "1Password CLI" {
         default = [ "_1password" ];
       };
     };
diff --git a/nixos/modules/programs/flashrom.nix b/nixos/modules/programs/flashrom.nix
index ff495558c9e04..294b208a37208 100644
--- a/nixos/modules/programs/flashrom.nix
+++ b/nixos/modules/programs/flashrom.nix
@@ -16,7 +16,7 @@ in
         group.
       '';
     };
-    package = mkPackageOption pkgs "flashrom" { };
+    package = mkPackageOptionMD pkgs "flashrom" { };
   };
 
   config = mkIf cfg.enable {
diff --git a/nixos/modules/programs/iay.nix b/nixos/modules/programs/iay.nix
new file mode 100644
index 0000000000000..1fa00e43795ad
--- /dev/null
+++ b/nixos/modules/programs/iay.nix
@@ -0,0 +1,37 @@
+{ config, lib, pkgs, ... }:
+
+let
+  cfg = config.programs.iay;
+  inherit (lib) mkEnableOption mkIf mkOption mkPackageOption optionalString types;
+in {
+  options.programs.iay = {
+    enable = mkEnableOption (lib.mdDoc "iay");
+    package = mkPackageOption pkgs "iay" {};
+
+    minimalPrompt = mkOption {
+      type = types.bool;
+      default = false;
+      description = lib.mdDoc "Use minimal one-liner prompt.";
+    };
+  };
+
+  config = mkIf cfg.enable {
+    programs.bash.promptInit = ''
+      if [[ $TERM != "dumb" && (-z $INSIDE_EMACS || $INSIDE_EMACS == "vterm") ]]; then
+        PS1='$(iay ${optionalString cfg.minimalPrompt "-m"})'
+      fi
+    '';
+
+    programs.zsh.promptInit = ''
+      if [[ $TERM != "dumb" && (-z $INSIDE_EMACS || $INSIDE_EMACS == "vterm") ]]; then
+        autoload -Uz add-zsh-hook
+        _iay_prompt() {
+          PROMPT="$(iay -z ${optionalString cfg.minimalPrompt "-m"})"
+        }
+        add-zsh-hook precmd _iay_prompt
+      fi
+    '';
+  };
+
+  meta.maintainers = pkgs.iay.meta.maintainers;
+}
diff --git a/nixos/modules/programs/skim.nix b/nixos/modules/programs/skim.nix
index 57a5d68ec3d5a..8dadf322606e2 100644
--- a/nixos/modules/programs/skim.nix
+++ b/nixos/modules/programs/skim.nix
@@ -1,6 +1,6 @@
 { pkgs, config, lib, ... }:
 let
-  inherit (lib) mdDoc mkEnableOption mkPackageOption optional optionalString;
+  inherit (lib) mdDoc mkEnableOption mkPackageOptionMD optional optionalString;
   cfg = config.programs.skim;
 in
 {
@@ -8,7 +8,7 @@ in
     programs.skim = {
       fuzzyCompletion = mkEnableOption (mdDoc "fuzzy completion with skim");
       keybindings = mkEnableOption (mdDoc "skim keybindings");
-      package = mkPackageOption pkgs "skim" {};
+      package = mkPackageOptionMD pkgs "skim" {};
     };
   };
 
diff --git a/nixos/modules/programs/streamdeck-ui.nix b/nixos/modules/programs/streamdeck-ui.nix
index 113d1d49e151a..4c055029e39b9 100644
--- a/nixos/modules/programs/streamdeck-ui.nix
+++ b/nixos/modules/programs/streamdeck-ui.nix
@@ -15,7 +15,7 @@ in
       description = lib.mdDoc "Whether streamdeck-ui should be started automatically.";
     };
 
-    package = mkPackageOption pkgs "streamdeck-ui" {
+    package = mkPackageOptionMD pkgs "streamdeck-ui" {
       default = [ "streamdeck-ui" ];
     };
 
diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix
index aef42d0f4db10..d88baac7a5d4d 100644
--- a/nixos/modules/rename.nix
+++ b/nixos/modules/rename.nix
@@ -14,7 +14,7 @@ with lib;
 
     # This alias module can't be where _module.check is defined because it would
     # be added to submodules as well there
-    (mkAliasOptionModule [ "environment" "checkConfigurationOptions" ] [ "_module" "check" ])
+    (mkAliasOptionModuleMD [ "environment" "checkConfigurationOptions" ] [ "_module" "check" ])
 
     # Completely removed modules
     (mkRemovedOptionModule [ "environment" "blcr" "enable" ] "The BLCR module has been removed")
diff --git a/nixos/modules/services/continuous-integration/gitlab-runner.nix b/nixos/modules/services/continuous-integration/gitlab-runner.nix
index 7b1c4da862606..d18c4cff04057 100644
--- a/nixos/modules/services/continuous-integration/gitlab-runner.nix
+++ b/nixos/modules/services/continuous-integration/gitlab-runner.nix
@@ -4,24 +4,41 @@ with lib;
 let
   cfg = config.services.gitlab-runner;
   hasDocker = config.virtualisation.docker.enable;
+
+  /* The whole logic of this module is to diff the hashes of the desired vs existing runners
+  The hash is recorded in the runner's name because we can't do better yet
+  See https://gitlab.com/gitlab-org/gitlab-runner/-/issues/29350 for more details
+  */
+  genRunnerName = service: let
+      hash = substring 0 12 (hashString "md5" (unsafeDiscardStringContext (toJSON service)));
+    in if service ? description
+    then "${hash} ${service.description}"
+    else "${name}_${config.networking.hostName}_${hash}";
+
   hashedServices = mapAttrs'
-    (name: service: nameValuePair
-      "${name}_${config.networking.hostName}_${
-        substring 0 12
-        (hashString "md5" (unsafeDiscardStringContext (toJSON service)))}"
-      service)
-    cfg.services;
-  configPath = "$HOME/.gitlab-runner/config.toml";
-  configureScript = pkgs.writeShellScriptBin "gitlab-runner-configure" (
-    if (cfg.configFile != null) then ''
-      mkdir -p $(dirname ${configPath})
+    (name: service: nameValuePair (genRunnerName service) service) cfg.services;
+  configPath = ''"$HOME"/.gitlab-runner/config.toml'';
+  configureScript = pkgs.writeShellApplication {
+    name = "gitlab-runner-configure";
+    runtimeInputs = with pkgs; [
+        bash
+        gawk
+        jq
+        moreutils
+        remarshal
+        util-linux
+        cfg.package
+        perl
+        python3
+    ];
+    text = if (cfg.configFile != null) then ''
       cp ${cfg.configFile} ${configPath}
       # make config file readable by service
       chown -R --reference=$HOME $(dirname ${configPath})
     '' else ''
       export CONFIG_FILE=${configPath}
 
-      mkdir -p $(dirname ${configPath})
+      mkdir -p "$(dirname "${configPath}")"
       touch ${configPath}
 
       # update global options
@@ -34,22 +51,43 @@ let
       # remove no longer existing services
       gitlab-runner verify --delete
 
-      # current and desired state
-      NEEDED_SERVICES=$(echo ${concatStringsSep " " (attrNames hashedServices)} | tr " " "\n")
-      REGISTERED_SERVICES=$(gitlab-runner list 2>&1 | grep 'Executor' | awk '{ print $1 }')
+      ${toShellVar "NEEDED_SERVICES" (lib.mapAttrs (name: value: 1) hashedServices)}
+
+      declare -A REGISTERED_SERVICES
+
+      while IFS="," read -r name token;
+      do
+        REGISTERED_SERVICES["$name"]="$token"
+      done < <(gitlab-runner --log-format json list 2>&1 | grep Token  | jq -r '.msg +"," + .Token')
+
+      echo "NEEDED_SERVICES: " "''${!NEEDED_SERVICES[@]}"
+      echo "REGISTERED_SERVICES:" "''${!REGISTERED_SERVICES[@]}"
 
       # difference between current and desired state
-      NEW_SERVICES=$(grep -vxF -f <(echo "$REGISTERED_SERVICES") <(echo "$NEEDED_SERVICES") || true)
-      OLD_SERVICES=$(grep -vxF -f <(echo "$NEEDED_SERVICES") <(echo "$REGISTERED_SERVICES") || true)
+      declare -A NEW_SERVICES
+      for name in "''${!NEEDED_SERVICES[@]}"; do
+        if [ ! -v 'REGISTERED_SERVICES[$name]' ]; then
+          NEW_SERVICES[$name]=1
+        fi
+      done
+
+      declare -A OLD_SERVICES
+      # shellcheck disable=SC2034
+      for name in "''${!REGISTERED_SERVICES[@]}"; do
+        if [ ! -v 'NEEDED_SERVICES[$name]' ]; then
+          OLD_SERVICES[$name]=1
+        fi
+      done
 
       # register new services
       ${concatStringsSep "\n" (mapAttrsToList (name: service: ''
-        if echo "$NEW_SERVICES" | grep -xq "${name}"; then
+        # TODO so here we should mention NEW_SERVICES
+        if [ -v 'NEW_SERVICES["${name}"]' ] ; then
           bash -c ${escapeShellArg (concatStringsSep " \\\n " ([
             "set -a && source ${service.registrationConfigFile} &&"
             "gitlab-runner register"
             "--non-interactive"
-            (if service.description != null then "--description \"${service.description}\"" else "--name '${name}'")
+            "--name '${name}'"
             "--executor ${service.executor}"
             "--limit ${toString service.limit}"
             "--request-concurrency ${toString service.requestConcurrency}"
@@ -92,22 +130,26 @@ let
         fi
       '') hashedServices)}
 
+      # check key is in array https://stackoverflow.com/questions/30353951/how-to-check-if-dictionary-contains-a-key-in-bash
+
+      echo "NEW_SERVICES: ''${NEW_SERVICES[*]}"
+      echo "OLD_SERVICES: ''${OLD_SERVICES[*]}"
       # unregister old services
-      for NAME in $(echo "$OLD_SERVICES")
+      for NAME in "''${!OLD_SERVICES[@]}"
       do
-        [ ! -z "$NAME" ] && gitlab-runner unregister \
+        [ -n "$NAME" ] && gitlab-runner unregister \
           --name "$NAME" && sleep 1
       done
 
       # make config file readable by service
-      chown -R --reference=$HOME $(dirname ${configPath})
-    '');
+      chown -R --reference="$HOME" "$(dirname ${configPath})"
+    '';
+  };
   startScript = pkgs.writeShellScriptBin "gitlab-runner-start" ''
     export CONFIG_FILE=${configPath}
     exec gitlab-runner run --working-directory $HOME
   '';
-in
-{
+in {
   options.services.gitlab-runner = {
     enable = mkEnableOption (lib.mdDoc "Gitlab Runner");
     configFile = mkOption {
diff --git a/nixos/modules/services/databases/dgraph.nix b/nixos/modules/services/databases/dgraph.nix
index 5726851a43f95..887164fa5b943 100644
--- a/nixos/modules/services/databases/dgraph.nix
+++ b/nixos/modules/services/databases/dgraph.nix
@@ -55,7 +55,7 @@ in
     services.dgraph = {
       enable = mkEnableOption (lib.mdDoc "Dgraph native GraphQL database with a graph backend");
 
-      package = lib.mkPackageOption pkgs "dgraph" { };
+      package = lib.mkPackageOptionMD pkgs "dgraph" { };
 
       settings = mkOption {
         type = settingsFormat.type;
diff --git a/nixos/modules/services/mail/listmonk.nix b/nixos/modules/services/mail/listmonk.nix
index 8b636bd5b1ff6..251362fdd89d3 100644
--- a/nixos/modules/services/mail/listmonk.nix
+++ b/nixos/modules/services/mail/listmonk.nix
@@ -128,7 +128,7 @@ in {
           '';
         };
       };
-      package = mkPackageOption pkgs "listmonk" {};
+      package = mkPackageOptionMD pkgs "listmonk" {};
       settings = mkOption {
         type = types.submodule { freeformType = tomlFormat.type; };
         description = lib.mdDoc ''
diff --git a/nixos/modules/services/misc/input-remapper.nix b/nixos/modules/services/misc/input-remapper.nix
index 51e1abdc98a08..6353966f5c3ff 100644
--- a/nixos/modules/services/misc/input-remapper.nix
+++ b/nixos/modules/services/misc/input-remapper.nix
@@ -7,7 +7,7 @@ let cfg = config.services.input-remapper; in
   options = {
     services.input-remapper = {
       enable = mkEnableOption (lib.mdDoc "input-remapper, an easy to use tool to change the mapping of your input device buttons.");
-      package = options.mkPackageOption pkgs "input-remapper" { };
+      package = mkPackageOptionMD pkgs "input-remapper" { };
       enableUdevRules = mkEnableOption (lib.mdDoc "udev rules added by input-remapper to handle hotplugged devices. Currently disabled by default due to https://github.com/sezanzeb/input-remapper/issues/140");
       serviceWantedBy = mkOption {
         default = [ "graphical.target" ];
diff --git a/nixos/modules/services/misc/polaris.nix b/nixos/modules/services/misc/polaris.nix
index 83da486083b42..70f097f028406 100644
--- a/nixos/modules/services/misc/polaris.nix
+++ b/nixos/modules/services/misc/polaris.nix
@@ -13,7 +13,7 @@ in
     services.polaris = {
       enable = mkEnableOption (lib.mdDoc "Polaris Music Server");
 
-      package = mkPackageOption pkgs "polaris" { };
+      package = mkPackageOptionMD pkgs "polaris" { };
 
       user = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/monitoring/apcupsd.nix b/nixos/modules/services/monitoring/apcupsd.nix
index d4216b44cdc8c..666479c78a84d 100644
--- a/nixos/modules/services/monitoring/apcupsd.nix
+++ b/nixos/modules/services/monitoring/apcupsd.nix
@@ -62,6 +62,21 @@ let
 
   );
 
+  # Ensure the CLI uses our generated configFile
+  wrappedBinaries = pkgs.runCommandLocal "apcupsd-wrapped-binaries"
+    { nativeBuildInputs = [ pkgs.makeWrapper ]; }
+    ''
+      for p in "${lib.getBin pkgs.apcupsd}/bin/"*; do
+          bname=$(basename "$p")
+          makeWrapper "$p" "$out/bin/$bname" --add-flags "-f ${configFile}"
+      done
+    '';
+
+  apcupsdWrapped = pkgs.symlinkJoin {
+    name = "apcupsd-wrapped";
+    # Put wrappers first so they "win"
+    paths = [ wrappedBinaries pkgs.apcupsd ];
+  };
 in
 
 {
@@ -138,7 +153,7 @@ in
     } ];
 
     # Give users access to the "apcaccess" tool
-    environment.systemPackages = [ pkgs.apcupsd ];
+    environment.systemPackages = [ apcupsdWrapped ];
 
     # NOTE 1: apcupsd runs as root because it needs permission to run
     # "shutdown"
diff --git a/nixos/modules/services/networking/openconnect.nix b/nixos/modules/services/networking/openconnect.nix
index 4676b1733af68..5a02bd072257f 100644
--- a/nixos/modules/services/networking/openconnect.nix
+++ b/nixos/modules/services/networking/openconnect.nix
@@ -116,7 +116,7 @@ let
   };
 in {
   options.networking.openconnect = {
-    package = mkPackageOption pkgs "openconnect" { };
+    package = mkPackageOptionMD pkgs "openconnect" { };
 
     interfaces = mkOption {
       description = lib.mdDoc "OpenConnect interfaces.";
diff --git a/nixos/modules/services/networking/radicale.nix b/nixos/modules/services/networking/radicale.nix
index 9ec507fe2ab6a..8e4789c7ca597 100644
--- a/nixos/modules/services/networking/radicale.nix
+++ b/nixos/modules/services/networking/radicale.nix
@@ -200,5 +200,5 @@ in {
     };
   };
 
-  meta.maintainers = with lib.maintainers; [ aneeshusa infinisil dotlambda ];
+  meta.maintainers = with lib.maintainers; [ infinisil dotlambda ];
 }
diff --git a/nixos/modules/services/networking/shellhub-agent.nix b/nixos/modules/services/networking/shellhub-agent.nix
index ad33c50f9d633..7cce23cb9c4e3 100644
--- a/nixos/modules/services/networking/shellhub-agent.nix
+++ b/nixos/modules/services/networking/shellhub-agent.nix
@@ -14,7 +14,7 @@ in
 
       enable = mkEnableOption (lib.mdDoc "ShellHub Agent daemon");
 
-      package = mkPackageOption pkgs "shellhub-agent" { };
+      package = mkPackageOptionMD pkgs "shellhub-agent" { };
 
       preferredHostname = mkOption {
         type = types.str;
diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix
index af8200c7e2951..37d7518ab3c4e 100644
--- a/nixos/modules/services/networking/ssh/sshd.nix
+++ b/nixos/modules/services/networking/ssh/sshd.nix
@@ -79,8 +79,8 @@ in
 
 {
   imports = [
-    (mkAliasOptionModule [ "services" "sshd" "enable" ] [ "services" "openssh" "enable" ])
-    (mkAliasOptionModule [ "services" "openssh" "knownHosts" ] [ "programs" "ssh" "knownHosts" ])
+    (mkAliasOptionModuleMD [ "services" "sshd" "enable" ] [ "services" "openssh" "enable" ])
+    (mkAliasOptionModuleMD [ "services" "openssh" "knownHosts" ] [ "programs" "ssh" "knownHosts" ])
     (mkRenamedOptionModule [ "services" "openssh" "challengeResponseAuthentication" ] [ "services" "openssh" "kbdInteractiveAuthentication" ])
   ];
 
diff --git a/nixos/modules/services/networking/vdirsyncer.nix b/nixos/modules/services/networking/vdirsyncer.nix
index 6a069943434da..f9b880c763e3d 100644
--- a/nixos/modules/services/networking/vdirsyncer.nix
+++ b/nixos/modules/services/networking/vdirsyncer.nix
@@ -71,7 +71,7 @@ in
     services.vdirsyncer = {
       enable = mkEnableOption (mdDoc "vdirsyncer");
 
-      package = mkPackageOption pkgs "vdirsyncer" {};
+      package = mkPackageOptionMD pkgs "vdirsyncer" {};
 
       jobs = mkOption {
         description = mdDoc "vdirsyncer job configurations";
diff --git a/nixos/modules/services/networking/webhook.nix b/nixos/modules/services/networking/webhook.nix
index b020db6961c32..2a78491941cf9 100644
--- a/nixos/modules/services/networking/webhook.nix
+++ b/nixos/modules/services/networking/webhook.nix
@@ -36,7 +36,7 @@ in {
         which execute configured commands for any person or service that knows the URL
       '');
 
-      package = mkPackageOption pkgs "webhook" {};
+      package = mkPackageOptionMD pkgs "webhook" {};
       user = mkOption {
         type = types.str;
         default = defaultUser;
diff --git a/nixos/modules/services/torrent/transmission.nix b/nixos/modules/services/torrent/transmission.nix
index 4378233848338..752ab91fe6315 100644
--- a/nixos/modules/services/torrent/transmission.nix
+++ b/nixos/modules/services/torrent/transmission.nix
@@ -19,8 +19,8 @@ in
   imports = [
     (mkRenamedOptionModule ["services" "transmission" "port"]
                            ["services" "transmission" "settings" "rpc-port"])
-    (mkAliasOptionModule ["services" "transmission" "openFirewall"]
-                         ["services" "transmission" "openPeerPorts"])
+    (mkAliasOptionModuleMD ["services" "transmission" "openFirewall"]
+                           ["services" "transmission" "openPeerPorts"])
   ];
   options = {
     services.transmission = {
@@ -174,7 +174,7 @@ in
         };
       };
 
-      package = mkPackageOption pkgs "transmission" {};
+      package = mkPackageOptionMD pkgs "transmission" {};
 
       downloadDirPermissions = mkOption {
         type = with types; nullOr str;
diff --git a/nixos/modules/services/x11/desktop-managers/plasma5.nix b/nixos/modules/services/x11/desktop-managers/plasma5.nix
index eb30e601dd009..8270b64787f8f 100644
--- a/nixos/modules/services/x11/desktop-managers/plasma5.nix
+++ b/nixos/modules/services/x11/desktop-managers/plasma5.nix
@@ -32,7 +32,7 @@ let
   inherit (lib)
     getBin optionalString literalExpression
     mkRemovedOptionModule mkRenamedOptionModule
-    mkDefault mkIf mkMerge mkOption mkPackageOption types;
+    mkDefault mkIf mkMerge mkOption mkPackageOptionMD types;
 
   ini = pkgs.formats.ini { };
 
@@ -198,7 +198,7 @@ in
       example = literalExpression "[ pkgs.plasma5Packages.oxygen ]";
     };
 
-    notoPackage = mkPackageOption pkgs "Noto fonts" {
+    notoPackage = mkPackageOptionMD pkgs "Noto fonts" {
       default = [ "noto-fonts" ];
       example = "noto-fonts-lgc-plus";
     };
diff --git a/nixos/modules/services/x11/picom.nix b/nixos/modules/services/x11/picom.nix
index 4a0578de09cb5..1d6f3daa40225 100644
--- a/nixos/modules/services/x11/picom.nix
+++ b/nixos/modules/services/x11/picom.nix
@@ -41,7 +41,7 @@ let
 in {
 
   imports = [
-    (mkAliasOptionModule [ "services" "compton" ] [ "services" "picom" ])
+    (mkAliasOptionModuleMD [ "services" "compton" ] [ "services" "picom" ])
     (mkRemovedOptionModule [ "services" "picom" "refreshRate" ] ''
       This option corresponds to `refresh-rate`, which has been unused
       since picom v6 and was subsequently removed by upstream.
diff --git a/nixos/modules/services/x11/window-managers/katriawm.nix b/nixos/modules/services/x11/window-managers/katriawm.nix
index 106631792ff4e..9a3fd5f3ca44a 100644
--- a/nixos/modules/services/x11/window-managers/katriawm.nix
+++ b/nixos/modules/services/x11/window-managers/katriawm.nix
@@ -1,7 +1,7 @@
 { config, lib, pkgs, ... }:
 
 let
-  inherit (lib) mdDoc mkEnableOption mkIf mkPackageOption singleton;
+  inherit (lib) mdDoc mkEnableOption mkIf mkPackageOptionMD singleton;
   cfg = config.services.xserver.windowManager.katriawm;
 in
 {
@@ -9,7 +9,7 @@ in
   options = {
     services.xserver.windowManager.katriawm = {
       enable = mkEnableOption (mdDoc "katriawm");
-      package = mkPackageOption pkgs "katriawm" {};
+      package = mkPackageOptionMD pkgs "katriawm" {};
     };
   };
 
diff --git a/nixos/modules/services/x11/window-managers/qtile.nix b/nixos/modules/services/x11/window-managers/qtile.nix
index 523642591d947..fc27566d49ee6 100644
--- a/nixos/modules/services/x11/window-managers/qtile.nix
+++ b/nixos/modules/services/x11/window-managers/qtile.nix
@@ -10,7 +10,7 @@ in
   options.services.xserver.windowManager.qtile = {
     enable = mkEnableOption (lib.mdDoc "qtile");
 
-    package = mkPackageOption pkgs "qtile" { };
+    package = mkPackageOptionMD pkgs "qtile" { };
   };
 
   config = mkIf cfg.enable {
diff --git a/nixos/modules/system/boot/systemd/initrd.nix b/nixos/modules/system/boot/systemd/initrd.nix
index 196f44ccd783c..d30f61146e189 100644
--- a/nixos/modules/system/boot/systemd/initrd.nix
+++ b/nixos/modules/system/boot/systemd/initrd.nix
@@ -142,7 +142,7 @@ in {
       '';
     };
 
-    package = (mkPackageOption pkgs "systemd" {
+    package = (mkPackageOptionMD pkgs "systemd" {
       default = "systemdStage1";
     }) // {
       visible = false;
diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix
index e9b58c7c4f77e..83ad7c48a0892 100644
--- a/nixos/tests/all-tests.nix
+++ b/nixos/tests/all-tests.nix
@@ -78,6 +78,7 @@ in {
   allTerminfo = handleTest ./all-terminfo.nix {};
   alps = handleTest ./alps.nix {};
   amazon-init-shell = handleTest ./amazon-init-shell.nix {};
+  apcupsd = handleTest ./apcupsd.nix {};
   apfs = handleTest ./apfs.nix {};
   apparmor = handleTest ./apparmor.nix {};
   atd = handleTest ./atd.nix {};
diff --git a/nixos/tests/apcupsd.nix b/nixos/tests/apcupsd.nix
new file mode 100644
index 0000000000000..287140f039d85
--- /dev/null
+++ b/nixos/tests/apcupsd.nix
@@ -0,0 +1,41 @@
+let
+  # arbitrary address
+  ipAddr = "192.168.42.42";
+in
+import ./make-test-python.nix ({ lib, pkgs, ... }: {
+  name = "apcupsd";
+  meta.maintainers = with lib.maintainers; [ bjornfor ];
+
+  nodes = {
+    machine = {
+      services.apcupsd = {
+        enable = true;
+        configText = ''
+          UPSTYPE usb
+          BATTERYLEVEL 42
+          # Configure NISIP so that the only way apcaccess can work is to read
+          # this config.
+          NISIP ${ipAddr}
+        '';
+      };
+      networking.interfaces.eth1 = {
+        ipv4.addresses = [{
+          address = ipAddr;
+          prefixLength = 24;
+        }];
+      };
+    };
+  };
+
+  # Check that the service starts, that the CLI (apcaccess) works and that it
+  # uses the config (ipAddr) defined in the service config.
+  testScript = ''
+    start_all()
+    machine.wait_for_unit("apcupsd.service")
+    machine.wait_for_open_port(3551, "${ipAddr}")
+    res = machine.succeed("apcaccess")
+    expect_line="MBATTCHG : 42 Percent"
+    assert "MBATTCHG : 42 Percent" in res, f"expected apcaccess output to contain '{expect_line}' but got '{res}'"
+    machine.shutdown()
+  '';
+})
diff --git a/nixos/tests/wordpress.nix b/nixos/tests/wordpress.nix
index 416a20aa7fe81..6a460dbce3547 100644
--- a/nixos/tests/wordpress.nix
+++ b/nixos/tests/wordpress.nix
@@ -1,6 +1,6 @@
-import ./make-test-python.nix ({ pkgs, ... }:
+import ./make-test-python.nix ({ lib, pkgs, ... }:
 
-{
+rec {
   name = "wordpress";
   meta = with pkgs.lib.maintainers; {
     maintainers = [
@@ -10,17 +10,22 @@ import ./make-test-python.nix ({ pkgs, ... }:
     ];
   };
 
-  nodes = {
-    wp_httpd = { ... }: {
+  nodes = lib.foldl (a: version: let
+    package = pkgs."wordpress${version}";
+  in a // {
+    "wp${version}_httpd" = _: {
       services.httpd.adminAddr = "webmaster@site.local";
       services.httpd.logPerVirtualHost = true;
 
+      services.wordpress.webserver = "httpd";
       services.wordpress.sites = {
         "site1.local" = {
           database.tablePrefix = "site1_";
+          inherit package;
         };
         "site2.local" = {
           database.tablePrefix = "site2_";
+          inherit package;
         };
       };
 
@@ -28,14 +33,16 @@ import ./make-test-python.nix ({ pkgs, ... }:
       networking.hosts."127.0.0.1" = [ "site1.local" "site2.local" ];
     };
 
-    wp_nginx = { ... }: {
+    "wp${version}_nginx" = _: {
       services.wordpress.webserver = "nginx";
       services.wordpress.sites = {
         "site1.local" = {
           database.tablePrefix = "site1_";
+          inherit package;
         };
         "site2.local" = {
           database.tablePrefix = "site2_";
+          inherit package;
         };
       };
 
@@ -43,34 +50,38 @@ import ./make-test-python.nix ({ pkgs, ... }:
       networking.hosts."127.0.0.1" = [ "site1.local" "site2.local" ];
     };
 
-    wp_caddy = { ... }: {
+    "wp${version}_caddy" = _: {
       services.wordpress.webserver = "caddy";
       services.wordpress.sites = {
         "site1.local" = {
           database.tablePrefix = "site1_";
+          inherit package;
         };
         "site2.local" = {
           database.tablePrefix = "site2_";
+          inherit package;
         };
       };
 
       networking.firewall.allowedTCPPorts = [ 80 ];
       networking.hosts."127.0.0.1" = [ "site1.local" "site2.local" ];
     };
-  };
+  }) {} [
+    "6_1"
+  ];
 
   testScript = ''
     import re
 
     start_all()
 
-    wp_httpd.wait_for_unit("httpd")
-    wp_nginx.wait_for_unit("nginx")
-    wp_caddy.wait_for_unit("caddy")
+    ${lib.concatStrings (lib.mapAttrsToList (name: value: ''
+      ${name}.wait_for_unit("${(value null).services.wordpress.webserver}")
+    '') nodes)}
 
     site_names = ["site1.local", "site2.local"]
 
-    for machine in (wp_httpd, wp_nginx, wp_caddy):
+    for machine in (${lib.concatStringsSep ", " (builtins.attrNames nodes)}):
         for site_name in site_names:
             machine.wait_for_unit(f"phpfpm-wordpress-{site_name}")