diff --git a/nixos/doc/manual/release-notes/rl-2505.section.md b/nixos/doc/manual/release-notes/rl-2505.section.md index 5079ca741469..6f1453de55a4 100644 --- a/nixos/doc/manual/release-notes/rl-2505.section.md +++ b/nixos/doc/manual/release-notes/rl-2505.section.md @@ -289,14 +289,22 @@ services.caddy = { enable = true; package = pkgs.caddy.withPlugins { - plugins = [ "github.com/caddy-dns/powerdns@v1.0.1" ]; - hash = "sha256-F/jqR4iEsklJFycTjSaW8B/V3iTGqqGOzwYBUXxRKrc="; + plugins = [ + # tagged upstream + "github.com/caddy-dns/powerdns@v1.0.1" + # pseudo-version number generated by Go + "github.com/caddy-dns/cloudflare@v0.0.0-20240703190432-89f16b99c18e" + "github.com/mholt/caddy-webdav@v0.0.0-20241008162340-42168ba04c9d" + ]; + hash = "sha256-wqXSd1Ep9TVpQi570TTb96LwzNYvWL5EBJXMJfYWCAk="; }; }; ``` To get the necessary hash of the vendored dependencies, omit `hash`. The build will fail and tell you the correct value. + Note that all provided plugins must have versions/tags (string after `@`), even if upstream repo does not tag each release. For untagged plugins, you can either create an empty Go project and run `go get ` and see changes in `go.mod` to get the pseudo-version number, or provide a commit hash in place of version/tag for the first run, and update the plugin string based on the error output. + - KDE Partition Manager `partitionmanager`'s support for ReiserFS is removed. ReiserFS has not been actively maintained for many years. It has been marked as obsolete since Linux 6.6, and [is removed](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=c01f664e4ca210823b7594b50669bbd9b0a3c3b0) diff --git a/nixos/tests/caddy.nix b/nixos/tests/caddy.nix index 57fe16f92d37..36d0051cf037 100644 --- a/nixos/tests/caddy.nix +++ b/nixos/tests/caddy.nix @@ -3,12 +3,15 @@ import ./make-test-python.nix ( { name = "caddy"; meta = with pkgs.lib.maintainers; { - maintainers = [ Br1ght0ne ]; + maintainers = [ + Br1ght0ne + stepbrobd + ]; }; nodes = { webserver = - { pkgs, lib, ... }: + { pkgs, ... }: { services.caddy.enable = true; services.caddy.extraConfig = '' @@ -63,6 +66,24 @@ import ./make-test-python.nix ( respond "hello world" ''; }; + specialisation.with-plugins.configuration = { + services.caddy = { + package = pkgs.caddy.withPlugins { + plugins = [ "github.com/caddyserver/replace-response@v0.0.0-20241211194404-3865845790a7" ]; + hash = "sha256-zgMdtOJbmtRSfTlrrg8njr11in2C7OAXLB+34V23jek="; + }; + configFile = pkgs.writeText "Caddyfile" '' + { + order replace after encode + } + + localhost:80 { + respond "hello world" + replace world caddy + } + ''; + }; + }; }; }; @@ -73,6 +94,7 @@ import ./make-test-python.nix ( justReloadSystem = "${nodes.webserver.system.build.toplevel}/specialisation/config-reload"; multipleConfigs = "${nodes.webserver.system.build.toplevel}/specialisation/multiple-configs"; rfc42Config = "${nodes.webserver.system.build.toplevel}/specialisation/rfc42"; + withPluginsConfig = "${nodes.webserver.system.build.toplevel}/specialisation/with-plugins"; in '' url = "http://localhost/example.html" @@ -108,6 +130,13 @@ import ./make-test-python.nix ( ) webserver.wait_for_open_port(80) webserver.succeed("curl http://localhost | grep hello") + + with subtest("plugins are correctled installed and configurable"): + webserver.succeed( + "${withPluginsConfig}/bin/switch-to-configuration test >&2" + ) + webserver.wait_for_open_port(80) + webserver.succeed("curl http://localhost | grep caddy") ''; } ) diff --git a/pkgs/by-name/ca/caddy/package.nix b/pkgs/by-name/ca/caddy/package.nix index 5a07a76181cf..e0f509b3cd6d 100644 --- a/pkgs/by-name/ca/caddy/package.nix +++ b/pkgs/by-name/ca/caddy/package.nix @@ -7,10 +7,6 @@ , testers , installShellFiles , stdenv -, go -, xcaddy -, cacert -, git }: let version = "2.8.4"; diff --git a/pkgs/by-name/ca/caddy/plugins.nix b/pkgs/by-name/ca/caddy/plugins.nix index 790c1180be67..e46a98167eae 100644 --- a/pkgs/by-name/ca/caddy/plugins.nix +++ b/pkgs/by-name/ca/caddy/plugins.nix @@ -1,3 +1,4 @@ +# callPackage args { lib, stdenv, @@ -7,19 +8,44 @@ git, caddy, }: + +let + inherit (builtins) hashString; + inherit (lib) + assertMsg + concatMapStrings + elemAt + fakeHash + filter + hasInfix + length + lessThan + sort + toShellVar + ; +in + +# pkgs.caddy.withPlugins args { plugins, - hash ? lib.fakeHash, + hash ? fakeHash, }: + let - pluginsSorted = lib.sort lib.lessThan plugins; - pluginsList = lib.concatMapStrings (plugin: "${plugin}-") pluginsSorted; - pluginsHash = builtins.hashString "md5" pluginsList; - pluginsWithoutVersion = lib.filter (p: !lib.hasInfix "@" p) pluginsSorted; + pluginsSorted = sort lessThan plugins; + pluginsList = concatMapStrings (plugin: "${plugin}-") pluginsSorted; + pluginsHash = hashString "md5" pluginsList; + pluginsWithoutVersion = filter (p: !hasInfix "@" p) pluginsSorted; in -assert lib.assertMsg ( - lib.length pluginsWithoutVersion == 0 -) "All plugins should have a version (eg ${lib.elemAt pluginsWithoutVersion 0}@x.y.z)!"; + +# eval barrier: user provided plugins must have tags +# the go module must either be tagged in upstream repo +# or user must provide commit sha or a pseudo-version number +# https://go.dev/doc/modules/version-numbers#pseudo-version-number +assert assertMsg ( + length pluginsWithoutVersion == 0 +) "Plugins must have tags present (e.g. ${elemAt pluginsWithoutVersion 0}@x.y.z)!"; + caddy.overrideAttrs ( finalAttrs: prevAttrs: { vendorHash = null; @@ -38,7 +64,7 @@ caddy.overrideAttrs ( dontUnpack = true; buildPhase = let - withArgs = lib.concatMapStrings (plugin: "--with ${plugin} ") pluginsSorted; + withArgs = concatMapStrings (plugin: "--with ${plugin} ") pluginsSorted; in '' export GOCACHE=$TMPDIR/go-cache @@ -55,11 +81,14 @@ caddy.overrideAttrs ( outputHashAlgo = "sha256"; }; + # xcaddy built output always uses pseudo-version number + # we enforce user provided plugins are present and have matching tags here doInstallCheck = true; installCheckPhase = '' runHook preInstallCheck - ${lib.toShellVar "notfound" pluginsSorted} + ${toShellVar "notfound" pluginsSorted} + while read kind module version; do [[ "$kind" = "dep" ]] || continue module="''${module}@''${version}" @@ -69,8 +98,28 @@ caddy.overrideAttrs ( fi done done < <($out/bin/caddy build-info) + if (( ''${#notfound[@]} )); then - >&2 echo "Plugins not found: ''${notfound[@]}" + for plugin in "''${notfound[@]}"; do + base=''${plugin%@*} + specified=''${plugin#*@} + found=0 + + while read kind module expected; do + [[ "$kind" = "dep" && "$module" = "$base" ]] || continue + echo "Plugin \"$base\" have incorrect tag:" + echo " specified: \"$base@$specified\"" + echo " got: \"$base@$expected\"" + found=1 + done < <($out/bin/caddy build-info) + + if (( found == 0 )); then + echo "Plugin \"$base\" not found in build:" + echo " specified: \"$base@$specified\"" + echo " plugin does not exist in the xcaddy build output, open an issue in nixpkgs or upstream" + fi + done + exit 1 fi