From 34e7918c86322476f4308b98a0b7232a476a2d78 Mon Sep 17 00:00:00 2001 From: Noah Markert Date: Sat, 13 Jun 2026 10:47:26 +0200 Subject: [PATCH 01/45] freeradius: 3.2.8 -> 3.2.10 --- pkgs/by-name/fr/freeradius/package.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/by-name/fr/freeradius/package.nix b/pkgs/by-name/fr/freeradius/package.nix index 7f0036dc66a5..3aa2e394b9f5 100644 --- a/pkgs/by-name/fr/freeradius/package.nix +++ b/pkgs/by-name/fr/freeradius/package.nix @@ -38,13 +38,13 @@ assert withRest -> withJson; stdenv.mkDerivation rec { pname = "freeradius"; - version = "3.2.8"; + version = "3.2.10"; src = fetchFromGitHub { owner = "FreeRADIUS"; repo = "freeradius-server"; tag = "release_${lib.replaceStrings [ "." ] [ "_" ] version}"; - hash = "sha256-NvcXTT0jp3WR/w+JWcNESg6iNYqIV8QAlM8MxpYkpjs="; + hash = "sha256-+pFV6dDnL7T5G309cLACa+/0vGppCEdk3ghOQhgSjTs="; }; nativeBuildInputs = [ autoreconfHook ]; From 5faa73af1db4258328925792ed56e2204c9a181d Mon Sep 17 00:00:00 2001 From: "R. Ryantm" Date: Sat, 13 Jun 2026 19:47:16 +0000 Subject: [PATCH 02/45] sssd: 2.13.0 -> 2.13.1 --- pkgs/by-name/ss/sssd/package.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/by-name/ss/sssd/package.nix b/pkgs/by-name/ss/sssd/package.nix index c9d89133e736..91b66f7eb88a 100644 --- a/pkgs/by-name/ss/sssd/package.nix +++ b/pkgs/by-name/ss/sssd/package.nix @@ -65,13 +65,13 @@ let in stdenv.mkDerivation (finalAttrs: { pname = "sssd"; - version = "2.13.0"; + version = "2.13.1"; src = fetchFromGitHub { owner = "SSSD"; repo = "sssd"; tag = finalAttrs.version; - hash = "sha256-/zMF7+rpQpWNq7srK2/gP99tgq8s6uFAYb/ORoPO/9w="; + hash = "sha256-f4abHqZ8ojNU4dVw1hkfEJC4asE/NamhYmOQyy368eI="; }; patches = [ From b5f2b69b07a6a4b99e268ce674e4c35cb3c59912 Mon Sep 17 00:00:00 2001 From: "R. Ryantm" Date: Mon, 29 Jun 2026 05:47:54 +0000 Subject: [PATCH 03/45] python3Packages.sigima: 1.1.4 -> 1.1.5 --- pkgs/development/python-modules/sigima/default.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/development/python-modules/sigima/default.nix b/pkgs/development/python-modules/sigima/default.nix index 234d3967c616..bf67ac8b0666 100644 --- a/pkgs/development/python-modules/sigima/default.nix +++ b/pkgs/development/python-modules/sigima/default.nix @@ -47,7 +47,7 @@ buildPythonPackage (finalAttrs: { pname = "sigima"; - version = "1.1.4"; + version = "1.1.5"; pyproject = true; __structuredAttrs = true; @@ -55,7 +55,7 @@ buildPythonPackage (finalAttrs: { owner = "DataLab-Platform"; repo = "Sigima"; tag = "v${finalAttrs.version}"; - hash = "sha256-AQrUn/WgWZ5W9Lrg4TJjerEZvGDH1wKL2WbeP3sGjrE="; + hash = "sha256-WRuTncx6iKQVdKjDaSwg/hVcBM4WxLGq1pcMEMXMVQI="; }; build-system = [ From cfedd4f94237a409709b83646da8e77af8ed413f Mon Sep 17 00:00:00 2001 From: "R. Ryantm" Date: Mon, 29 Jun 2026 08:15:43 +0000 Subject: [PATCH 04/45] listmonk: 6.1.0 -> 6.2.0 --- pkgs/by-name/li/listmonk/email-builder.nix | 2 +- pkgs/by-name/li/listmonk/frontend.nix | 2 +- pkgs/by-name/li/listmonk/package.nix | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/pkgs/by-name/li/listmonk/email-builder.nix b/pkgs/by-name/li/listmonk/email-builder.nix index a8c4718730e6..4b069365903e 100644 --- a/pkgs/by-name/li/listmonk/email-builder.nix +++ b/pkgs/by-name/li/listmonk/email-builder.nix @@ -17,7 +17,7 @@ stdenv.mkDerivation { offlineCache = fetchYarnDeps { yarnLock = "${src}/frontend/email-builder/yarn.lock"; - hash = "sha256-sFRmnMPStNp45hxcF+Iq1WhH6LtVFtgq2regq6MPzcc="; + hash = "sha256-ANPLOL9j0gljtNtbfb+ZifVRN9vLexPddAevpeFwX4o="; }; nativeBuildInputs = [ diff --git a/pkgs/by-name/li/listmonk/frontend.nix b/pkgs/by-name/li/listmonk/frontend.nix index 4fec2c272de4..cb82721de315 100644 --- a/pkgs/by-name/li/listmonk/frontend.nix +++ b/pkgs/by-name/li/listmonk/frontend.nix @@ -17,7 +17,7 @@ stdenv.mkDerivation (finalAttrs: { offlineCache = fetchYarnDeps { yarnLock = "${src}/frontend/yarn.lock"; - hash = "sha256-VCaEMftA7AzW/6jyceVO596iby0wC3LW9YDG66kLJmw="; + hash = "sha256-R2xHcHksTtFfFh41FLeBhpuz84ceixGt6oz6SQWWyMQ="; }; nativeBuildInputs = [ diff --git a/pkgs/by-name/li/listmonk/package.nix b/pkgs/by-name/li/listmonk/package.nix index 7fc3c88b6425..ed62aebb3996 100644 --- a/pkgs/by-name/li/listmonk/package.nix +++ b/pkgs/by-name/li/listmonk/package.nix @@ -11,16 +11,16 @@ buildGoModule (finalAttrs: { pname = "listmonk"; - version = "6.1.0"; + version = "6.2.0"; src = fetchFromGitHub { owner = "knadh"; repo = "listmonk"; rev = "v${finalAttrs.version}"; - hash = "sha256-SG9PhQOu3QB0LA9dNLnNzwwtfaib7MCfvOcBMkWMRPw="; + hash = "sha256-eora/+zJf60trmANEqAhYAQXfEMifyw5gLPKcqBW46w="; }; - vendorHash = "sha256-0KrjaExgT9tN4M99CfyQpqpGYnXOpzsPRk/Ih4qXsuE="; + vendorHash = "sha256-t4l8872bniTmNIW4ias1gImURJgrR6htXkncqfrJ+AU="; nativeBuildInputs = [ stuffbin From e1a4f68f2ae09dcb313677c27928a0972cfd16ad Mon Sep 17 00:00:00 2001 From: "R. Ryantm" Date: Mon, 29 Jun 2026 22:06:06 +0000 Subject: [PATCH 05/45] mattermostLatest: 11.8.1 -> 11.8.2 --- pkgs/by-name/ma/mattermostLatest/package.nix | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkgs/by-name/ma/mattermostLatest/package.nix b/pkgs/by-name/ma/mattermostLatest/package.nix index e0fd905a82d2..e98f1f7032b5 100644 --- a/pkgs/by-name/ma/mattermostLatest/package.nix +++ b/pkgs/by-name/ma/mattermostLatest/package.nix @@ -15,10 +15,10 @@ mattermost.override ( # and make sure the version regex is up to date here. # Ensure you also check ../mattermost/package.nix for ESR releases. regex = "^v(11\\.[0-9]+\\.[0-9]+)$"; - version = "11.8.1"; - srcHash = "sha256-9EIbTwnEeZQKg5uixkMp3sp/n+9I2N9W7hxsW5juF3M="; + version = "11.8.2"; + srcHash = "sha256-XZ4yr7nbGum6UQaBjze50L8Yc/MLjo4NQBh263CNRtI="; vendorHash = "sha256-F2QMrLbio7812ZTGQZZPTqHWtIXbwbDmjUhtvv0DJ9s="; - npmDepsHash = "sha256-9GRM0VXrh1eR16ocSGEV/F2eflOflzkhrhRRnm9uB6s="; + npmDepsHash = "sha256-WIPLpi6lQvq9wieqvOACiRh7v1znxzcf+jyKXSjWzNc="; autoUpdate = ./package.nix; }; } From f9f60a4608798c2bf37208562dbdcf2ddfa59e61 Mon Sep 17 00:00:00 2001 From: Arnout Engelen Date: Tue, 30 Jun 2026 16:53:01 +0200 Subject: [PATCH 06/45] onlyoffice-documentserver: use icu78 This is needed so that doctrenderer uses the same version of icu as the nodejs.libv8 . This is a little scary because it's a different version of icu than boost is built with, but seems to work out in practice. After #520553 this should ideally be in sync again. Fixes #536824 --- pkgs/by-name/on/onlyoffice-documentserver/x2t.nix | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/pkgs/by-name/on/onlyoffice-documentserver/x2t.nix b/pkgs/by-name/on/onlyoffice-documentserver/x2t.nix index 26d1d20ea9db..09208f3e79a2 100644 --- a/pkgs/by-name/on/onlyoffice-documentserver/x2t.nix +++ b/pkgs/by-name/on/onlyoffice-documentserver/x2t.nix @@ -12,7 +12,7 @@ optipng, x265, libde265, - icu, + icu78, jdk, lib, nodejs_22, @@ -30,6 +30,9 @@ }: let + # default at the time of writing is still 76, + # but libv8 from nodejs_22 needs 78 + icu = icu78; openssl' = openssl.override { enableMD2 = true; static = true; @@ -41,8 +44,11 @@ let $BUILDRT/Common/3dParty/icu/icu.pri \ --replace-fail "ICU_MAJOR_VER = 74" "ICU_MAJOR_VER = ${lib.versions.major icu.version}" - mkdir $BUILDRT/Common/3dParty/icu/linux_64 - ln -s ${icu}/lib $BUILDRT/Common/3dParty/icu/linux_64/build + mkdir -p $BUILDRT/Common/3dParty/icu/linux_64/build + ln -s ${icu.dev}/include $BUILDRT/Common/3dParty/icu/linux_64/build/include + for i in ${icu}/lib/* ; do + ln -s $i $BUILDRT/Common/3dParty/icu/linux_64/build/$(basename $i) + done ''; icuQmakeFlags = [ "QMAKE_LFLAGS+=-Wl,--no-undefined" From c975ef3d1a02fd6b9dfd5718cec61003d1889dfc Mon Sep 17 00:00:00 2001 From: "R. Ryantm" Date: Wed, 1 Jul 2026 03:24:21 +0000 Subject: [PATCH 07/45] zsh-forgit: 26.05.0 -> 26.07.0 --- pkgs/by-name/zs/zsh-forgit/package.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/by-name/zs/zsh-forgit/package.nix b/pkgs/by-name/zs/zsh-forgit/package.nix index 7fb1ec8e44c1..b6b0ca367435 100644 --- a/pkgs/by-name/zs/zsh-forgit/package.nix +++ b/pkgs/by-name/zs/zsh-forgit/package.nix @@ -16,13 +16,13 @@ stdenvNoCC.mkDerivation (finalAttrs: { pname = "zsh-forgit"; - version = "26.05.0"; + version = "26.07.0"; src = fetchFromGitHub { owner = "wfxr"; repo = "forgit"; tag = finalAttrs.version; - hash = "sha256-EFbzrVgLfVO+dEEQ1vZUcZkIszZFCktYjQjwkBVrHQI="; + hash = "sha256-Ks/kUuQLtzKLjwIDpfkh6pL90aII8Rfh8ijxDmlFvmg="; }; strictDeps = true; From 0a35e687d74a79bda24043b9fdd2e873a6d34891 Mon Sep 17 00:00:00 2001 From: "R. Ryantm" Date: Wed, 1 Jul 2026 19:06:04 +0000 Subject: [PATCH 08/45] selinuxPackages.semodule-utils: 3.10 -> 3.11 --- pkgs/by-name/se/semodule-utils/package.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/by-name/se/semodule-utils/package.nix b/pkgs/by-name/se/semodule-utils/package.nix index e8364954b4d1..ad0eb8f40db8 100644 --- a/pkgs/by-name/se/semodule-utils/package.nix +++ b/pkgs/by-name/se/semodule-utils/package.nix @@ -7,13 +7,13 @@ stdenv.mkDerivation (finalAttrs: { pname = "semodule-utils"; - version = "3.10"; + version = "3.11"; inherit (libsepol) se_url; src = fetchurl { url = "${finalAttrs.se_url}/${finalAttrs.version}/semodule-utils-${finalAttrs.version}.tar.gz"; - hash = "sha256-HC8UzAmMu011kS0THF90fnAkbhBC5y8qtA4o9Tz0XBA="; + hash = "sha256-DFdOFUE/9+1mDEXgEb7+JIu4nqonPbb1brKX1h3rLtY="; }; buildInputs = [ libsepol ]; From 22b74d95da33e0b2f927939fa3c9f196e6cbf703 Mon Sep 17 00:00:00 2001 From: "R. Ryantm" Date: Wed, 1 Jul 2026 19:06:15 +0000 Subject: [PATCH 09/45] selinux-sandbox: 3.10 -> 3.11 --- pkgs/by-name/se/selinux-sandbox/package.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/by-name/se/selinux-sandbox/package.nix b/pkgs/by-name/se/selinux-sandbox/package.nix index 060fb77ad612..72dd5ea60172 100644 --- a/pkgs/by-name/se/selinux-sandbox/package.nix +++ b/pkgs/by-name/se/selinux-sandbox/package.nix @@ -21,12 +21,12 @@ stdenv.mkDerivation (finalAttrs: { pname = "selinux-sandbox"; - version = "3.10"; + version = "3.11"; inherit (policycoreutils) se_url; src = fetchurl { url = "${finalAttrs.se_url}/${finalAttrs.version}/selinux-sandbox-${finalAttrs.version}.tar.gz"; - hash = "sha256-4r0T4YT3IYFVoz6pQygdAvRBwpcQQBW+69/G2Npv9cM="; + hash = "sha256-MnxiXev62tCi1Ek6PP7ZhS9GA5AhQrLLWHV1Z/LeOt8="; }; nativeBuildInputs = [ From 9306bd0932bfabb948442b02de24967ae5629249 Mon Sep 17 00:00:00 2001 From: John Titor <50095635+JohnRTitor@users.noreply.github.com> Date: Thu, 2 Jul 2026 01:05:50 +0530 Subject: [PATCH 10/45] nixos/ollama: rename services.ollama.models to modelsDir It was ambigious with loadModels --- nixos/modules/services/misc/ollama.nix | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/nixos/modules/services/misc/ollama.nix b/nixos/modules/services/misc/ollama.nix index bc1693f1902e..3ce42646a64d 100644 --- a/nixos/modules/services/misc/ollama.nix +++ b/nixos/modules/services/misc/ollama.nix @@ -37,6 +37,18 @@ in "ollama" "acceleration" ] "Set `services.ollama.package` to one of `pkgs.ollama[,-vulkan,-rocm,-cuda,-cpu]` instead.") + (lib.mkRenamedOptionModule + [ + "services" + "ollama" + "models" + ] + [ + "services" + "ollama" + "modelsDir" + ] + ) ]; options = { @@ -91,7 +103,7 @@ in The home directory that the ollama service is started in. ''; }; - models = lib.mkOption { + modelsDir = lib.mkOption { type = types.str; default = "${cfg.home}/models"; defaultText = "\${config.services.ollama.home}/models"; @@ -207,7 +219,7 @@ in cfg.environmentVariables // { HOME = cfg.home; - OLLAMA_MODELS = cfg.models; + OLLAMA_MODELS = cfg.modelsDir; OLLAMA_HOST = "${cfg.host}:${toString cfg.port}"; } // lib.optionalAttrs (cfg.rocmOverrideGfx != null) { @@ -226,7 +238,7 @@ in StateDirectory = [ "ollama" ]; ReadWritePaths = [ cfg.home - cfg.models + cfg.modelsDir ]; CapabilityBoundingSet = [ "" ]; From 13a2636935baf2cd7e4d3d40e26087f88cb0989e Mon Sep 17 00:00:00 2001 From: "R. Ryantm" Date: Wed, 1 Jul 2026 20:14:21 +0000 Subject: [PATCH 11/45] libsemanage: 3.10 -> 3.11 --- pkgs/by-name/li/libsemanage/package.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/by-name/li/libsemanage/package.nix b/pkgs/by-name/li/libsemanage/package.nix index c0423d7ef3e5..d37f651c1a29 100644 --- a/pkgs/by-name/li/libsemanage/package.nix +++ b/pkgs/by-name/li/libsemanage/package.nix @@ -16,12 +16,12 @@ stdenv.mkDerivation (finalAttrs: { pname = "libsemanage"; - version = "3.10"; + version = "3.11"; inherit (libsepol) se_url; src = fetchurl { url = "${finalAttrs.se_url}/${finalAttrs.version}/libsemanage-${finalAttrs.version}.tar.gz"; - hash = "sha256-GXiJTEFHaa13Q40miG6q4/t7t0V47ypa0xMMictcsf4="; + hash = "sha256-52FgKGu/sIIWAsbAwyIOvPNmrTJG07nQoPvvzTXoYEM="; }; outputs = [ From e07a1255a85d2b8eb757aa96005caca8ee8dd5ae Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Wed, 1 Jul 2026 01:25:59 +0200 Subject: [PATCH 12/45] cyberstrike: init at 1.1.14 AI-powered offensive security agent https://github.com/CyberStrikeus/CyberStrike --- pkgs/by-name/cy/cyberstrike/package.nix | 178 ++++++++++++++++++++++++ 1 file changed, 178 insertions(+) create mode 100644 pkgs/by-name/cy/cyberstrike/package.nix diff --git a/pkgs/by-name/cy/cyberstrike/package.nix b/pkgs/by-name/cy/cyberstrike/package.nix new file mode 100644 index 000000000000..8ce2972eb26e --- /dev/null +++ b/pkgs/by-name/cy/cyberstrike/package.nix @@ -0,0 +1,178 @@ +{ + lib, + bun, + fetchFromGitHub, + installShellFiles, + makeBinaryWrapper, + models-dev, + nix-update-script, + nodejs, + ripgrep, + stdenvNoCC, + sysctl, + versionCheckHook, + writableTmpDirAsHomeHook, +}: + +stdenvNoCC.mkDerivation (finalAttrs: { + pname = "cyberstrike"; + version = "1.1.14"; + + __structuredAttrs = true; + strictDeps = true; + + src = fetchFromGitHub { + owner = "CyberStrikeus"; + repo = "CyberStrike"; + tag = "v${finalAttrs.version}"; + hash = "sha256-MlFEGP/MiuDtLl7Ms6j11u1MdLV6w8T/7TYo7eeE/rc="; + }; + + node_modules = stdenvNoCC.mkDerivation { + pname = "${finalAttrs.pname}-node_modules"; + inherit (finalAttrs) version src; + + impureEnvVars = lib.fetchers.proxyImpureEnvVars ++ [ + "GIT_PROXY_COMMAND" + "SOCKS_SERVER" + ]; + + nativeBuildInputs = [ + bun + writableTmpDirAsHomeHook + ]; + + dontConfigure = true; + + buildPhase = '' + runHook preBuild + + export BUN_INSTALL_CACHE_DIR=$(mktemp -d) + bun install \ + --cpu="${if stdenvNoCC.hostPlatform.isAarch64 then "arm64" else "x64"}" \ + --os="${if stdenvNoCC.hostPlatform.isLinux then "linux" else "darwin"}" \ + --filter '!./' \ + --filter './packages/cyberstrike' \ + --frozen-lockfile \ + --ignore-scripts \ + --no-progress + + bun --bun ./nix/scripts/canonicalize-node-modules.ts + bun --bun ./nix/scripts/normalize-bun-binaries.ts + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + mkdir -p $out + find . -type d -name node_modules -exec cp -R --parents {} $out \; + + runHook postInstall + ''; + + # Required so fixed-output derivation does not retain store references + dontFixup = true; + + outputHash = "sha256-IxIdzd9MJJRpc0nB5eEASSW0LIckU+SvcUgkKoL+mog="; + outputHashAlgo = "sha256"; + outputHashMode = "recursive"; + }; + + nativeBuildInputs = [ + bun + installShellFiles + makeBinaryWrapper + writableTmpDirAsHomeHook + ]; + + configurePhase = '' + runHook preConfigure + + cp -R ${finalAttrs.node_modules}/. . + patchShebangs node_modules + patchShebangs packages/*/node_modules + + runHook postConfigure + ''; + + env = { + MODELS_DEV_API_JSON = "${models-dev}/dist/_api.json"; + CYBERSTRIKE_DISABLE_MODELS_FETCH = true; + CYBERSTRIKE_VERSION = finalAttrs.version; + CYBERSTRIKE_CHANNEL = "local"; + }; + + buildPhase = '' + runHook preBuild + + cd ./packages/cyberstrike + bun --bun ./script/build.ts --single --skip-install + bun --bun ./script/schema.ts schema.json + + runHook postBuild + ''; + + installPhase = '' + runHook preInstall + + install -Dm755 dist/cyberstrike-*/bin/cyberstrike $out/bin/cyberstrike + install -Dm644 schema.json $out/share/cyberstrike/schema.json + + wrapProgram $out/bin/cyberstrike \ + --prefix PATH : ${ + lib.makeBinPath ( + [ + ripgrep + nodejs + ] + ++ lib.optional stdenvNoCC.hostPlatform.isDarwin sysctl + ) + } + + runHook postInstall + ''; + + postInstall = lib.optionalString (stdenvNoCC.buildPlatform.canExecute stdenvNoCC.hostPlatform) '' + installShellCompletion --cmd cyberstrike \ + --bash <($out/bin/cyberstrike completion) \ + --zsh <(SHELL=/bin/zsh $out/bin/cyberstrike completion) + ''; + + nativeInstallCheckInputs = [ + versionCheckHook + writableTmpDirAsHomeHook + ]; + + doInstallCheck = true; + + versionCheckKeepEnvironment = [ + "HOME" + "CYBERSTRIKE_DISABLE_MODELS_FETCH" + ]; + + versionCheckProgramArg = "--version"; + + passthru = { + jsonschema = { + config = "${placeholder "out"}/share/cyberstrike/schema.json"; + tui = "${placeholder "out"}/share/cyberstrike/tui.json"; + }; + updateScript = nix-update-script { + extraArgs = [ + "--subpackage" + "node_modules" + ]; + }; + }; + + meta = { + description = "AI-powered offensive security agent"; + homepage = "https://github.com/CyberStrikeus/CyberStrike"; + changelog = "https://github.com/CyberStrikeus/CyberStrike/blob/${finalAttrs.src.rev}/CHANGELOG.md"; + license = lib.licenses.agpl3Only; + maintainers = with lib.maintainers; [ fab ]; + mainProgram = "cyberstrike"; + }; +}) From 5fd4aa12e09f7eaf75ec6a9cdc997f9403647989 Mon Sep 17 00:00:00 2001 From: "R. Ryantm" Date: Thu, 2 Jul 2026 00:39:04 +0000 Subject: [PATCH 13/45] checkpolicy: 3.10 -> 3.11 --- pkgs/by-name/ch/checkpolicy/package.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkgs/by-name/ch/checkpolicy/package.nix b/pkgs/by-name/ch/checkpolicy/package.nix index b2d6a59daedf..9422f0807d29 100644 --- a/pkgs/by-name/ch/checkpolicy/package.nix +++ b/pkgs/by-name/ch/checkpolicy/package.nix @@ -9,12 +9,12 @@ stdenv.mkDerivation (finalAttrs: { pname = "checkpolicy"; - version = "3.10"; + version = "3.11"; inherit (libsepol) se_url; src = fetchurl { url = "${finalAttrs.se_url}/${finalAttrs.version}/checkpolicy-${finalAttrs.version}.tar.gz"; - hash = "sha256-LZKVHfywkNYXnnojhWYi4Py8Mr4Dvx5grOncnL2hHlk="; + hash = "sha256-m4G/zu9/qdAvmHLlanhvND3FjvS1cT3ODVxBbluEzvo="; }; nativeBuildInputs = [ From 46f01634b5b59bc74b3376ae09bc825f60d1068a Mon Sep 17 00:00:00 2001 From: Fabian Affolter Date: Thu, 2 Jul 2026 10:47:55 +0200 Subject: [PATCH 14/45] user-scanner: init at 1.4.1 Email & Username OSINT suite https://github.com/kaifcodec/user-scanner --- pkgs/by-name/us/user-scanner/package.nix | 49 ++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 pkgs/by-name/us/user-scanner/package.nix diff --git a/pkgs/by-name/us/user-scanner/package.nix b/pkgs/by-name/us/user-scanner/package.nix new file mode 100644 index 000000000000..c29183fae954 --- /dev/null +++ b/pkgs/by-name/us/user-scanner/package.nix @@ -0,0 +1,49 @@ +{ + lib, + fetchFromGitHub, + nix-update-script, + python3Packages, + versionCheckHook, +}: + +python3Packages.buildPythonApplication (finalAttrs: { + pname = "user-scanner"; + version = "1.4.1"; + pyproject = true; + + __structuredAttrs = true; + + src = fetchFromGitHub { + owner = "kaifcodec"; + repo = "user-scanner"; + tag = "v${finalAttrs.version}"; + hash = "sha256-SDi13KGqWXgNXdgF5KOpqEcjwbuNv4PU5ahB5UdsbWQ="; + }; + + build-system = with python3Packages; [ flit-core ]; + + dependencies = with python3Packages; [ + colorama + httpx + socksio + ]; + + nativeCheckInputs = with python3Packages; [ pytestCheckHook ]; + + nativeInstallCheckInputs = [ versionCheckHook ]; + + doInstallCheck = true; + + pythonImportsCheck = [ "user_scanner" ]; + + passthru.updateScript = nix-update-script { }; + + meta = { + description = "Email & Username OSINT suite"; + homepage = "https://github.com/kaifcodec/user-scanner"; + changelog = "https://github.com/kaifcodec/user-scanner/releases/tag/${finalAttrs.src.tag}"; + license = lib.licenses.mit; + maintainers = with lib.maintainers; [ fab ]; + mainProgram = "user-scanner"; + }; +}) From ad97f5573d6621d4861bfdcfbd433ca08e86a188 Mon Sep 17 00:00:00 2001 From: Johannes Kirschbauer Date: Thu, 2 Jul 2026 15:41:55 +0200 Subject: [PATCH 15/45] pkgs/nixos-render-docs: replace inlince tocs with collapsible sidebar tables of contents disconnect headings from body text. decouples heading levels from include type (part,chapter,part etc.) structure of the sidebar is derived from the include type for now. Can be changed to a meta file later. sidebar now uses proper ol-, li-, span-, a-tags definition tables are not ideal for navigation and accessibility breaking change: --toc-depth, --chunk-toc-depth, --section-toc-depth is now collapsed into --sidebar-depth --- doc/doc-support/package.nix | 3 +- doc/languages-frameworks/beam.section.md | 4 +- doc/style.css | 37 ++-- nixos/doc/manual/default.nix | 3 +- .../src/nixos_render_docs/html.py | 20 +-- .../src/nixos_render_docs/manual.py | 164 +++++++----------- .../src/tests/test_auto_id_prefix.py | 6 +- .../src/tests/test_manual.py | 116 +++++++++++++ .../src/tests/test_redirects.py | 2 +- 9 files changed, 210 insertions(+), 145 deletions(-) create mode 100644 pkgs/by-name/ni/nixos-render-docs/src/tests/test_manual.py diff --git a/doc/doc-support/package.nix b/doc/doc-support/package.nix index 3cc6daa32863..466beb204425 100644 --- a/doc/doc-support/package.nix +++ b/doc/doc-support/package.nix @@ -116,8 +116,7 @@ stdenvNoCC.mkDerivation ( --script ./highlightjs/loader.js \ --script ./anchor.min.js \ --script ./anchor-use.js \ - --toc-depth 1 \ - --section-toc-depth 1 \ + --sidebar-depth 3 \ manual.md \ out/index.html diff --git a/doc/languages-frameworks/beam.section.md b/doc/languages-frameworks/beam.section.md index 70ad1591be01..db4edaad4a4b 100644 --- a/doc/languages-frameworks/beam.section.md +++ b/doc/languages-frameworks/beam.section.md @@ -125,7 +125,7 @@ There are 2 ways to package backend dependencies: either per-dependency mix2nix When writing an elixir project targeting `mixRelease`, you can also consider using [deps_nix](https://github.com/code-supply/deps_nix) with `mixNixDeps`. `deps_nix` supports git dependencies, but is intended to be added to the project's `mix.exs` directly. -###### mix2nix {#mix2nix} +##### mix2nix {#mix2nix} `mix2nix` is a cli tool available in Nixpkgs. It will generate a Nix expression from a `mix.lock` file. It is quite standard in the 2nix tool series. @@ -175,7 +175,7 @@ If there are git dependencies. You will need to run the build process once to fix the hash to correspond to your new git src. -###### FOD {#fixed-output-derivation} +##### FOD {#fixed-output-derivation} A fixed output derivation will download mix dependencies from the internet. To ensure reproducibility, a hash will be supplied. Note that mix is relatively reproducible. An FOD generating a different hash on each run hasn't been observed (as opposed to npm where the chances are relatively high). See [akkoma](https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/ak/akkoma/package.nix) for a usage example of FOD. diff --git a/doc/style.css b/doc/style.css index c3c58e88637d..90517caf4948 100644 --- a/doc/style.css +++ b/doc/style.css @@ -387,15 +387,6 @@ div.appendix dt { margin-top: 1em; } -div.book .toc dt, -div.appendix .toc dt { - margin-top: 0; -} - -.list-of-examples dt { - margin-top: 0; -} - div.book code, div.appendix code { padding: 0; @@ -408,17 +399,6 @@ div.appendix code { hyphens: none; } -div.book div.toc, -div.appendix div.toc { - margin-bottom: 3em; - border-bottom: 0.0625rem solid #d8d8d8; -} - -div.book div.toc dd, -div.appendix div.toc dd { - margin-left: 2em; -} - div.book span.command, div.appendix span.command { font-family: monospace; @@ -515,12 +495,23 @@ nav.toc-sidebar .toc { margin-bottom: 0; } -nav.toc-sidebar .toc dl { +nav.toc-sidebar ol.toc, +nav.toc-sidebar ol.toc ol { + list-style: none; + margin: 0; + padding-left: 0; +} + +nav.toc-sidebar ol.toc ol { + padding-left: 1em; +} + +nav.toc-sidebar li { margin: 0; } -nav.toc-sidebar .toc dd { - margin-left: 1em; +nav.toc-sidebar summary { + cursor: pointer; } @media screen and (min-width: 768px) { diff --git a/nixos/doc/manual/default.nix b/nixos/doc/manual/default.nix index c8afe6167a7d..cf5c28358097 100644 --- a/nixos/doc/manual/default.nix +++ b/nixos/doc/manual/default.nix @@ -201,8 +201,7 @@ rec { --script ./highlightjs/loader.js \ --script ./anchor.min.js \ --script ./anchor-use.js \ - --toc-depth 1 \ - --chunk-toc-depth 1 \ + --sidebar-depth 2 \ ./manual.md \ $dst/${common.indexPath} diff --git a/pkgs/by-name/ni/nixos-render-docs/src/nixos_render_docs/html.py b/pkgs/by-name/ni/nixos-render-docs/src/nixos_render_docs/html.py index 3e4ff1aedb7a..5944431d4680 100644 --- a/pkgs/by-name/ni/nixos-render-docs/src/nixos_render_docs/html.py +++ b/pkgs/by-name/ni/nixos-render-docs/src/nixos_render_docs/html.py @@ -1,12 +1,13 @@ from collections.abc import Mapping, Sequence -from typing import cast, Optional, NamedTuple - from html import escape +from typing import NamedTuple, Optional, cast + from markdown_it.token import Token from .manual_structure import XrefTarget from .md import Renderer + class UnresolvedXrefError(Exception): pass @@ -17,9 +18,6 @@ class Heading(NamedTuple): # special handling for part content: whether partinfo div was already closed from # elsewhere or still needs closing. partintro_closed: bool - # tocs are generated when the heading opens, but have to be emitted into the file - # after the heading titlepage (and maybe partinfo) has been closed. - toc_fragment: str _bullet_list_styles = [ 'disc', 'circle', 'square' ] _ordered_list_styles = [ '1', 'a', 'i', 'A', 'I' ] @@ -29,7 +27,6 @@ class HTMLRenderer(Renderer): _headings: list[Heading] _attrspans: list[str] - _hlevel_offset: int = 0 _bullet_list_nesting: int = 0 _ordered_list_nesting: int = 0 @@ -185,8 +182,7 @@ class HTMLRenderer(Renderer): anchor = f'id="{escape(anchor, True)}"' result = self._close_headings(hlevel) tag = self._heading_tag(token, tokens, i) - toc_fragment = self._build_toc(tokens, i) - self._headings.append(Heading(tag, hlevel, htag, tag != 'part', toc_fragment)) + self._headings.append(Heading(tag, hlevel, htag, tag != 'part')) return ( f'{result}' f'
' @@ -205,8 +201,6 @@ class HTMLRenderer(Renderer): ) if heading.container_tag == 'part': result += '
' - else: - result += heading.toc_fragment return result def ordered_list_open(self, token: Token, tokens: Sequence[Token], i: int) -> str: extra = 'compact' if token.meta.get('compact', False) else '' @@ -329,14 +323,14 @@ class HTMLRenderer(Renderer): ) def _make_hN(self, level: int) -> tuple[str, str]: - return f"h{min(6, max(1, level + self._hlevel_offset))}", "" + return f"h{min(6, max(1, level))}", "" def _maybe_close_partintro(self) -> str: if self._headings: heading = self._headings[-1] if heading.container_tag == 'part' and not heading.partintro_closed: self._headings[-1] = heading._replace(partintro_closed=True) - return heading.toc_fragment + "
" + return "
" return "" def _close_headings(self, level: Optional[int]) -> str: @@ -349,5 +343,3 @@ class HTMLRenderer(Renderer): def _heading_tag(self, token: Token, tokens: Sequence[Token], i: int) -> str: return "section" - def _build_toc(self, tokens: Sequence[Token], i: int) -> str: - return "" diff --git a/pkgs/by-name/ni/nixos-render-docs/src/nixos_render_docs/manual.py b/pkgs/by-name/ni/nixos-render-docs/src/nixos_render_docs/manual.py index 9208148c594b..902b365d8b5f 100644 --- a/pkgs/by-name/ni/nixos-render-docs/src/nixos_render_docs/manual.py +++ b/pkgs/by-name/ni/nixos-render-docs/src/nixos_render_docs/manual.py @@ -4,21 +4,29 @@ import html import json import re import xml.sax.saxutils as xml - from abc import abstractmethod from collections.abc import Mapping, Sequence from pathlib import Path -from typing import Any, Callable, cast, ClassVar, Generic, get_args, NamedTuple +from typing import Any, Callable, ClassVar, Generic, NamedTuple, cast, get_args from markdown_it.token import Token from . import md, options from .html import HTMLRenderer, UnresolvedXrefError -from .manual_structure import check_structure, FragmentType, is_include, make_xml_id, TocEntry, TocEntryType, XrefTarget +from .manual_structure import ( + FragmentType, + TocEntry, + TocEntryType, + XrefTarget, + check_structure, + is_include, + make_xml_id, +) from .md import Converter, Renderer from .redirects import Redirects from .src_error import SrcError + class BaseConverter(Converter[md.TR], Generic[md.TR]): # per-converter configuration for ns:arg=value arguments to include blocks, following # the include type. html converters need something like this to support chunking, or @@ -253,12 +261,8 @@ class HTMLParameters(NamedTuple): generator: str stylesheets: Sequence[str] scripts: Sequence[str] - # number of levels in the rendered table of contents. tables are prepended to - # the content they apply to (entire document / document chunk / top-level section - # of a chapter), setting a depth of 0 omits the respective table. - toc_depth: int - chunk_toc_depth: int - section_toc_depth: int + # structural depth of the navigation sidebar tree + sidebar_depth: int media_dir: Path class ManualHTMLRenderer(RendererMixin, HTMLRenderer): @@ -289,14 +293,13 @@ class ManualHTMLRenderer(RendererMixin, HTMLRenderer): target_path.write_bytes(content) return f"./{self._html_params.media_dir}/{target_name}" - def _push(self, tag: str, hlevel_offset: int) -> Any: - result = (self._toplevel_tag, self._headings, self._attrspans, self._hlevel_offset, self._in_dir) - self._hlevel_offset += hlevel_offset + def _push(self, tag: str) -> Any: + result = (self._toplevel_tag, self._headings, self._attrspans, self._in_dir) self._toplevel_tag, self._headings, self._attrspans = tag, [], [] return result def _pop(self, state: Any) -> None: - (self._toplevel_tag, self._headings, self._attrspans, self._hlevel_offset, self._in_dir) = state + (self._toplevel_tag, self._headings, self._attrspans, self._in_dir) = state def _render_book(self, tokens: Sequence[Token]) -> str: assert tokens[4].children @@ -307,7 +310,7 @@ class ManualHTMLRenderer(RendererMixin, HTMLRenderer): toc = TocEntry.of(tokens[0]) return "\n".join([ - self._file_header(toc, sidebar=self._build_toc(tokens, 0)), + self._file_header(toc, sidebar=self._build_sidebar(toc)), '
', '
', '
', @@ -434,103 +437,60 @@ class ManualHTMLRenderer(RendererMixin, HTMLRenderer): if token.tag == 'h1': return self._toplevel_tag return super()._heading_tag(token, tokens, i) - def _build_toc(self, tokens: Sequence[Token], i: int) -> str: - toc = TocEntry.of(tokens[i]) - if toc.kind == 'section' and self._html_params.section_toc_depth < 1: - return "" - def walk_and_emit(toc: TocEntry, depth: int) -> list[str]: - if depth <= 0: - return [] - result = [] - for child in toc.children: - result.append( - f'
' - f' ' - f' {child.target.toc_html}' - f' ' - f'
' - ) - # we want to look straight through parts because docbook-xsl did too, but it - # also makes for more uesful top-level tocs. - next_level = walk_and_emit(child, depth - (0 if child.kind == 'part' else 1)) - if next_level: - result.append(f'
{"".join(next_level)}
') - return result + def _build_sidebar(self, toc: TocEntry) -> str: + root = toc.root + def render_entries(entries: Sequence[TocEntry], budget: int) -> str: + items: list[str] = [] + for e in entries: + # 'part' are structural containers we look straight through, so + # they do not consume a depth level + child_budget = budget if e.kind == 'part' else budget - 1 + children = (render_entries(e.children, child_budget) + if e.children and child_budget > 0 else "") + link = f'{e.target.toc_html}' + cls = html.escape(e.kind, True) + if children: + items.append( + f'
  • ' + f'
    {link}{children}
    ' + '
  • ' + ) + else: + items.append(f'
  • {link}
  • ') + return f'
      {"".join(items)}
    ' if items else "" def build_list(kind: str, id: str, lst: Sequence[TocEntry]) -> str: if not lst: return "" - entries = [ - f'
    {i}. {e.target.toc_html}
    ' - for i, e in enumerate(lst, start=1) - ] + entries = "".join( + f'
  • {e.target.toc_html}
  • ' + for e in lst + ) return ( f'
    ' f'

    List of {kind}

    ' - f'
    {"".join(entries)}
    ' + f'
      {entries}
    ' '
    ' ) - # we don't want to generate the "Title of Contents" header for sections, - # docbook didn't and it's only distracting clutter unless it's the main table. - # we also want to generate tocs only for a top-level section (ie, one that is - # not itself contained in another section) - print_title = toc.kind != 'section' - if toc.kind == 'section': - if toc.parent and toc.parent.kind == 'section': - toc_depth = 0 - else: - toc_depth = self._html_params.section_toc_depth - elif toc.starts_new_chunk and toc.kind != 'book': - toc_depth = self._html_params.chunk_toc_depth - else: - toc_depth = self._html_params.toc_depth - if not (items := walk_and_emit(toc, toc_depth)): - return "" - figures = build_list("Figures", "list-of-figures", toc.figures) - examples = build_list("Examples", "list-of-examples", toc.examples) - return "".join([ - f'
    ', - '

    Table of Contents

    ' if print_title else "", - f'
    ' - f' {"".join(items)}' - f'
    ' - f'
    ' - f'{figures}' - f'{examples}' - ]) + nav = render_entries(root.children, self._html_params.sidebar_depth) + figures = build_list("Figures", "list-of-figures", root.figures) + examples = build_list("Examples", "list-of-examples", root.examples) + return f'{nav}{figures}{examples}' def _make_hN(self, level: int) -> tuple[str, str]: - # for some reason chapters didn't increase the hN nesting count in docbook xslts. - # originally this was duplicated here for consistency with docbook rendering, but - # it could be reevaluated and changed now that docbook is gone. - if self._toplevel_tag == 'chapter': - level -= 1 - # this style setting is also for docbook compatibility only and could well go away. - style = "" - if level + self._hlevel_offset < 3 \ - and (self._toplevel_tag == 'section' or (self._toplevel_tag == 'chapter' and level > 0)): - style = "clear: both" - tag, hstyle = super()._make_hN(max(1, level)) - return tag, style + # book heading := h1 + # Everything else is h2 ... h6 + return super()._make_hN(level + 1) def _included_thing(self, tag: str, token: Token, tokens: Sequence[Token], i: int) -> str: outer, inner = [], [] - # since books have no non-include content the toplevel book wrapper will not count - # towards nesting depth. other types will have at least a title+id heading which - # *does* count towards the nesting depth. chapters give a -1 to included sections - # mirroring the special handing in _make_hN. sigh. - hoffset = ( - 0 if not self._headings - else self._headings[-1].level - 1 if self._toplevel_tag == 'chapter' - else self._headings[-1].level - ) outer.append(self._maybe_close_partintro()) into = token.meta['include-args'].get('into-file') fragments = token.meta['included'] - state = self._push(tag, hoffset) + state = self._push(tag) if into: toc = TocEntry.of(fragments[0][0][0]) - inner.append(self._file_header(toc)) - # we do not set _hlevel_offset=0 because docbook didn't either. + # chunk pages carry the same whole-book sidebar as the main page. + inner.append(self._file_header(toc, sidebar=self._build_sidebar(toc))) else: inner = outer in_dir = self._in_dir @@ -755,17 +715,25 @@ class HTMLConverter(BaseConverter[ManualHTMLRenderer]): server_redirects_file.write("\n".join(formatted_server_redirects)) +class _DeprecatedDepthFlag(argparse.Action): + def __call__(self, parser: argparse.ArgumentParser, namespace: argparse.Namespace, + values: Any, option_string: str | None = None) -> None: + parser.error(f"{option_string} has been removed, use --sidebar-depth instead") + def _build_cli_html(p: argparse.ArgumentParser) -> None: p.add_argument('--manpage-urls', required=True) p.add_argument('--revision', required=True) p.add_argument('--generator', default='nixos-render-docs') p.add_argument('--stylesheet', default=[], action='append') p.add_argument('--script', default=[], action='append') - p.add_argument('--toc-depth', default=1, type=int) - p.add_argument('--chunk-toc-depth', default=1, type=int) - p.add_argument('--section-toc-depth', default=0, type=int) p.add_argument('--media-dir', default="media", type=Path) p.add_argument('--redirects', type=Path) + p.add_argument('--sidebar-depth', default=2, type=int) + # Deprecated flags, + p.add_argument('--toc-depth', nargs='?', action=_DeprecatedDepthFlag, default=None) + p.add_argument('--chunk-toc-depth', nargs='?', action=_DeprecatedDepthFlag, default=None) + p.add_argument('--section-toc-depth', nargs='?', action=_DeprecatedDepthFlag, default=None) + # Positional p.add_argument('infile', type=Path) p.add_argument('outfile', type=Path) @@ -778,8 +746,8 @@ def _run_cli_html(args: argparse.Namespace) -> None: md = HTMLConverter( args.revision, - HTMLParameters(args.generator, args.stylesheet, args.script, args.toc_depth, - args.chunk_toc_depth, args.section_toc_depth, args.media_dir), + HTMLParameters(args.generator, args.stylesheet, args.script, + args.sidebar_depth, args.media_dir), json.load(manpage_urls), redirects) md.convert(args.infile, args.outfile) diff --git a/pkgs/by-name/ni/nixos-render-docs/src/tests/test_auto_id_prefix.py b/pkgs/by-name/ni/nixos-render-docs/src/tests/test_auto_id_prefix.py index 6fb706bad5ac..fce017fc70ba 100644 --- a/pkgs/by-name/ni/nixos-render-docs/src/tests/test_auto_id_prefix.py +++ b/pkgs/by-name/ni/nixos-render-docs/src/tests/test_auto_id_prefix.py @@ -10,7 +10,7 @@ def set_prefix(token: Token, ident: str) -> None: def test_auto_id_prefix_simple() -> None: - md = HTMLConverter("1.0.0", HTMLParameters("", [], [], 2, 2, 2, Path("")), {}) + md = HTMLConverter("1.0.0", HTMLParameters("", [], [], 2, Path("")), {}) src = f""" # title @@ -31,7 +31,7 @@ def test_auto_id_prefix_simple() -> None: def test_auto_id_prefix_repeated() -> None: - md = HTMLConverter("1.0.0", HTMLParameters("", [], [], 2, 2, 2, Path("")), {}) + md = HTMLConverter("1.0.0", HTMLParameters("", [], [], 2, Path("")), {}) src = f""" # title @@ -57,7 +57,7 @@ def test_auto_id_prefix_repeated() -> None: ] def test_auto_id_prefix_maximum_nested() -> None: - md = HTMLConverter("1.0.0", HTMLParameters("", [], [], 2, 2, 2, Path("")), {}) + md = HTMLConverter("1.0.0", HTMLParameters("", [], [], 2, Path("")), {}) src = f""" # h1 diff --git a/pkgs/by-name/ni/nixos-render-docs/src/tests/test_manual.py b/pkgs/by-name/ni/nixos-render-docs/src/tests/test_manual.py new file mode 100644 index 000000000000..339bf58b2462 --- /dev/null +++ b/pkgs/by-name/ni/nixos-render-docs/src/tests/test_manual.py @@ -0,0 +1,116 @@ +from pathlib import Path + +from nixos_render_docs.manual import HTMLConverter, HTMLParameters + + +def _build(tmp_path: Path, sidebar_depth: int = 2) -> str: + (tmp_path / "part.md").write_text( + "# Build helpers {#part-builders}\n\n" # -> h2 + "```{=include=} chapters\nchapter.md\n```\n" + ) + (tmp_path / "chapter.md").write_text( + "# Fixed-point arguments {#chap-fpa}\n\n" # -> h2 + "Intro.\n\n" + "## First section {#sec-first}\n\n" # -> h3 + "Body.\n\n" + "### A subsection {#sub-a}\n\n" + "Deep.\n\n" + "#### Deeper {#d4}\n\n" + "More.\n\n" + "##### Deepest {#d5}\n\n" + "Most.\n" + ) + (tmp_path / "index.md").write_text( + "# Test manual {#book-test}\n\n" # -> h1 (book title) + "## Version 1\n\n" # -> h2 + "```{=include=} parts\npart.md\n```\n" + ) + out = tmp_path / "out" + out.mkdir(exist_ok=True) + conv = HTMLConverter( + "1.0.0", + HTMLParameters("test-gen", [], [], sidebar_depth, Path("media")), + {}, + ) + conv.convert(tmp_path / "index.md", out / "index.html") + return (out / "index.html").read_text() + + +def test_single_h1_and_flat_heading_levels(tmp_path: Path) -> None: + html = _build(tmp_path) + # There should be only one h1 on an html for acessibility and semantic reasons + assert html.count("' in html + assert '

    None: + html = _build(tmp_path) + assert '