diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index c0a31e826ac04..f079fba5eaac3 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -109,8 +109,15 @@ fb0e5be84331188a69b3edd31679ca6576edb75a # postgresql: move packages.nix to ext/default.nix 719034f6f6749d624faa28dff259309fc0e3e730 +# php ecosystem: reformat with nixfmt-rfc-style +75ae7621330ff8db944ce4dff4374e182d5d151f +c759efa5e7f825913f9a69ef20f025f50f56dc4d + # pkgs/os-specific/bsd: Reformat with nixfmt-rfc-style 2024-03-01 3fe3b055adfc020e6a923c466b6bcd978a13069a # k3s: format with nixfmt-rfc-style 6cfcd3c75428ede517bc6b15a353d704837a2830 + +# python3Packages: format with nixfmt +59b1aef59071cae6e87859dc65de973d2cc595c0 diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 47d5d399f1983..8adb04ecbf5a0 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -67,8 +67,8 @@ /nixos/lib/make-disk-image.nix @raitobezarius # Nix, the package manager -pkgs/tools/package-management/nix/ @raitobezarius @ma27 -nixos/modules/installer/tools/nix-fallback-paths.nix @raitobezarius @ma27 +pkgs/tools/package-management/nix/ @raitobezarius +nixos/modules/installer/tools/nix-fallback-paths.nix @raitobezarius # Nixpkgs documentation /maintainers/scripts/db-to-md.sh @jtojnar @ryantm @@ -306,8 +306,8 @@ nixos/modules/services/networking/networkmanager.nix @Janik-Haag /pkgs/applications/networking/cluster/terraform-providers @zowoq # Forgejo -nixos/modules/services/misc/forgejo.nix @bendlas @emilylange -pkgs/applications/version-management/forgejo @bendlas @emilylange +nixos/modules/services/misc/forgejo.nix @adamcstephens @bendlas @emilylange +pkgs/by-name/fo/forgejo/package.nix @adamcstephens @bendlas @emilylange # Dotnet /pkgs/build-support/dotnet @IvarWithoutBones diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 7b68fbd77b74b..15741f57e6f4c 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -24,7 +24,7 @@ For new packages please briefly describe the package or provide a link to its ho - made sure NixOS tests are [linked](https://nixos.org/manual/nixpkgs/unstable/#ssec-nixos-tests-linking) to the relevant packages - [ ] Tested compilation of all packages that depend on this change using `nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD"`. Note: all changes have to be committed, also see [nixpkgs-review usage](https://github.com/Mic92/nixpkgs-review#usage) - [ ] Tested basic functionality of all binary files (usually in `./result/bin/`) -- [24.05 Release Notes](https://github.com/NixOS/nixpkgs/blob/master/nixos/doc/manual/release-notes/rl-2405.section.md) (or backporting [23.05](https://github.com/NixOS/nixpkgs/blob/master/nixos/doc/manual/release-notes/rl-2305.section.md) and [23.11](https://github.com/NixOS/nixpkgs/blob/master/nixos/doc/manual/release-notes/rl-2311.section.md) Release notes) +- [24.11 Release Notes](https://github.com/NixOS/nixpkgs/blob/master/nixos/doc/manual/release-notes/rl-2411.section.md) (or backporting [23.11](https://github.com/NixOS/nixpkgs/blob/master/nixos/doc/manual/release-notes/rl-2311.section.md) and [24.05](https://github.com/NixOS/nixpkgs/blob/master/nixos/doc/manual/release-notes/rl-2405.section.md) Release notes) - [ ] (Package updates) Added a release notes entry if the change is major or breaking - [ ] (Module updates) Added a release notes entry if the change is significant - [ ] (Module addition) Added a release notes entry if adding a new NixOS module diff --git a/.github/labeler.yml b/.github/labeler.yml index 57086953f8d03..90c25048299e8 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -16,6 +16,17 @@ - nixos/modules/services/x11/desktop-managers/cinnamon.nix - nixos/tests/cinnamon.nix +"6.topic: dotnet": + - any: + - changed-files: + - any-glob-to-any-file: + - doc/languages-frameworks/dotnet.section.md + - maintainers/scripts/update-dotnet-lockfiles.nix + - pkgs/build-support/dotnet/**/* + - pkgs/development/compilers/dotnet/**/* + - pkgs/test/dotnet/**/* + - pkgs/top-level/dotnet-packages.nix + "6.topic: emacs": - any: - changed-files: @@ -134,6 +145,12 @@ - any-glob-to-any-file: - lib/** +"6.topic: llvm/clang": + - any: + - changed-files: + - any-glob-to-any-file: + - pkgs/development/compilers/llvm/* + "6.topic: lua": - any: - changed-files: @@ -201,6 +218,7 @@ - pkgs/development/node-packages/**/* - pkgs/development/tools/yarn/* - pkgs/development/tools/yarn2nix-moretea/**/* + - pkgs/development/tools/pnpm/**/* - pkgs/development/web/nodejs/* "6.topic: ocaml": diff --git a/.github/workflows/basic-eval.yml b/.github/workflows/basic-eval.yml index 1f787397f2611..a5ada7a6e210f 100644 --- a/.github/workflows/basic-eval.yml +++ b/.github/workflows/basic-eval.yml @@ -20,7 +20,7 @@ jobs: steps: - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5 - uses: cachix/install-nix-action@8887e596b4ee1134dae06b98d573bd674693f47c # v26 - - uses: cachix/cachix-action@18cf96c7c98e048e10a83abd92116114cd8504be # v14 + - uses: cachix/cachix-action@ad2ddac53f961de1989924296a1f236fcfbaa4fc # v15 with: # This cache is for the nixpkgs repo checks and should not be trusted or used elsewhere. name: nixpkgs-ci diff --git a/.github/workflows/check-by-name.yml b/.github/workflows/check-by-name.yml index e857c88f746d3..ce7802f4aa8ee 100644 --- a/.github/workflows/check-by-name.yml +++ b/.github/workflows/check-by-name.yml @@ -14,16 +14,16 @@ on: # While `edited` is also triggered when the PR title/body is changed, # this PR action is fairly quick, and PR's don't get edited that often, # so it shouldn't be a problem + # There is a feature request for adding a `base_changed` event: + # https://github.com/orgs/community/discussions/35058 types: [opened, synchronize, reopened, edited] permissions: {} -# Create a check-by-name concurrency group based on the pull request number. if -# an event triggers a run on the same PR while a previous run is still in -# progress, the previous run will be canceled and the new one will start. -concurrency: - group: check-by-name-${{ github.event.pull_request.number }} - cancel-in-progress: true +# We don't use a concurrency group here, because the action is triggered quite often (due to the PR edit +# trigger), and contributers would get notified on any canceled run. +# There is a feature request for supressing notifications on concurrency-canceled runs: +# https://github.com/orgs/community/discussions/13015 jobs: check: diff --git a/.github/workflows/check-cherry-picks.yml b/.github/workflows/check-cherry-picks.yml index 0bee949c3dbc4..67a5506bcc199 100644 --- a/.github/workflows/check-cherry-picks.yml +++ b/.github/workflows/check-cherry-picks.yml @@ -4,6 +4,7 @@ on: branches: - 'release-**' - 'staging-**' + - '!staging-next' permissions: {} diff --git a/.github/workflows/manual-nixos.yml b/.github/workflows/manual-nixos.yml index a72b1adfeac03..f841fcadc5005 100644 --- a/.github/workflows/manual-nixos.yml +++ b/.github/workflows/manual-nixos.yml @@ -22,7 +22,7 @@ jobs: with: # explicitly enable sandbox extra_nix_config: sandbox = true - - uses: cachix/cachix-action@18cf96c7c98e048e10a83abd92116114cd8504be # v14 + - uses: cachix/cachix-action@ad2ddac53f961de1989924296a1f236fcfbaa4fc # v15 with: # This cache is for the nixpkgs repo checks and should not be trusted or used elsewhere. name: nixpkgs-ci diff --git a/.github/workflows/manual-nixpkgs.yml b/.github/workflows/manual-nixpkgs.yml index 52aefa8472ed2..7b2cef0e108b5 100644 --- a/.github/workflows/manual-nixpkgs.yml +++ b/.github/workflows/manual-nixpkgs.yml @@ -24,7 +24,7 @@ jobs: with: # explicitly enable sandbox extra_nix_config: sandbox = true - - uses: cachix/cachix-action@18cf96c7c98e048e10a83abd92116114cd8504be # v14 + - uses: cachix/cachix-action@ad2ddac53f961de1989924296a1f236fcfbaa4fc # v15 with: # This cache is for the nixpkgs repo checks and should not be trusted or used elsewhere. name: nixpkgs-ci diff --git a/.github/workflows/periodic-merge-24h.yml b/.github/workflows/periodic-merge-24h.yml index 7001dccb0d5db..261a2cdba45dc 100644 --- a/.github/workflows/periodic-merge-24h.yml +++ b/.github/workflows/periodic-merge-24h.yml @@ -39,6 +39,10 @@ jobs: into: staging-next-23.11 - from: staging-next-23.11 into: staging-23.11 + - from: release-24.05 + into: staging-next-24.05 + - from: staging-next-24.05 + into: staging-24.05 name: ${{ matrix.pairs.from }} → ${{ matrix.pairs.into }} steps: - uses: actions/checkout@44c2b7a8a4ea60a981eaca3cf939b5f4305c123b # v4.1.5 diff --git a/.mailmap b/.mailmap index ba9bcefb55e1c..ce432f161b878 100644 --- a/.mailmap +++ b/.mailmap @@ -10,6 +10,7 @@ Robert Hensing Sandro Jäckel Sandro Jäckel superherointj <5861043+superherointj@users.noreply.github.com> +Tomodachi94 Tomo <68489118+Tomodachi94@users.noreply.github.com> Vladimír Čunát Vladimír Čunát Yifei Sun StepBroBD diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f40fb86ee5595..23a826d9a7b7e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -330,7 +330,14 @@ Container system, boot system and library changes are some examples of the pull ## How to merge pull requests [pr-merge]: #how-to-merge-pull-requests -The *Nixpkgs committers* are people who have been given +To streamline automated updates, leverage the nixpkgs-merge-bot by simply commenting `@NixOS/nixpkgs-merge-bot merge`. The bot will verify if the following conditions are met, refusing to merge otherwise: + +- the commenter that issued the command should be among the package maintainers; +- the package should reside in `pkgs/by-name`. + +Further, nixpkgs-merge-bot will ensure all ofBorg checks (except the Darwin-related ones) are successfully completed before merging the pull request. Should the checks still be underway, the bot patiently waits for ofBorg to finish before attempting the merge again. + +For other pull requests, the *Nixpkgs committers* are people who have been given permission to merge. It is possible for community members that have enough knowledge and experience on a special topic to contribute by merging pull requests. @@ -359,7 +366,7 @@ See [Nix Channel Status](https://status.nixos.org/) for the current channels and Here's a brief overview of the main Git branches and what channels they're used for: - `master`: The main branch, used for the unstable channels such as `nixpkgs-unstable`, `nixos-unstable` and `nixos-unstable-small`. -- `release-YY.MM` (e.g. `release-23.11`): The NixOS release branches, used for the stable channels such as `nixos-23.11`, `nixos-23.11-small` and `nixpkgs-23.11-darwin`. +- `release-YY.MM` (e.g. `release-24.05`): The NixOS release branches, used for the stable channels such as `nixos-24.05`, `nixos-24.05-small` and `nixpkgs-24.05-darwin`. When a channel is updated, a corresponding Git branch is also updated to point to the corresponding commit. So e.g. the [`nixpkgs-unstable` branch](https://github.com/nixos/nixpkgs/tree/nixpkgs-unstable) corresponds to the Git commit from the [`nixpkgs-unstable` channel](https://channels.nixos.org/nixpkgs-unstable). diff --git a/README.md b/README.md index 5e6a8c54832b3..8b16318bfc685 100644 --- a/README.md +++ b/README.md @@ -52,9 +52,9 @@ Nixpkgs and NixOS are built and tested by our continuous integration system, [Hydra](https://hydra.nixos.org/). * [Continuous package builds for unstable/master](https://hydra.nixos.org/jobset/nixos/trunk-combined) -* [Continuous package builds for the NixOS 23.11 release](https://hydra.nixos.org/jobset/nixos/release-23.11) +* [Continuous package builds for the NixOS 24.05 release](https://hydra.nixos.org/jobset/nixos/release-24.05) * [Tests for unstable/master](https://hydra.nixos.org/job/nixos/trunk-combined/tested#tabs-constituents) -* [Tests for the NixOS 23.11 release](https://hydra.nixos.org/job/nixos/release-23.11/tested#tabs-constituents) +* [Tests for the NixOS 24.05 release](https://hydra.nixos.org/job/nixos/release-24.05/tested#tabs-constituents) Artifacts successfully built with Hydra are published to cache at https://cache.nixos.org/. When successful build and test criteria are diff --git a/doc/build-helpers/fetchers.chapter.md b/doc/build-helpers/fetchers.chapter.md index cb37dca06d487..0cc271f5db8c4 100644 --- a/doc/build-helpers/fetchers.chapter.md +++ b/doc/build-helpers/fetchers.chapter.md @@ -365,8 +365,8 @@ If `pname` and `version` are specified, `fetchurl` will use those values and wil _Default value:_ `{}`. `passthru` (Attribute Set; _optional_) -: Specifies any extra [passthru](#var-stdenv-passthru) attributes for the derivation returned by `fetchurl`. - Note that `fetchurl` defines [passthru attributes of its own](#ssec-pkgs-fetchers-fetchurl-passthru-outputs). +: Specifies any extra [`passthru`](#chap-passthru) attributes for the derivation returned by `fetchurl`. + Note that `fetchurl` defines [`passthru` attributes of its own](#ssec-pkgs-fetchers-fetchurl-passthru-outputs). Attributes specified in `passthru` can override the default attributes returned by `fetchurl`. _Default value:_ `{}`. @@ -387,7 +387,7 @@ If `pname` and `version` are specified, `fetchurl` will use those values and wil ### Passthru outputs {#ssec-pkgs-fetchers-fetchurl-passthru-outputs} -`fetchurl` also defines its own [`passthru`](#var-stdenv-passthru) attributes: +`fetchurl` also defines its own [`passthru`](#chap-passthru) attributes: `url` (String) diff --git a/doc/build-helpers/images/dockertools.section.md b/doc/build-helpers/images/dockertools.section.md index 527e623e78987..aeb831c770c59 100644 --- a/doc/build-helpers/images/dockertools.section.md +++ b/doc/build-helpers/images/dockertools.section.md @@ -191,7 +191,7 @@ Similarly, if you encounter errors similar to `Error_Protocol ("certificate has ### Passthru outputs {#ssec-pkgs-dockerTools-buildImage-passthru-outputs} -`buildImage` defines a few [`passthru`](#var-stdenv-passthru) attributes: +`buildImage` defines a few [`passthru`](#chap-passthru) attributes: `buildArgs` (Attribute Set) @@ -576,13 +576,13 @@ This allows the function to produce reproducible images. `passthru` (Attribute Set; _optional_) -: Use this to pass any attributes as [passthru](#var-stdenv-passthru) for the resulting derivation. +: Use this to pass any attributes as [`passthru`](#chap-passthru) for the resulting derivation. _Default value:_ `{}` ### Passthru outputs {#ssec-pkgs-dockerTools-streamLayeredImage-passthru-outputs} -`streamLayeredImage` also defines its own [`passthru`](#var-stdenv-passthru) attributes: +`streamLayeredImage` also defines its own [`passthru`](#chap-passthru) attributes: `imageTag` (String) diff --git a/doc/build-helpers/images/makediskimage.section.md b/doc/build-helpers/images/makediskimage.section.md index e50479c4e83e4..3edfa906aa6ae 100644 --- a/doc/build-helpers/images/makediskimage.section.md +++ b/doc/build-helpers/images/makediskimage.section.md @@ -85,14 +85,14 @@ let in make-disk-image { inherit pkgs lib; - config = evalConfig { + inherit (evalConfig { modules = [ { fileSystems."/" = { device = "/dev/vda"; fsType = "ext4"; autoFormat = true; }; boot.grub.device = "/dev/vda"; } ]; - }; + }) config; format = "qcow2"; onlyNixStore = false; partitionTableType = "legacy+gpt"; @@ -104,5 +104,3 @@ in memSize = 2048; # Qemu VM memory size in megabytes. Defaults to 1024M. } ``` - - diff --git a/doc/build-helpers/testers.chapter.md b/doc/build-helpers/testers.chapter.md index b734cbbbd4e29..34cfc00a4953c 100644 --- a/doc/build-helpers/testers.chapter.md +++ b/doc/build-helpers/testers.chapter.md @@ -40,6 +40,82 @@ If the `moduleNames` argument is omitted, `hasPkgConfigModules` will use `meta.p ::: +## `lycheeLinkCheck` {#tester-lycheeLinkCheck} + +Check a packaged static site's links with the [`lychee` package](https://search.nixos.org/packages?show=lychee&type=packages&query=lychee). + +You may use Nix to reproducibly build static websites, such as for software documentation. +Some packages will install documentation in their `out` or `doc` outputs, or maybe you have dedicated package where you've made your static site reproducible by running a generator, such as [Hugo](https://gohugo.io/) or [mdBook](https://rust-lang.github.io/mdBook/), in a derivation. + +If you have a static site that can be built with Nix, you can use `lycheeLinkCheck` to check that the hyperlinks in your site are correct, and do so as part of your Nix workflow and CI. + +:::{.example #ex-lycheelinkcheck} + +# Check hyperlinks in the `nix` documentation + +```nix +testers.lycheeLinkCheck { + site = nix.doc + "/share/doc/nix/manual"; +} +``` + +::: + +### Return value {#tester-lycheeLinkCheck-return} + +This tester produces a package that does not produce useful outputs, but only succeeds if the hyperlinks in your site are correct. The build log will list the broken links. + +It has two modes: + +- Build the returned derivation; its build process will check that internal hyperlinks are correct. This runs in the sandbox, so it will not check external hyperlinks, but it is quick and reliable. + +- Invoke the `.online` attribute with [`nix run`](https://nixos.org/manual/nix/stable/command-ref/new-cli/nix3-run) ([experimental](https://nixos.org/manual/nix/stable/contributing/experimental-features#xp-feature-nix-command)). This runs outside the sandbox, and checks that both internal and external hyperlinks are correct. + Example: + + ```shell + nix run nixpkgs#lychee.tests.ok.online + ``` + +### Inputs {#tester-lycheeLinkCheck-inputs} + +`site` (path or derivation) {#tester-lycheeLinkCheck-param-site} + +: The path to the files to check. + +`remap` (attribe set, optional) {#tester-lycheeLinkCheck-param-remap} + +: An attribute set where the attribute names are regular expressions. + The values should be strings, derivations, or path values. + + In the returned check's default configuration, external URLs are only checked when you run the `.online` attribute. + + By adding remappings, you can check offline that URLs to external resources are correct, by providing a stand-in from the file system. + + Before checking the existence of a URL, the regular expressions are matched and replaced by their corresponding values. + + Example: + + ```nix + { + "https://nix\\.dev/manual/nix/[a-z0-9.-]*" = "${nix.doc}/share/doc/nix/manual"; + "https://nixos\\.org/manual/nix/(un)?stable" = "${emptyDirectory}/placeholder-to-disallow-old-nix-docs-urls"; + } + ``` + + Store paths in the attribute values are automatically prefixed with `file://`, because lychee requires this for paths in the file system. + If this is a problem, or if you need to control the order in which replacements are performed, use `extraConfig.remap` instead. + +`extraConfig` (attribute set) {#tester-lycheeLinkCheck-param-extraConfig} + +: Extra configuration to pass to `lychee` in its [configuration file](https://github.com/lycheeverse/lychee/blob/master/lychee.example.toml). + It is automatically [translated](https://nixos.org/manual/nixos/stable/index.html#sec-settings-nix-representable) to TOML. + + Example: `{ "include_verbatim" = true; }` + +`lychee` (derivation, optional) {#tester-lycheeLinkCheck-param-lychee} + +: The `lychee` package to use. + ## `testVersion` {#tester-testVersion} Checks that the output from running a command contains the specified version string in it as a whole word. @@ -129,7 +205,7 @@ runCommand "example" { ::: -## `testEqualContents` {#tester-equalContents} +## `testEqualContents` {#tester-testEqualContents} Check that two paths have the same contents. diff --git a/doc/default.nix b/doc/default.nix index ca4091dc222cc..fd623cf15b8c8 100644 --- a/doc/default.nix +++ b/doc/default.nix @@ -2,6 +2,7 @@ let inherit (pkgs) lib; inherit (lib) hasPrefix removePrefix; + fs = lib.fileset; common = import ./common.nix; @@ -99,13 +100,31 @@ in pkgs.stdenv.mkDerivation { nixos-render-docs ]; - src = ./.; + src = fs.toSource { + root = ./.; + fileset = fs.unions [ + (fs.fileFilter (file: + file.hasExt "md" + || file.hasExt "md.in" + ) ./.) + ./style.css + ./anchor-use.js + ./anchor.min.js + ./manpage-urls.json + ]; + }; postPatch = '' ln -s ${optionsDoc.optionsJSON}/share/doc/nixos/options.json ./config-options.json ''; + pythonInterpreterTable = pkgs.callPackage ./doc-support/python-interpreter-table.nix {}; + + passAsFile = [ "pythonInterpreterTable" ]; + buildPhase = '' + substituteInPlace ./languages-frameworks/python.section.md --subst-var-by python-interpreter-table "$(<"$pythonInterpreterTablePath")" + cat \ ./functions/library.md.in \ ${lib-docs}/index.md \ diff --git a/doc/doc-support/python-interpreter-table.nix b/doc/doc-support/python-interpreter-table.nix new file mode 100644 index 0000000000000..6f2b3422f6727 --- /dev/null +++ b/doc/doc-support/python-interpreter-table.nix @@ -0,0 +1,63 @@ +# For debugging, run in this directory: +# nix eval --impure --raw --expr 'import ./python-interpreter-table.nix {}' +{ pkgs ? (import ../.. { config = { }; overlays = []; }) }: +let + lib = pkgs.lib; + inherit (lib.attrsets) attrNames filterAttrs; + inherit (lib.lists) elem filter map naturalSort reverseList; + inherit (lib.strings) concatStringsSep; + + isPythonInterpreter = name: + /* NB: Package names that don't follow the regular expression: + - `python-cosmopolitan` is not part of `pkgs.pythonInterpreters`. + - `_prebuilt` interpreters are used for bootstrapping internally. + - `python3Minimal` contains python packages, left behind conservatively. + - `rustpython` lacks `pythonVersion` and `implementation`. + */ + (lib.strings.match "(pypy|python)([[:digit:]]*)" name) != null; + + interpreterName = pname: + let + cuteName = { + cpython = "CPython"; + pypy = "PyPy"; + }; + interpreter = pkgs.${pname}; + in + "${cuteName.${interpreter.implementation}} ${interpreter.pythonVersion}"; + + interpreters = reverseList (naturalSort ( + filter isPythonInterpreter (attrNames pkgs.pythonInterpreters) + )); + + aliases = pname: + attrNames ( + filterAttrs (name: value: + isPythonInterpreter name + && name != pname + && interpreterName name == interpreterName pname + ) pkgs + ); + + result = map (pname: { + inherit pname; + aliases = aliases pname; + interpreter = interpreterName pname; + }) interpreters; + + toMarkdown = data: + let + line = package: '' + | ${package.pname} | ${join ", " package.aliases or [ ]} | ${package.interpreter} | + ''; + in + join "" (map line data); + + join = lib.strings.concatStringsSep; + +in +'' + | Package | Aliases | Interpeter | + |---------|---------|------------| + ${toMarkdown result} +'' diff --git a/doc/functions/library/.gitkeep b/doc/functions/library/.gitkeep deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/doc/hooks/waf.section.md b/doc/hooks/waf.section.md index fa027d87a94d7..b58887b6b6471 100644 --- a/doc/hooks/waf.section.md +++ b/doc/hooks/waf.section.md @@ -20,10 +20,6 @@ If `wafPath` doesn't exist, then `wafHook` will copy the `waf` provided from Nix Controls the flags passed to waf tool during build and install phases. For settings specific to build or install phases, use `wafBuildFlags` or `wafInstallFlags` respectively. -#### `dontAddWafCrossFlags` {#dont-add-waf-cross-flags} - -When set to `true`, don't add cross compilation flags during configure phase. - #### `dontUseWafConfigure` {#dont-use-waf-configure} When set to true, don't use the predefined `wafConfigurePhase`. diff --git a/doc/languages-frameworks/android.section.md b/doc/languages-frameworks/android.section.md index 1c5687f8ebf1b..d6ed1f35cb0a8 100644 --- a/doc/languages-frameworks/android.section.md +++ b/doc/languages-frameworks/android.section.md @@ -3,10 +3,36 @@ The Android build environment provides three major features and a number of supporting features. +## Using androidenv with Android Studio {#using-androidenv-with-android-studio} + +Use the `android-studio-full` attribute for a very complete Android SDK, including system images: + +```nix +buildInputs = [ android-studio-full ]; +``` + +This is identical to: + +```nix +buildInputs = [ androidStudioPackages.stable.full ]; +``` + +Alternatively, you can pass composeAndroidPackages to the `withSdk` passthru: + +```nix +buildInputs = [ + (android-studio.withSdk (androidenv.composeAndroidPackages { + includeNDK = true; + }).androidsdk) +]; +``` + +These will export ANDROID_SDK_ROOT and ANDROID_NDK_ROOT to the SDK and NDK directories +in the specified Android build environment. + ## Deploying an Android SDK installation with plugins {#deploying-an-android-sdk-installation-with-plugins} -The first use case is deploying the SDK with a desired set of plugins or subsets -of an SDK. +Alternatively, you can deploy the SDK separately with a desired set of plugins, or subsets of an SDK. ```nix with import {}; @@ -145,16 +171,14 @@ androidComposition.platform-tools ## Using predefined Android package compositions {#using-predefined-android-package-compositions} In addition to composing an Android package set manually, it is also possible -to use a predefined composition that contains all basic packages for a specific -Android version, such as version 9.0 (API-level 28). +to use a predefined composition that contains a fairly complete set of Android packages: -The following Nix expression can be used to deploy the entire SDK with all basic -plugins: +The following Nix expression can be used to deploy the entire SDK: ```nix with import {}; -androidenv.androidPkgs_9_0.androidsdk +androidenv.androidPkgs.androidsdk ``` It is also possible to use one plugin only: @@ -162,50 +186,9 @@ It is also possible to use one plugin only: ```nix with import {}; -androidenv.androidPkgs_9_0.platform-tools -``` - -## Building an Android application {#building-an-android-application} - -In addition to the SDK, it is also possible to build an Ant-based Android -project and automatically deploy all the Android plugins that a project -requires. - - -```nix -with import {}; - -androidenv.buildApp { - name = "MyAndroidApp"; - src = ./myappsources; - release = true; - - # If release is set to true, you need to specify the following parameters - keyStore = ./keystore; - keyAlias = "myfirstapp"; - keyStorePassword = "mykeystore"; - keyAliasPassword = "myfirstapp"; - - # Any Android SDK parameters that install all the relevant plugins that a - # build requires - platformVersions = [ "24" ]; - - # When we include the NDK, then ndk-build is invoked before Ant gets invoked - includeNDK = true; -} +androidenv.androidPkgs.platform-tools ``` -Aside from the app-specific build parameters (`name`, `src`, `release` and -keystore parameters), the `buildApp {}` function supports all the function -parameters that the SDK composition function (the function shown in the -previous section) supports. - -This build function is particularly useful when it is desired to use -[Hydra](https://nixos.org/hydra): the Nix-based continuous integration solution -to build Android apps. An Android APK gets exposed as a build product and can be -installed on any Android device with a web browser by navigating to the build -result page. - ## Spawning emulator instances {#spawning-emulator-instances} For testing purposes, it can also be quite convenient to automatically generate @@ -349,3 +332,44 @@ To update the expressions run the `generate.sh` script that is stored in the ```bash ./generate.sh ``` + +## Building an Android application with Ant {#building-an-android-application-with-ant} + +In addition to the SDK, it is also possible to build an Ant-based Android +project and automatically deploy all the Android plugins that a project +requires. Most newer Android projects use Gradle, and this is included for historical +purposes. + +```nix +with import {}; + +androidenv.buildApp { + name = "MyAndroidApp"; + src = ./myappsources; + release = true; + + # If release is set to true, you need to specify the following parameters + keyStore = ./keystore; + keyAlias = "myfirstapp"; + keyStorePassword = "mykeystore"; + keyAliasPassword = "myfirstapp"; + + # Any Android SDK parameters that install all the relevant plugins that a + # build requires + platformVersions = [ "24" ]; + + # When we include the NDK, then ndk-build is invoked before Ant gets invoked + includeNDK = true; +} +``` + +Aside from the app-specific build parameters (`name`, `src`, `release` and +keystore parameters), the `buildApp {}` function supports all the function +parameters that the SDK composition function (the function shown in the +previous section) supports. + +This build function is particularly useful when it is desired to use +[Hydra](https://nixos.org/hydra): the Nix-based continuous integration solution +to build Android apps. An Android APK gets exposed as a build product and can be +installed on any Android device with a web browser by navigating to the build +result page. diff --git a/doc/languages-frameworks/dart.section.md b/doc/languages-frameworks/dart.section.md index 019765f75354c..594ef7391cbb1 100644 --- a/doc/languages-frameworks/dart.section.md +++ b/doc/languages-frameworks/dart.section.md @@ -98,10 +98,12 @@ The function `buildFlutterApplication` builds Flutter applications. See the [Dart documentation](#ssec-dart-applications) for more details on required files and arguments. +`flutter` in Nixpkgs always points to `flutterPackages.stable`, which is the latest packaged version. To avoid unforeseen breakage during upgrade, packages in Nixpkgs should use a specific flutter version, such as `flutter319` and `flutter322`, instead of using `flutter` directly. + ```nix { flutter, fetchFromGitHub }: -flutter.buildFlutterApplication { +flutter322.buildFlutterApplication { pname = "firmware-updater"; version = "0-unstable-2023-04-30"; diff --git a/doc/languages-frameworks/dotnet.section.md b/doc/languages-frameworks/dotnet.section.md index a4e9d6cf9a6c6..36c20a9e9c507 100644 --- a/doc/languages-frameworks/dotnet.section.md +++ b/doc/languages-frameworks/dotnet.section.md @@ -117,7 +117,6 @@ For more detail about managing the `deps.nix` file, see [Generating and updating * `useDotnetFromEnv` will change the binary wrapper so that it uses the .NET from the environment. The runtime specified by `dotnet-runtime` is given as a fallback in case no .NET is installed in the user's environment. This is most useful for .NET global tools and LSP servers, which often extend the .NET CLI and their runtime should match the users' .NET runtime. * `dotnet-sdk` is useful in cases where you need to change what dotnet SDK is being used. You can also set this to the result of `dotnetSdkPackages.combinePackages`, if the project uses multiple SDKs to build. * `dotnet-runtime` is useful in cases where you need to change what dotnet runtime is being used. This can be either a regular dotnet runtime, or an aspnetcore. -* `dotnet-test-sdk` is useful in cases where unit tests expect a different dotnet SDK. By default, this is set to the `dotnet-sdk` attribute. * `testProjectFile` is useful in cases where the regular project file does not contain the unit tests. It gets restored and build, but not installed. You may need to regenerate your nuget lockfile after setting this. Note that if set, only tests from this project are executed. * `disabledTests` is used to disable running specific unit tests. This gets passed as: `dotnet test --filter "FullyQualifiedName!={}"`, to ensure compatibility with all unit test frameworks. * `dotnetRestoreFlags` can be used to pass flags to `dotnet restore`. diff --git a/doc/languages-frameworks/hare.section.md b/doc/languages-frameworks/hare.section.md new file mode 100644 index 0000000000000..0ae8abeba45c1 --- /dev/null +++ b/doc/languages-frameworks/hare.section.md @@ -0,0 +1,53 @@ +# Hare {#sec-language-hare} + +## Building Hare programs with `hareHook` {#ssec-language-hare} + +The `hareHook` package sets up the environment for building Hare programs by +doing the following: + +1. Setting the `HARECACHE`, `HAREPATH` and `NIX_HAREFLAGS` environment variables; +1. Propagating `harec`, `qbe` and two wrapper scripts for the hare binary. + +It is not a function as is the case for some other languages --- *e. g.*, Go or +Rust ---, but a package to be added to `nativeBuildInputs`. + +## Attributes of `hareHook` {#hareHook-attributes} + +The following attributes are accepted by `hareHook`: + +1. `hareBuildType`: Either `release` (default) or `debug`. It controls if the + `-R` flag is added to `NIX_HAREFLAGS`. + +## Example for `hareHook` {#ex-hareHook} + +```nix +{ + hareHook, + lib, + stdenv, +}: stdenv.mkDerivation { + pname = ""; + version = ""; + src = ""; + + nativeBuildInputs = [ hareHook ]; + + meta = { + description = ""; + inherit (hareHook) badPlatforms platforms; + }; +} +``` + +## Cross Compilation {#hareHook-cross-compilation} + +`hareHook` should handle cross compilation out of the box. This is the main +purpose of `NIX_HAREFLAGS`: In it, the `-a` flag is passed with the architecture +of the `hostPlatform`. + +However, manual intervention may be needed when a binary compiled by the build +process must be run for the build to complete --- *e. g.*, when using Hare's +`hare` module for code generation. + +In those cases, `hareHook` provides the `hare-native` script, which is a wrapper +around the hare binary for using the native (`buildPlatform`) toolchain. diff --git a/doc/languages-frameworks/haskell.section.md b/doc/languages-frameworks/haskell.section.md index dde55c329a4ac..6c2af33c8c9eb 100644 --- a/doc/languages-frameworks/haskell.section.md +++ b/doc/languages-frameworks/haskell.section.md @@ -923,14 +923,61 @@ for this to work. `justStaticExecutables drv` : Only build and install the executables produced by `drv`, removing everything -that may refer to other Haskell packages' store paths (like libraries and -documentation). This dramatically reduces the closure size of the resulting -derivation. Note that the executables are only statically linked against their -Haskell dependencies, but will still link dynamically against libc, GMP and -other system library dependencies. If dependencies use their Cabal-generated -`Paths_*` module, this may not work as well if GHC's dead code elimination -is unable to remove the references to the dependency's store path that module -contains. + that may refer to other Haskell packages' store paths (like libraries and + documentation). This dramatically reduces the closure size of the resulting + derivation. Note that the executables are only statically linked against their + Haskell dependencies, but will still link dynamically against libc, GMP and + other system library dependencies. + + If a library or its dependencies use their Cabal-generated + `Paths_*` module, this may not work as well if GHC's dead code elimination is + unable to remove the references to the dependency's store path that module + contains. + As a consequence, an unused reference may be created from the static binary to such a _library_ store path. + (See [nixpkgs#164630][164630] for more information.) + + Importing the `Paths_*` module may cause builds to fail with this message: + + ``` + error: output '/nix/store/64k8iw0ryz76qpijsnl9v87fb26v28z8-my-haskell-package-1.0.0.0' is not allowed to refer to the following paths: + /nix/store/5q5s4a07gaz50h04zpfbda8xjs8wrnhg-ghc-9.6.3 + ``` + + If that happens, first disable the check for GHC references and rebuild the + derivation: + + ```nix + pkgs.haskell.lib.overrideCabal + (pkgs.haskell.lib.justStaticExecutables my-haskell-package) + (drv: { + disallowGhcReference = false; + }) + ``` + + Then use `strings` to determine which libraries are responsible: + + ``` + $ nix-build ... + $ strings result/bin/my-haskell-binary | grep /nix/store/ + ... + /nix/store/n7ciwdlg8yyxdhbrgd6yc2d8ypnwpmgq-hs-opentelemetry-sdk-0.0.3.6/bin + ... + ``` + + Finally, use `remove-references-to` to delete those store paths from the produced output: + + ```nix + pkgs.haskell.lib.overrideCabal + (pkgs.haskell.lib.justStaticExecutables my-haskell-package) + (drv: { + postInstall = '' + ${drv.postInstall or ""} + remove-references-to -t ${pkgs.haskellPackages.hs-opentelemetry-sdk} + ''; + }) + ``` + +[164630]: https://github.com/NixOS/nixpkgs/issues/164630 `enableSeparateBinOutput drv` : Install executables produced by `drv` to a separate `bin` output. This diff --git a/doc/languages-frameworks/index.md b/doc/languages-frameworks/index.md index 920e5e7bd431e..e8fee9c45216c 100644 --- a/doc/languages-frameworks/index.md +++ b/doc/languages-frameworks/index.md @@ -19,6 +19,7 @@ dotnet.section.md emscripten.section.md gnome.section.md go.section.md +hare.section.md haskell.section.md hy.section.md idris.section.md diff --git a/doc/languages-frameworks/javascript.section.md b/doc/languages-frameworks/javascript.section.md index f706f92c6691f..76db9d0007ce5 100644 --- a/doc/languages-frameworks/javascript.section.md +++ b/doc/languages-frameworks/javascript.section.md @@ -310,6 +310,71 @@ See `node2nix` [docs](https://github.com/svanderburg/node2nix) for more info. - `node2nix` has some [bugs](https://github.com/svanderburg/node2nix/issues/238) related to working with lock files from npm distributed with `nodejs_16`. - `node2nix` does not like missing packages from npm. If you see something like `Cannot resolve version: vue-loader-v16@undefined` then you might want to try another tool. The package might have been pulled off of npm. +### pnpm {#javascript-pnpm} + +Pnpm is available as the top-level package `pnpm`. Additionally, there are variants pinned to certain major versions, like `pnpm_8` and `pnpm_9`, which support different sets of lock file versions. + +When packaging an application that includes a `pnpm-lock.yaml`, you need to fetch the pnpm store for that project using a fixed-output-derivation. The functions `pnpm_8.fetchDeps` and `pnpm_9.fetchDeps` can create this pnpm store derivation. In conjunction, the setup hooks `pnpm_8.configHook` and `pnpm_9.configHook` will prepare the build environment to install the prefetched dependencies store. Here is an example for a package that contains a `package.json` and a `pnpm-lock.yaml` files using the above `pnpm_` attributes: + +```nix +{ + stdenv, + nodejs, + # This is pinned as { pnpm = pnpm_9; } + pnpm +}: + +stdenv.mkDerivation (finalAttrs: { + pname = "foo"; + version = "0-unstable-1980-01-01"; + + src = ...; + + nativeBuildInputs = [ + nodejs + pnpm.configHook + ]; + + pnpmDeps = pnpm.fetchDeps { + inherit (finalAttrs) pname version src; + hash = "..."; + }; +}) +``` + +NOTE: It is highly recommended to use a pinned version of pnpm (i.e. `pnpm_8` or `pnpm_9`), to increase future reproducibility. It might also be required to use an older version, if the package needs support for a certain lock file version. + +In case you are patching `package.json` or `pnpm-lock.yaml`, make sure to pass `finalAttrs.patches` to the function as well (i.e. `inherit (finalAttrs) patches`. + +#### Dealing with `sourceRoot` {#javascript-pnpm-sourceRoot} + +NOTE: Nixpkgs pnpm tooling doesn't support building projects with a `pnpm-workspace.yaml`, or building monorepos. It maybe possible to use `pnpm.fetchDeps` for these projects, but it may be hard or impossible to produce a binary from such projects ([an example attempt](https://github.com/NixOS/nixpkgs/pull/290715#issuecomment-2144543728)). + +If the pnpm project is in a subdirectory, you can just define `sourceRoot` or `setSourceRoot` for `fetchDeps`. Note, that projects using `pnpm-workspace.yaml` are currently not supported, and will probably not work using this approach. +If `sourceRoot` is different between the parent derivation and `fetchDeps`, you will have to set `pnpmRoot` to effectively be the same location as it is in `fetchDeps`. + +Assuming the following directory structure, we can define `sourceRoot` and `pnpmRoot` as follows: + +``` +. +├── frontend +│   ├── ... +│   ├── package.json +│   └── pnpm-lock.yaml +└── ... +``` + +```nix + ... + pnpmDeps = pnpm.fetchDeps { + ... + sourceRoot = "${finalAttrs.src.name}/frontend"; + }; + + # by default the working directory is the extracted source + pnpmRoot = "frontend"; +``` + ### yarn2nix {#javascript-yarn2nix} #### Preparation {#javascript-yarn2nix-preparation} diff --git a/doc/languages-frameworks/nim.section.md b/doc/languages-frameworks/nim.section.md index c6ebf49b83f66..71e3ae25a86d9 100644 --- a/doc/languages-frameworks/nim.section.md +++ b/doc/languages-frameworks/nim.section.md @@ -7,7 +7,7 @@ The following example shows a Nim program that depends only on Nim libraries: ```nix { lib, buildNimPackage, fetchFromGitHub }: -buildNimPackage { } (finalAttrs: { +buildNimPackage (finalAttrs: { pname = "ttop"; version = "1.2.7"; @@ -80,7 +80,6 @@ For example, to propagate a dependency on SDL2 for lockfiles that select the Nim /* … */ sdl2 = lockAttrs: - finalAttrs: { buildInputs ? [ ], ... }: { buildInputs = buildInputs ++ [ SDL2 ]; @@ -89,9 +88,8 @@ For example, to propagate a dependency on SDL2 for lockfiles that select the Nim } ``` -The annotations in the `nim-overrides.nix` set are functions that take three arguments and return a new attrset to be overlayed on the package being built. +The annotations in the `nim-overrides.nix` set are functions that take two arguments and return a new attrset to be overlayed on the package being built. - lockAttrs: the attrset for this library from within a lockfile. This can be used to implement library version constraints, such as marking libraries as broken or insecure. -- finalAttrs: the final attrset passed by `buildNimPackage` to `stdenv.mkDerivation`. - prevAttrs: the attrset produced by initial arguments to `buildNimPackage` and any preceding lockfile overlays. ### Overriding an Nim library override {#nim-lock-overrides-overrides} diff --git a/doc/languages-frameworks/python.section.md b/doc/languages-frameworks/python.section.md index 6fcae4b6520d9..827c85146537d 100644 --- a/doc/languages-frameworks/python.section.md +++ b/doc/languages-frameworks/python.section.md @@ -4,16 +4,7 @@ ### Interpreters {#interpreters} -| Package | Aliases | Interpreter | -|------------|-----------------|-------------| -| python27 | python2, python | CPython 2.7 | -| python39 | | CPython 3.9 | -| python310 | | CPython 3.10 | -| python311 | python3 | CPython 3.11 | -| python312 | | CPython 3.12 | -| python313 | | CPython 3.13 | -| pypy27 | pypy2, pypy | PyPy2.7 | -| pypy39 | pypy3 | PyPy 3.9 | +@python-interpreter-table@ The Nix expressions for the interpreters can be found in `pkgs/development/interpreters/python`. @@ -40,8 +31,8 @@ Each interpreter has the following attributes: ### Building packages and applications {#building-packages-and-applications} -Python libraries and applications that use `setuptools` or -`distutils` are typically built with respectively the [`buildPythonPackage`](#buildpythonpackage-function) and +Python libraries and applications that use tools to follow PEP 517 (e.g. `setuptools` or `hatchling`, etc.) or +previous tools such as `distutils` are typically built with respectively the [`buildPythonPackage`](#buildpythonpackage-function) and [`buildPythonApplication`](#buildpythonapplication-function) functions. These two functions also support installing a `wheel`. All Python packages reside in `pkgs/top-level/python-packages.nix` and all @@ -87,6 +78,7 @@ The following is an example: , fetchPypi # build-system +, setuptools , setuptools-scm # dependencies @@ -116,6 +108,7 @@ buildPythonPackage rec { ''; build-system = [ + setuptools setuptools-scm ]; @@ -143,13 +136,13 @@ buildPythonPackage rec { The `buildPythonPackage` mainly does four things: -* In the [`buildPhase`](#build-phase), it calls `${python.pythonOnBuildForHost.interpreter} setup.py bdist_wheel` to +* In the [`buildPhase`](#build-phase), it calls `${python.pythonOnBuildForHost.interpreter} -m build --wheel` to build a wheel binary zipfile. -* In the [`installPhase`](#ssec-install-phase), it installs the wheel file using `pip install *.whl`. +* In the [`installPhase`](#ssec-install-phase), it installs the wheel file using `${python.pythonOnBuildForHost.interpreter} -m installer *.whl`. * In the [`postFixup`](#var-stdenv-postFixup) phase, the `wrapPythonPrograms` bash function is called to wrap all programs in the `$out/bin/*` directory to include `$PATH` environment variable and add dependent libraries to script's `sys.path`. -* In the [`installCheck`](#ssec-installCheck-phase) phase, `${python.interpreter} setup.py test` is run. +* In the [`installCheck`](#ssec-installCheck-phase) phase, `${python.interpreter} -m pytest` is run. By default tests are run because [`doCheck = true`](#var-stdenv-doCheck). Test dependencies, like e.g. the test runner, should be added to [`nativeCheckInputs`](#var-stdenv-nativeCheckInputs). @@ -186,10 +179,6 @@ following are specific to `buildPythonPackage`: `makeWrapperArgs = ["--set FOO BAR" "--set BAZ QUX"]`. * `namePrefix`: Prepends text to `${name}` parameter. In case of libraries, this defaults to `"python3.8-"` for Python 3.8, etc., and in case of applications to `""`. -* `pipInstallFlags ? []`: A list of strings. Arguments to be passed to `pip - install`. To pass options to `python setup.py install`, use - `--install-option`. E.g., `pipInstallFlags=["--install-option='--cpp_implementation'"]`. -* `pipBuildFlags ? []`: A list of strings. Arguments to be passed to `pip wheel`. * `pypaBuildFlags ? []`: A list of strings. Arguments to be passed to `python -m build --wheel`. * `pythonPath ? []`: List of packages to be added into `$PYTHONPATH`. Packages in `pythonPath` are not propagated (contrary to [`propagatedBuildInputs`](#var-stdenv-propagatedBuildInputs)). @@ -307,7 +296,6 @@ python3Packages.buildPythonApplication rec { build-system = with python3Packages; [ setuptools - wheel ]; dependencies = with python3Packages; [ @@ -474,13 +462,11 @@ are used in [`buildPythonPackage`](#buildpythonpackage-function). with the `eggInstallHook` - `eggBuildHook` to skip building for eggs. - `eggInstallHook` to install eggs. -- `pipBuildHook` to build a wheel using `pip` and PEP 517. Note a build system - (e.g. `setuptools` or `flit`) should still be added as `build-system`. - `pypaBuildHook` to build a wheel using [`pypa/build`](https://pypa-build.readthedocs.io/en/latest/index.html) and PEP 517/518. Note a build system (e.g. `setuptools` or `flit`) should still be added as `build-system`. -- `pipInstallHook` to install wheels. +- `pypaInstallHook` to install wheels. - `pytestCheckHook` to run tests with `pytest`. See [example usage](#using-pytestcheckhook). - `pythonCatchConflictsHook` to fail if the package depends on two different versions of the same dependency. - `pythonImportsCheckHook` to check whether importing the listed modules works. @@ -618,7 +604,8 @@ that sets up an interpreter pointing to them. This matters much more for "big" modules like `pytorch` or `tensorflow`. Module names usually match their names on [pypi.org](https://pypi.org/), but -you can use the [Nixpkgs search website](https://nixos.org/nixos/packages.html) +normalized according to PEP 503/508. (e.g. Foo__Bar.baz -> foo-bar-baz) +You can use the [Nixpkgs search website](https://nixos.org/nixos/packages.html) to find them as well (along with non-python packages). At this point we can create throwaway experimental Python environments with @@ -846,7 +833,6 @@ building Python libraries is [`buildPythonPackage`](#buildpythonpackage-function , buildPythonPackage , fetchPypi , setuptools -, wheel }: buildPythonPackage rec { @@ -861,7 +847,6 @@ buildPythonPackage rec { build-system = [ setuptools - wheel ]; # has no tests @@ -885,7 +870,7 @@ buildPythonPackage rec { What happens here? The function [`buildPythonPackage`](#buildpythonpackage-function) is called and as argument it accepts a set. In this case the set is a recursive set, `rec`. One of the arguments is the name of the package, which consists of a basename (generally -following the name on PyPi) and a version. Another argument, `src` specifies the +following the name on PyPI) and a version. Another argument, `src` specifies the source, which in this case is fetched from PyPI using the helper function `fetchPypi`. The argument `doCheck` is used to set whether tests should be run when building the package. Since there are no tests, we rely on [`pythonImportsCheck`](#using-pythonimportscheck) @@ -920,7 +905,6 @@ with import {}; build-system = [ python311.pkgs.setuptools - python311.pkgs.wheel ]; # has no tests @@ -973,13 +957,13 @@ order to build [`datashape`](https://github.com/blaze/datashape). , fetchPypi # build dependencies -, setuptools, wheel +, setuptools # dependencies , numpy, multipledispatch, python-dateutil # tests -, pytest +, pytestCheckHook }: buildPythonPackage rec { @@ -994,7 +978,6 @@ buildPythonPackage rec { build-system = [ setuptools - wheel ]; dependencies = [ @@ -1004,7 +987,7 @@ buildPythonPackage rec { ]; nativeCheckInputs = [ - pytest + pytestCheckHook ]; meta = { @@ -1017,8 +1000,8 @@ buildPythonPackage rec { ``` We can see several runtime dependencies, `numpy`, `multipledispatch`, and -`python-dateutil`. Furthermore, we have [`nativeCheckInputs`](#var-stdenv-nativeCheckInputs) with `pytest`. -`pytest` is a test runner and is only used during the [`checkPhase`](#ssec-check-phase) and is +`python-dateutil`. Furthermore, we have [`nativeCheckInputs`](#var-stdenv-nativeCheckInputs) with `pytestCheckHook`. +`pytestCheckHook` is a test runner hook and is only used during the [`checkPhase`](#ssec-check-phase) and is therefore not added to `dependencies`. In the previous case we had only dependencies on other Python packages to consider. @@ -1031,7 +1014,6 @@ when building the bindings and are therefore added as [`buildInputs`](#var-stden , buildPythonPackage , fetchPypi , setuptools -, wheel , libxml2 , libxslt }: @@ -1048,7 +1030,6 @@ buildPythonPackage rec { build-system = [ setuptools - wheel ]; buildInputs = [ @@ -1056,6 +1037,14 @@ buildPythonPackage rec { libxslt ]; + # tests are meant to be ran "in-place" in the same directory as src + doCheck = false; + + pythonImportsCheck = [ + "lxml" + "lxml.etree" + ]; + meta = { changelog = "https://github.com/lxml/lxml/releases/tag/lxml-${version}"; description = "Pythonic binding for the libxml2 and libxslt libraries"; @@ -1083,7 +1072,6 @@ therefore we have to set `LDFLAGS` and `CFLAGS`. # build dependencies , setuptools -, wheel # dependencies , fftw @@ -1094,7 +1082,7 @@ therefore we have to set `LDFLAGS` and `CFLAGS`. }: buildPythonPackage rec { - pname = "pyFFTW"; + pname = "pyfftw"; version = "0.9.2"; pyproject = true; @@ -1105,7 +1093,6 @@ buildPythonPackage rec { build-system = [ setuptools - wheel ]; buildInputs = [ @@ -1127,6 +1114,8 @@ buildPythonPackage rec { # Tests cannot import pyfftw. pyfftw works fine though. doCheck = false; + pythonImportsCheck = [ "pyfftw" ]; + meta = { changelog = "https://github.com/pyFFTW/pyFFTW/releases/tag/v${version}"; description = "A pythonic wrapper around FFTW, the FFT library, presenting a unified interface for all the supported transforms"; @@ -1142,10 +1131,8 @@ Note also the line [`doCheck = false;`](#var-stdenv-doCheck), we explicitly disa It is highly encouraged to have testing as part of the package build. This helps to avoid situations where the package was able to build and install, -but is not usable at runtime. Currently, all packages will use the `test` -command provided by the setup.py (i.e. `python setup.py test`). However, -this is currently deprecated https://github.com/pypa/setuptools/pull/1878 -and your package should provide its own [`checkPhase`](#ssec-check-phase). +but is not usable at runtime. +Your package should provide its own [`checkPhase`](#ssec-check-phase). ::: {.note} The [`checkPhase`](#ssec-check-phase) for python maps to the `installCheckPhase` on a @@ -1216,9 +1203,11 @@ been removed, in this case, it's recommended to use `pytestCheckHook`. #### Using pytestCheckHook {#using-pytestcheckhook} -`pytestCheckHook` is a convenient hook which will substitute the setuptools -`test` command for a [`checkPhase`](#ssec-check-phase) which runs `pytest`. This is also beneficial +`pytestCheckHook` is a convenient hook which will set up (or configure) +a [`checkPhase`](#ssec-check-phase) to run `pytest`. This is also beneficial when a package may need many items disabled to run the test suite. +Most packages use `pytest` or `unittest`, which is compatible with `pytest`, +so you will most likely use `pytestCheckHook`. Using the example above, the analogous `pytestCheckHook` usage would be: @@ -1373,10 +1362,12 @@ instead of a dev dependency). Keep in mind that while the examples above are done with `requirements.txt`, `pythonRelaxDepsHook` works by modifying the resulting wheel file, so it should work with any of the [existing hooks](#setup-hooks). +It indicates that `pythonRelaxDepsHook` has no effect on build time dependencies, such as in `build-system`. +If a package requires incompatible build time dependencies, they should be removed in `postPatch` with `substituteInPlace` or something similar. #### Using unittestCheckHook {#using-unittestcheckhook} -`unittestCheckHook` is a hook which will substitute the setuptools `test` command for a [`checkPhase`](#ssec-check-phase) which runs `python -m unittest discover`: +`unittestCheckHook` is a hook which will set up (or configure) a [`checkPhase`](#ssec-check-phase) to run `python -m unittest discover`: ```nix { @@ -1390,6 +1381,8 @@ work with any of the [existing hooks](#setup-hooks). } ``` +`pytest` is compatible with `unittest`, so in most cases you can use `pytestCheckHook` instead. + #### Using sphinxHook {#using-sphinxhook} The `sphinxHook` is a helpful tool to build documentation and manpages @@ -1468,7 +1461,6 @@ We first create a function that builds `toolz` in `~/path/to/toolz/release.nix` , buildPythonPackage , fetchPypi , setuptools -, wheel }: buildPythonPackage rec { @@ -1483,7 +1475,6 @@ buildPythonPackage rec { build-system = [ setuptools - wheel ]; meta = { @@ -1503,10 +1494,9 @@ with import {}; ( let toolz = callPackage /path/to/toolz/release.nix { - buildPythonPackage = python310 -Packages.buildPythonPackage; + buildPythonPackage = python3Packages.buildPythonPackage; }; - in python310.withPackages (ps: [ + in python3.withPackages (ps: [ ps.numpy toolz ]) @@ -1927,6 +1917,8 @@ because we can only provide security support for non-vendored dependencies. We recommend [nix-init](https://github.com/nix-community/nix-init) for creating new python packages within nixpkgs, as it already prefetches the source, parses dependencies for common formats and prefills most things in `meta`. +See also [contributing section](#contributing). + ### Are Python interpreters built deterministically? {#deterministic-builds} The Python interpreters are now built deterministically. Minor modifications had @@ -1944,16 +1936,15 @@ Both are also exported in `nix-shell`. It is recommended to test packages as part of the build process. Source distributions (`sdist`) often include test files, but not always. -By default the command `python setup.py test` is run as part of the -[`checkPhase`](#ssec-check-phase), but often it is necessary to pass a custom [`checkPhase`](#ssec-check-phase). An -example of such a situation is when `py.test` is used. +The best practice today is to pass a test hook (e.g. pytestCheckHook, unittestCheckHook) into nativeCheckInputs. +This will reconfigure the checkPhase to make use of that particular test framework. +Occasionally packages don't make use of a common test framework, which may then require a custom checkPhase. #### Common issues {#common-issues} -* Non-working tests can often be deselected. By default [`buildPythonPackage`](#buildpythonpackage-function) - runs `python setup.py test`. which is deprecated. Most Python modules however - do follow the standard test protocol where the pytest runner can be used - instead. `pytest` supports the `-k` and `--ignore` parameters to ignore test +* Non-working tests can often be deselected. Most Python modules + do follow the standard test protocol where the pytest runner can be used. + `pytest` supports the `-k` and `--ignore` parameters to ignore test methods or classes as well as whole files. For `pytestCheckHook` these are conveniently exposed as `disabledTests` and `disabledTestPaths` respectively. @@ -1994,14 +1985,25 @@ The following rules are desired to be respected: * Python applications live outside of `python-packages.nix` and are packaged with [`buildPythonApplication`](#buildpythonapplication-function). * Make sure libraries build for all Python interpreters. -* By default we enable tests. Make sure the tests are found and, in the case of + If it fails to build on some Python versions, consider disabling them by setting `disable = pythonAtLeast "3.x"` along with a comment. +* The two parameters, `pyproject` and `build-system` are set to avoid the legacy setuptools/distutils build. +* Only unversioned attributes (e.g. `pydantic`, but not `pypdantic_1`) can be included in `dependencies`, + since due to `PYTHONPATH` limitations we can only ever support a single version for libraries + without running into duplicate module name conflicts. +* The version restrictions of `dependencies` can be relaxed by [`pythonRelaxDepsHook`](#using-pythonrelaxdepshook). +* Make sure the tests are enabled using for example [`pytestCheckHook`](#using-pytestcheckhook) and, in the case of libraries, are passing for all interpreters. If certain tests fail they can be disabled individually. Try to avoid disabling the tests altogether. In any case, when you disable tests, leave a comment explaining why. +* `pythonImportsCheck` is set. This is still a good smoke test even if `pytestCheckHook` is set. +* `meta.platforms` takes the default value in many cases. + It does not need to be set explicitly unless the package requires a specific platform. +* The file is formatted with `nixfmt-rfc-style`. * Commit names of Python libraries should reflect that they are Python libraries, so write for example `python311Packages.numpy: 1.11 -> 1.12`. It is highly recommended to specify the current default version to enable automatic build by ofborg. + Note that `pythonPackages` is an alias for `python27Packages`. * Attribute names in `python-packages.nix` as well as `pname`s should match the library's name on PyPI, but be normalized according to [PEP 0503](https://www.python.org/dev/peps/pep-0503/#normalized-names). This means @@ -2015,6 +2017,8 @@ The following rules are desired to be respected: * Attribute names in `python-packages.nix` should be sorted alphanumerically to avoid merge conflicts and ease locating attributes. +This list is useful for reviewers as well as for self-checking when submitting packages. + ## Package set maintenance {#python-package-set-maintenance} The whole Python package set has a lot of packages that do not see regular diff --git a/doc/languages-frameworks/rust.section.md b/doc/languages-frameworks/rust.section.md index 8a1007b7bb8a9..e12bbe02bfb52 100644 --- a/doc/languages-frameworks/rust.section.md +++ b/doc/languages-frameworks/rust.section.md @@ -254,7 +254,7 @@ By default, it takes the `stdenv.hostPlatform.config` and replaces components where they are known to differ. But there are ways to customize the argument: - To choose a different target by name, define - `stdenv.hostPlatform.rustc.config` as that name (a string), and that + `stdenv.hostPlatform.rust.rustcTarget` as that name (a string), and that name will be used instead. For example: @@ -262,7 +262,7 @@ where they are known to differ. But there are ways to customize the argument: ```nix import { crossSystem = (import ).systems.examples.armhf-embedded // { - rustc.config = "thumbv7em-none-eabi"; + rust.rustcTarget = "thumbv7em-none-eabi"; }; } ``` @@ -274,10 +274,10 @@ where they are known to differ. But there are ways to customize the argument: ``` - To pass a completely custom target, define - `stdenv.hostPlatform.rustc.config` with its name, and - `stdenv.hostPlatform.rustc.platform` with the value. The value will be + `stdenv.hostPlatform.rust.rustcTarget` with its name, and + `stdenv.hostPlatform.rust.platform` with the value. The value will be serialized to JSON in a file called - `${stdenv.hostPlatform.rustc.config}.json`, and the path of that file + `${stdenv.hostPlatform.rust.rustcTarget}.json`, and the path of that file will be used instead. For example: @@ -285,8 +285,8 @@ where they are known to differ. But there are ways to customize the argument: ```nix import { crossSystem = (import ).systems.examples.armhf-embedded // { - rustc.config = "thumb-crazy"; - rustc.platform = { foo = ""; bar = ""; }; + rust.rustcTarget = "thumb-crazy"; + rust.platform = { foo = ""; bar = ""; }; }; } ``` diff --git a/doc/packages/linux.section.md b/doc/packages/linux.section.md index 4c3b2a3b132a1..90d14772134ba 100644 --- a/doc/packages/linux.section.md +++ b/doc/packages/linux.section.md @@ -40,31 +40,29 @@ pkgs.linux_latest.override { ## Manual kernel configuration {#sec-manual-kernel-configuration} Sometimes it may not be desirable to use kernels built with `pkgs.buildLinux`, especially if most of the common configuration has to be altered or disabled to achieve a kernel as expected by the target use case. -An example of this is building a kernel for use in a VM or micro VM. You can use `pkgs.linuxManualConfig` in these cases. It requires the `src`, `version`, and `configfile` attributes to be specified. +An example of this is building a kernel for use in a VM or micro VM. You can use `pkgs.linuxPackages_custom` in these cases. It requires the `src`, `version`, and `configfile` attributes to be specified. :::{.example #ex-using-linux-manual-config} -# Using `pkgs.linuxManualConfig` with a specific source, version, and config file +# Using `pkgs.linuxPackages_custom` with a specific source, version, and config file ```nix -{ pkgs, ... }: { +{ pkgs, ... }: +pkgs.linuxPackages_custom { version = "6.1.55"; src = pkgs.fetchurl { url = "https://cdn.kernel.org/pub/linux/kernel/v6.x/linux-${version}.tar.xz"; hash = "sha256:1h0mzx52q9pvdv7rhnvb8g68i7bnlc9rf8gy9qn4alsxq4g28zm8"; }; configfile = ./path_to_config_file; - linux = pkgs.linuxManualConfig { - inherit version src configfile; - allowImportFromDerivation = true; - }; } ``` If necessary, the version string can be slightly modified to explicitly mark it as a custom version. If you do so, ensure the `modDirVersion` attribute matches the source's version, otherwise the build will fail. ```nix -{ pkgs, ... }: { +{ pkgs, ... }: +pkgs.linuxPackages_custom { version = "6.1.55-custom"; modDirVersion = "6.1.55"; src = pkgs.fetchurl { @@ -72,16 +70,12 @@ If necessary, the version string can be slightly modified to explicitly mark it hash = "sha256:1h0mzx52q9pvdv7rhnvb8g68i7bnlc9rf8gy9qn4alsxq4g28zm8"; }; configfile = ./path_to_config_file; - linux = pkgs.linuxManualConfig { - inherit version modDirVersion src configfile; - allowImportFromDerivation = true; - }; } ``` ::: -Additional attributes can be used with `linuxManualConfig` for further customisation. You're encouraged to read [the `pkgs.linuxManualConfig` source code](https://github.com/NixOS/nixpkgs/blob/d77bda728d5041c1294a68fb25c79e2d161f62b9/pkgs/os-specific/linux/kernel/manual-config.nix) to understand how to use them. +Additional attributes can be used with `linuxManualConfig` for further customisation instead of `linuxPackages_custom`. You're encouraged to read [the `pkgs.linuxManualConfig` source code](https://github.com/NixOS/nixpkgs/blob/d77bda728d5041c1294a68fb25c79e2d161f62b9/pkgs/os-specific/linux/kernel/manual-config.nix) to understand how to use them. To edit the `.config` file for Linux X.Y from within Nix, proceed as follows: diff --git a/doc/stdenv.md b/doc/stdenv.md index 1ef81f84b5141..d49f7cb2d1000 100644 --- a/doc/stdenv.md +++ b/doc/stdenv.md @@ -3,6 +3,7 @@ ```{=include=} chapters stdenv/stdenv.chapter.md stdenv/meta.chapter.md +stdenv/passthru.chapter.md stdenv/multiple-output.chapter.md stdenv/cross-compilation.chapter.md stdenv/platform-notes.chapter.md diff --git a/doc/stdenv/meta.chapter.md b/doc/stdenv/meta.chapter.md index 575d3368326d6..b5955b96eeb64 100644 --- a/doc/stdenv/meta.chapter.md +++ b/doc/stdenv/meta.chapter.md @@ -110,83 +110,6 @@ Some packages use this to automatically detect the maximum set of features with For example, `systemd` [requires dynamic linking](https://github.com/systemd/systemd/issues/20600#issuecomment-912338965), and [has a `meta.badPlatforms` setting](https://github.com/NixOS/nixpkgs/blob/b03ac42b0734da3e7be9bf8d94433a5195734b19/pkgs/os-specific/linux/systemd/default.nix#L752) similar to the one above. Packages which can be built with or without `systemd` support will use `lib.meta.availableOn` to detect whether or not `systemd` is available on the [`hostPlatform`](#ssec-cross-platform-parameters) for which they are being built; if it is not available (e.g. due to a statically-linked host platform like `pkgsStatic`) this support will be disabled by default. -### `tests` {#var-meta-tests} - -::: {.warning} -This attribute is special in that it is not actually under the `meta` attribute set but rather under the `passthru` attribute set. This is due to how `meta` attributes work, and the fact that they are supposed to contain only metadata, not derivations. -::: - -An attribute set with tests as values. A test is a derivation that builds when the test passes and fails to build otherwise. - -You can run these tests with: - -```ShellSession -$ cd path/to/nixpkgs -$ nix-build -A your-package.tests -``` - -#### Package tests {#var-meta-tests-packages} - -Tests that are part of the source package are often executed in the `installCheckPhase`. - -Prefer `passthru.tests` for tests that are introduced in nixpkgs because: - -* `passthru.tests` tests the 'real' package, independently from the environment in which it was built -* we can run `passthru.tests` independently -* `installCheckPhase` adds overhead to each build - -For more on how to write and run package tests, see [](#sec-package-tests). - -#### NixOS tests {#var-meta-tests-nixos} - -The NixOS tests are available as `nixosTests` in parameters of derivations. For instance, the OpenSMTPD derivation includes lines similar to: - -```nix -{ /* ... , */ nixosTests }: -{ - # ... - passthru.tests = { - basic-functionality-and-dovecot-integration = nixosTests.opensmtpd; - }; -} -``` - -NixOS tests run in a VM, so they are slower than regular package tests. For more information see [NixOS module tests](https://nixos.org/manual/nixos/stable/#sec-nixos-tests). - -Alternatively, you can specify other derivations as tests. You can make use of -the optional parameter to inject the correct package without -relying on non-local definitions, even in the presence of `overrideAttrs`. -Here that's `finalAttrs.finalPackage`, but you could choose a different name if -`finalAttrs` already exists in your scope. - -`(mypkg.overrideAttrs f).passthru.tests` will be as expected, as long as the -definition of `tests` does not rely on the original `mypkg` or overrides it in -all places. - -```nix -# my-package/default.nix -{ stdenv, callPackage }: -stdenv.mkDerivation (finalAttrs: { - # ... - passthru.tests.example = callPackage ./example.nix { my-package = finalAttrs.finalPackage; }; -}) -``` - -```nix -# my-package/example.nix -{ runCommand, lib, my-package, ... }: -runCommand "my-package-test" { - nativeBuildInputs = [ my-package ]; - src = lib.sources.sourcesByRegex ./. [ ".*.in" ".*.expected" ]; -} '' - my-package --help - my-package example.actual - diff -U3 --color=auto example.expected example.actual - mkdir $out -'' -``` - - ### `timeout` {#var-meta-timeout} A timeout (in seconds) for building the derivation. If the derivation takes longer than this time to build, Hydra will fail it due to breaking the timeout. However, all computers do not have the same computing power, hence some builders may decide to apply a multiplicative factor to this value. When filling this value in, try to keep it approximately consistent with other values already present in `nixpkgs`. diff --git a/doc/stdenv/passthru.chapter.md b/doc/stdenv/passthru.chapter.md new file mode 100644 index 0000000000000..008b908b2f48e --- /dev/null +++ b/doc/stdenv/passthru.chapter.md @@ -0,0 +1,157 @@ +# Passthru-attributes {#chap-passthru} +[]{#var-stdenv-passthru} []{#special-variables} + +As opposed to most other `mkDerivation` input attributes, `passthru` is not passed to the derivation's [`builder` executable](https://nixos.org/manual/nix/stable/expressions/derivations.html#attr-builder). +Changing it will not trigger a rebuild – it is "passed through". +Its value can be accessed as if it was set inside a derivation. + +::: {.note} +`passthru` attributes follow no particular schema, but there are a few [conventional patterns](#sec-common-passthru-attributes). +::: + +:::{.example #ex-accessing-passthru} + +## Setting and accessing `passthru` attributes + +```nix +{ stdenv, fetchGit }: +let + hello = stdenv.mkDerivation { + pname = "hello"; + src = fetchGit { /* ... */ }; + + passthru = { + foo = "bar"; + baz = { + value1 = 4; + value2 = 5; + }; + }; + }; +in +hello.baz.value1 +``` + +``` +4 +``` +::: + +## Common `passthru`-attributes {#sec-common-passthru-attributes} + +Many `passthru` attributes are situational, so this section only lists recurring patterns. +They fall in one of these categories: + +- Global conventions, which are applied almost universally in Nixpkgs. + + Generally these don't entail any special support built into the derivation they belong to. + Common examples of this type are [`passthru.tests`](#var-passthru-tests) and [`passthru.updateScript`](#var-passthru-updateScript). + +- Conventions for adding extra functionality to a derivation. + + These tend to entail support from the derivation or the `passthru` attribute in question. + Common examples of this type are `passthru.optional-dependencies`, `passthru.withPlugins`, and `passthru.withPackages`. + All of those allow associating the package with a set of components built for that specific package, such as when building Python runtime environments using (`python.withPackages`)[#python.withpackages-function]. + +Attributes that apply only to particular [build helpers](#part-builders) or [language ecosystems](#chap-language-support) are documented there. + +### `passthru.tests` {#var-passthru-tests} +[]{#var-meta-tests} + +An attribute set with tests as values. +A test is a derivation that builds when the test passes and fails to build otherwise. + +Run these tests with: + +```ShellSession +$ cd path/to/nixpkgs +$ nix-build -A your-package.tests +``` + +:::{.note} +The Nixpkgs systems for continuous integration [Hydra](https://hydra.nixos.org/) and [`nixpkgs-review`](https://github.com/Mic92/nixpkgs-review) don't build these derivations by default, and ([`@ofborg`](https://github.com/NixOS/ofborg)) only builds them when evaluating pull requests for that particular package, or when manually instructed. +::: + +#### Package tests {#var-passthru-tests-packages} +[]{#var-meta-tests-packages} + +Tests that are part of the source package, if they run quickly, are typically executed in the [`installCheckPhase`](#var-stdenv-phases). +This phase is also suitable for performing a `--version` test for packages that support such flag. +Most programs distributed by Nixpkgs support such a `--version` flag, and successfully calling the program with that flag indicates that the package at least got compiled properly. + +:::{.example #ex-checking-build-installCheckPhase} + +## Checking builds with `installCheckPhase` + +When building `git`, a rudimentary test for successful compilation would be running `git --version`: + +```nix +stdenv.mkDerivation (finalAttrs: { + pname = "git"; + version = "1.2.3"; + # ... + doInstallCheck = true; + installCheckPhase = '' + runHook preInstallCheck + echo checking if 'git --version' mentions ${finalAttrs.version} + $out/bin/git --version | grep ${finalAttrs.version} + runHook postInstallCheck + ''; + # ... +}) +``` +::: + +However, tests that are non-trivial will better fit into `passthru.tests` because they: + +- Access the package as consumers would, independently from the environment in which it was built +- Can be run and debugged without rebuilding the package, which is useful if that takes a long time +- Don't add overhad to each build, as opposed to `installCheckPhase` + +It is also possible to use `passthru.tests` to test the version with [`testVersion`](#tester-testVersion). + + +For more on how to write and run package tests for Nixpkgs, see the [testing section in the package contributor guide](https://github.com/NixOS/nixpkgs/blob/master/pkgs/README.md#package-tests). + +#### NixOS tests {#var-passthru-tests-nixos} +[]{#var-meta-tests-nixos} + +Tests written for NixOS are available as the `nixosTests` argument to package recipes. +For instance, the [OpenSMTPD derivation](https://search.nixos.org/packages?show=opensmtpd) includes lines similar to: + +```nix +{ nixosTests, ... }: +{ + # ... + passthru.tests = { + basic-functionality-and-dovecot-integration = nixosTests.opensmtpd; + }; +} +``` + +NixOS tests run in a virtual machine (VM), so they are slower than regular package tests. +For more information see the NixOS manual on [NixOS module tests](https://nixos.org/manual/nixos/stable/#sec-nixos-tests). + +### `passthru.updateScript` {#var-passthru-updateScript} + +[]{#var-passthru-updateScript-command} +[]{#var-passthru-updateScript-set-command} +[]{#var-passthru-updateScript-set-attrPath} +[]{#var-passthru-updateScript-set-supportedFeatures} +[]{#var-passthru-updateScript-env-UPDATE_NIX_NAME} +[]{#var-passthru-updateScript-env-UPDATE_NIX_PNAME} +[]{#var-passthru-updateScript-env-UPDATE_NIX_OLD_VERSION} +[]{#var-passthru-updateScript-env-UPDATE_NIX_ATTR_PATH} +[]{#var-passthru-updateScript-execution} +[]{#var-passthru-updateScript-supported-features} +[]{#var-passthru-updateScript-commit} +[]{#var-passthru-updateScript-commit-attrPath} +[]{#var-passthru-updateScript-commit-oldVersion} +[]{#var-passthru-updateScript-commit-newVersion} +[]{#var-passthru-updateScript-commit-files} +[]{#var-passthru-updateScript-commit-commitBody} +[]{#var-passthru-updateScript-commit-commitMessage} +[]{#var-passthru-updateScript-example-commit} + +Nixpkgs tries to automatically update all packages that have an `passthru.updateScript` attribute. +See the [section on automatic package updates in the package contributor guide](https://github.com/NixOS/nixpkgs/blob/master/pkgs/README.md#automatic-package-updates) for details. diff --git a/doc/stdenv/stdenv.chapter.md b/doc/stdenv/stdenv.chapter.md index f3cdb1f2dc0c0..400fa2de1e764 100644 --- a/doc/stdenv/stdenv.chapter.md +++ b/doc/stdenv/stdenv.chapter.md @@ -442,145 +442,6 @@ If set to `true`, `stdenv` will pass specific flags to `make` and other build to Unless set to `false`, some build systems with good support for parallel building including `cmake`, `meson`, and `qmake` will set it to `true`. -### Special variables {#special-variables} - -#### `passthru` {#var-stdenv-passthru} - -This is an attribute set which can be filled with arbitrary values. For example: - -```nix -{ - passthru = { - foo = "bar"; - baz = { - value1 = 4; - value2 = 5; - }; - }; -} -``` - -Values inside it are not passed to the builder, so you can change them without triggering a rebuild. However, they can be accessed outside of a derivation directly, as if they were set inside a derivation itself, e.g. `hello.baz.value1`. We don’t specify any usage or schema of `passthru` - it is meant for values that would be useful outside the derivation in other parts of a Nix expression (e.g. in other derivations). An example would be to convey some specific dependency of your derivation which contains a program with plugins support. Later, others who make derivations with plugins can use passed-through dependency to ensure that their plugin would be binary-compatible with built program. - -#### `passthru.updateScript` {#var-passthru-updateScript} - -A script to be run by `maintainers/scripts/update.nix` when the package is matched. The attribute can contain one of the following: - -- []{#var-passthru-updateScript-command} an executable file, either on the file system: - - ```nix - { - passthru.updateScript = ./update.sh; - } - ``` - - or inside the expression itself: - - ```nix - { - passthru.updateScript = writeScript "update-zoom-us" '' - #!/usr/bin/env nix-shell - #!nix-shell -i bash -p curl pcre2 common-updater-scripts - - set -eu -o pipefail - - version="$(curl -sI https://zoom.us/client/latest/zoom_x86_64.tar.xz | grep -Fi 'Location:' | pcre2grep -o1 '/(([0-9]\.?)+)/')" - update-source-version zoom-us "$version" - ''; - } - ``` - -- a list, a script followed by arguments to be passed to it: - - ```nix - { - passthru.updateScript = [ ../../update.sh pname "--requested-release=unstable" ]; - } - ``` - -- an attribute set containing: - - [`command`]{#var-passthru-updateScript-set-command} – a string or list in the [format expected by `passthru.updateScript`](#var-passthru-updateScript-command). - - [`attrPath`]{#var-passthru-updateScript-set-attrPath} (optional) – a string containing the canonical attribute path for the package. If present, it will be passed to the update script instead of the attribute path on which the package was discovered during Nixpkgs traversal. - - [`supportedFeatures`]{#var-passthru-updateScript-set-supportedFeatures} (optional) – a list of the [extra features](#var-passthru-updateScript-supported-features) the script supports. - - ```nix - { - passthru.updateScript = { - command = [ ../../update.sh pname ]; - attrPath = pname; - supportedFeatures = [ /* ... */ ]; - }; - } - ``` - -::: {.tip} -A common pattern is to use the [`nix-update-script`](https://github.com/NixOS/nixpkgs/blob/master/pkgs/common-updater/nix-update.nix) attribute provided in Nixpkgs, which runs [`nix-update`](https://github.com/Mic92/nix-update): - -```nix -{ - passthru.updateScript = nix-update-script { }; -} -``` - -For simple packages, this is often enough, and will ensure that the package is updated automatically by [`nixpkgs-update`](https://ryantm.github.io/nixpkgs-update) when a new version is released. The [update bot](https://nix-community.org/update-bot) runs periodically to attempt to automatically update packages, and will run `passthru.updateScript` if set. While not strictly necessary if the project is listed on [Repology](https://repology.org), using `nix-update-script` allows the package to update via many more sources (e.g. GitHub releases). -::: - -##### How update scripts are executed? {#var-passthru-updateScript-execution} - -Update scripts are to be invoked by `maintainers/scripts/update.nix` script. You can run `nix-shell maintainers/scripts/update.nix` in the root of Nixpkgs repository for information on how to use it. `update.nix` offers several modes for selecting packages to update (e.g. select by attribute path, traverse Nixpkgs and filter by maintainer, etc.), and it will execute update scripts for all matched packages that have an `updateScript` attribute. - -Each update script will be passed the following environment variables: - -- [`UPDATE_NIX_NAME`]{#var-passthru-updateScript-env-UPDATE_NIX_NAME} – content of the `name` attribute of the updated package. -- [`UPDATE_NIX_PNAME`]{#var-passthru-updateScript-env-UPDATE_NIX_PNAME} – content of the `pname` attribute of the updated package. -- [`UPDATE_NIX_OLD_VERSION`]{#var-passthru-updateScript-env-UPDATE_NIX_OLD_VERSION} – content of the `version` attribute of the updated package. -- [`UPDATE_NIX_ATTR_PATH`]{#var-passthru-updateScript-env-UPDATE_NIX_ATTR_PATH} – attribute path the `update.nix` discovered the package on (or the [canonical `attrPath`](#var-passthru-updateScript-set-attrPath) when available). Example: `pantheon.elementary-terminal` - -::: {.note} -An update script will be usually run from the root of the Nixpkgs repository but you should not rely on that. Also note that `update.nix` executes update scripts in parallel by default so you should avoid running `git commit` or any other commands that cannot handle that. -::: - -::: {.tip} -While update scripts should not create commits themselves, `maintainers/scripts/update.nix` supports automatically creating commits when running it with `--argstr commit true`. If you need to customize commit message, you can have the update script implement [`commit`](#var-passthru-updateScript-commit) feature. -::: - -##### Supported features {#var-passthru-updateScript-supported-features} -###### `commit` {#var-passthru-updateScript-commit} - -This feature allows update scripts to *ask* `update.nix` to create Git commits. - -When support of this feature is declared, whenever the update script exits with `0` return status, it is expected to print a JSON list containing an object described below for each updated attribute to standard output. - -When `update.nix` is run with `--argstr commit true` arguments, it will create a separate commit for each of the objects. An empty list can be returned when the script did not update any files, for example, when the package is already at the latest version. - -The commit object contains the following values: - -- [`attrPath`]{#var-passthru-updateScript-commit-attrPath} – a string containing attribute path. -- [`oldVersion`]{#var-passthru-updateScript-commit-oldVersion} – a string containing old version. -- [`newVersion`]{#var-passthru-updateScript-commit-newVersion} – a string containing new version. -- [`files`]{#var-passthru-updateScript-commit-files} – a non-empty list of file paths (as strings) to add to the commit. -- [`commitBody`]{#var-passthru-updateScript-commit-commitBody} (optional) – a string with extra content to be appended to the default commit message (useful for adding changelog links). -- [`commitMessage`]{#var-passthru-updateScript-commit-commitMessage} (optional) – a string to use instead of the default commit message. - -If the returned array contains exactly one object (e.g. `[{}]`), all values are optional and will be determined automatically. - -::: {.example #var-passthru-updateScript-example-commit} -# Standard output of an update script using commit feature - -```json -[ - { - "attrPath": "volume_key", - "oldVersion": "0.3.11", - "newVersion": "0.3.12", - "files": [ - "/path/to/nixpkgs/pkgs/development/libraries/volume-key/default.nix" - ] - } -] -``` -::: - ### Fixed-point arguments of `mkDerivation` {#mkderivation-recursive-attributes} If you pass a function to `mkDerivation`, it will receive as its argument the final arguments, including the overrides when reinvoked via `overrideAttrs`. For example: @@ -633,7 +494,7 @@ in pkg Unlike the `pkg` binding in the above example, the `finalAttrs` parameter always references the final attributes. For instance `(pkg.overrideAttrs(x)).finalAttrs.finalPackage` is identical to `pkg.overrideAttrs(x)`, whereas `(pkg.overrideAttrs(x)).original` is the same as the original `pkg`. -See also the section about [`passthru.tests`](#var-meta-tests). +See also the section about [`passthru.tests`](#var-passthru-tests). ## Phases {#sec-stdenv-phases} @@ -1145,7 +1006,7 @@ This setup works as follows: The installCheck phase checks whether the package was installed correctly by running its test suite against the installed directories. The default `installCheck` calls `make installcheck`. It is often better to add tests that are not part of the source distribution to `passthru.tests` (see -[](#var-meta-tests)). This avoids adding overhead to every build and enables us to run them independently. +[](#var-passthru-tests)). This avoids adding overhead to every build and enables us to run them independently. #### Variables controlling the installCheck phase {#variables-controlling-the-installcheck-phase} @@ -1558,6 +1419,8 @@ Both parameters take a list of flags as strings. The special `"all"` flag can be For more in-depth information on these hardening flags and hardening in general, refer to the [Debian Wiki](https://wiki.debian.org/Hardening), [Ubuntu Wiki](https://wiki.ubuntu.com/Security/Features), [Gentoo Wiki](https://wiki.gentoo.org/wiki/Project:Hardened), and the [Arch Wiki](https://wiki.archlinux.org/title/Security). +Note that support for some hardening flags varies by compiler, CPU architecture, target OS and libc. Combinations of these that don't support a particular hardening flag will silently ignore attempts to enable it. To see exactly which hardening flags are being employed in any invocation, the `NIX_DEBUG` environment variable can be used. + ### Hardening flags enabled by default {#sec-hardening-flags-enabled-by-default} The following flags are enabled by default and might require disabling with `hardeningDisable` if the program to package is incompatible. @@ -1607,6 +1470,16 @@ installwatch.c:3751:5: error: conflicting types for '__open_2' fcntl2.h:50:4: error: call to '__open_missing_mode' declared with attribute error: open with O_CREAT or O_TMPFILE in second argument needs 3 arguments ``` +Disabling `fortify` implies disablement of `fortify3` + +#### `fortify3` {#fortify3} + +Adds the `-O2 -D_FORTIFY_SOURCE=3` compiler options. This expands the cases that can be protected by fortify-checks to include some situations with dynamic-length buffers whose length can be inferred at runtime using compiler hints. + +Enabling this flag implies enablement of `fortify`. Disabling this flag does not imply disablement of `fortify`. + +This flag can sometimes conflict with a build-system's own attempts at enabling fortify support and result in errors complaining about `redefinition of _FORTIFY_SOURCE`. + #### `pic` {#pic} Adds the `-fPIC` compiler options. This options adds support for position independent code in shared libraries and thus making ASLR possible. @@ -1655,6 +1528,16 @@ Adds the `-fPIE` compiler and `-pie` linker options. Position Independent Execut Static libraries need to be compiled with `-fPIE` so that executables can link them in with the `-pie` linker option. If the libraries lack `-fPIE`, you will get the error `recompile with -fPIE`. +#### `zerocallusedregs` {#zerocallusedregs} + +Adds the `-fzero-call-used-regs=used-gpr` compiler option. This causes the general-purpose registers that an architecture's calling convention considers "call-used" to be zeroed on return from the function. This can make it harder for attackers to construct useful ROP gadgets and also reduces the chance of data leakage from a function call. + +#### `trivialautovarinit` {#trivialautovarinit} + +Adds the `-ftrivial-auto-var-init=pattern` compiler option. This causes "trivially-initializable" uninitialized stack variables to be forcibly initialized with a nonzero value that is likely to cause a crash (and therefore be noticed). Uninitialized variables generally take on their values based on fragments of previous program state, and attackers can carefully manipulate that state to craft malicious initial values for these variables. + +Use of this flag is controversial as it can prevent tools that detect uninitialized variable use (such as valgrind) from operating correctly. + [^footnote-stdenv-ignored-build-platform]: The build platform is ignored because it is a mere implementation detail of the package satisfying the dependency: As a general programming principle, dependencies are always *specified* as interfaces, not concrete implementation. [^footnote-stdenv-native-dependencies-in-path]: Currently, this means for native builds all dependencies are put on the `PATH`. But in the future that may not be the case for sake of matching cross: the platforms would be assumed to be unique for native and cross builds alike, so only the `depsBuild*` and `nativeBuildInputs` would be added to the `PATH`. [^footnote-stdenv-propagated-dependencies]: Nix itself already takes a package’s transitive dependencies into account, but this propagation ensures nixpkgs-specific infrastructure like [setup hooks](#ssec-setup-hooks) also are run as if it were a propagated dependency. diff --git a/doc/style.css b/doc/style.css index 5bc587a6ee308..f517733be9727 100644 --- a/doc/style.css +++ b/doc/style.css @@ -431,6 +431,11 @@ div.appendix .informaltable td { padding: 0.5rem; } +div.book .variablelist .term, +div.appendix .variablelist .term { + font-weight: 500; +} + /* This relies on highlight.js applying certain classes on the prompts. For more details, see https://highlightjs.readthedocs.io/en/latest/css-classes-reference.html#stylable-scopes diff --git a/flake.nix b/flake.nix index d920d5d0dddab..8df05dc91263f 100644 --- a/flake.nix +++ b/flake.nix @@ -5,14 +5,15 @@ outputs = { self }: let - jobs = import ./pkgs/top-level/release.nix { - nixpkgs = self; - }; - libVersionInfoOverlay = import ./lib/flake-version-info.nix self; lib = (import ./lib).extend libVersionInfoOverlay; forAllSystems = lib.genAttrs lib.systems.flakeExposed; + + jobs = forAllSystems (system: import ./pkgs/top-level/release.nix { + nixpkgs = self; + inherit system; + }); in { lib = lib.extend (final: prev: { @@ -43,12 +44,14 @@ ); }); - checks.x86_64-linux = { - tarball = jobs.tarball; + checks = forAllSystems (system: { + tarball = jobs.${system}.tarball; + } // lib.optionalAttrs (self.legacyPackages.${system}.stdenv.isLinux) { # Test that ensures that the nixosSystem function can accept a lib argument # Note: prefer not to extend or modify `lib`, especially if you want to share reusable modules # alternatives include: `import` a file, or put a custom library in an option or in `_module.args.` nixosSystemAcceptsLib = (self.lib.nixosSystem { + pkgs = self.legacyPackages.${system}; lib = self.lib.extend (final: prev: { ifThisFunctionIsMissingTheTestFails = final.id; }); @@ -64,13 +67,13 @@ }) ]; }).config.system.build.toplevel; - }; + }); htmlDocs = { - nixpkgsManual = jobs.manual; + nixpkgsManual = builtins.mapAttrs (_: jobSet: jobSet.manual) jobs; nixosManual = (import ./nixos/release-small.nix { nixpkgs = self; - }).nixos.manual.x86_64-linux; + }).nixos.manual; }; # The "legacy" in `legacyPackages` doesn't imply that the packages exposed diff --git a/lib/.version b/lib/.version index 420f61e8c7f66..cd158b7c510bd 100644 --- a/lib/.version +++ b/lib/.version @@ -1 +1 @@ -24.05 \ No newline at end of file +24.11 \ No newline at end of file diff --git a/lib/cli.nix b/lib/cli.nix index fcffacb5ea996..311037c519a65 100644 --- a/lib/cli.nix +++ b/lib/cli.nix @@ -90,7 +90,16 @@ rec { mkOption ? k: v: if v == null then [] - else [ (mkOptionName k) (lib.generators.mkValueStringDefault {} v) ] + else if optionValueSeparator == null then + [ (mkOptionName k) (lib.generators.mkValueStringDefault {} v) ] + else + [ "${mkOptionName k}${optionValueSeparator}${lib.generators.mkValueStringDefault {} v}" ], + + # how to separate an option from its flag; + # by default, there is no separator, so option `-c` and value `5` + # would become ["-c" "5"]. + # This is useful if the command requires equals, for example, `-c=5`. + optionValueSeparator ? null }: options: let diff --git a/lib/debug.nix b/lib/debug.nix index 97e87acccf0ef..b10023d02616c 100644 --- a/lib/debug.nix +++ b/lib/debug.nix @@ -1,16 +1,17 @@ -/* Collection of functions useful for debugging - broken nix expressions. - - * `trace`-like functions take two values, print - the first to stderr and return the second. - * `traceVal`-like functions take one argument - which both printed and returned. - * `traceSeq`-like functions fully evaluate their - traced value before printing (not just to “weak - head normal form” like trace does by default). - * Functions that end in `-Fn` take an additional - function as their first argument, which is applied - to the traced value before it is printed. +/** + Collection of functions useful for debugging + broken nix expressions. + + * `trace`-like functions take two values, print + the first to stderr and return the second. + * `traceVal`-like functions take one argument + which both printed and returned. + * `traceSeq`-like functions fully evaluate their + traced value before printing (not just to “weak + head normal form” like trace does by default). + * Functions that end in `-Fn` take an additional + function as their first argument, which is applied + to the traced value before it is printed. */ { lib }: let @@ -32,79 +33,190 @@ rec { # -- TRACING -- - /* Conditionally trace the supplied message, based on a predicate. + /** + Conditionally trace the supplied message, based on a predicate. - Type: traceIf :: bool -> string -> a -> a - Example: - traceIf true "hello" 3 - trace: hello - => 3 + # Inputs + + `pred` + + : Predicate to check + + `msg` + + : Message that should be traced + + `x` + + : Value to return + + # Type + + ``` + traceIf :: bool -> string -> a -> a + ``` + + # Examples + :::{.example} + ## `lib.debug.traceIf` usage example + + ```nix + traceIf true "hello" 3 + trace: hello + => 3 + ``` + + ::: */ traceIf = - # Predicate to check pred: - # Message that should be traced msg: - # Value to return x: if pred then trace msg x else x; - /* Trace the supplied value after applying a function to it, and - return the original value. + /** + Trace the supplied value after applying a function to it, and + return the original value. + + + # Inputs + + `f` - Type: traceValFn :: (a -> b) -> a -> a + : Function to apply - Example: - traceValFn (v: "mystring ${v}") "foo" - trace: mystring foo - => "foo" + `x` + + : Value to trace and return + + # Type + + ``` + traceValFn :: (a -> b) -> a -> a + ``` + + # Examples + :::{.example} + ## `lib.debug.traceValFn` usage example + + ```nix + traceValFn (v: "mystring ${v}") "foo" + trace: mystring foo + => "foo" + ``` + + ::: */ traceValFn = - # Function to apply f: - # Value to trace and return x: trace (f x) x; - /* Trace the supplied value and return it. + /** + Trace the supplied value and return it. + + # Inputs - Type: traceVal :: a -> a + `x` - Example: - traceVal 42 - # trace: 42 - => 42 + : Value to trace and return + + # Type + + ``` + traceVal :: a -> a + ``` + + # Examples + :::{.example} + ## `lib.debug.traceVal` usage example + + ```nix + traceVal 42 + # trace: 42 + => 42 + ``` + + ::: */ traceVal = traceValFn id; - /* `builtins.trace`, but the value is `builtins.deepSeq`ed first. + /** + `builtins.trace`, but the value is `builtins.deepSeq`ed first. + + + # Inputs - Type: traceSeq :: a -> b -> b + `x` - Example: - trace { a.b.c = 3; } null - trace: { a = ; } - => null - traceSeq { a.b.c = 3; } null - trace: { a = { b = { c = 3; }; }; } - => null + : The value to trace + + `y` + + : The value to return + + # Type + + ``` + traceSeq :: a -> b -> b + ``` + + # Examples + :::{.example} + ## `lib.debug.traceSeq` usage example + + ```nix + trace { a.b.c = 3; } null + trace: { a = ; } + => null + traceSeq { a.b.c = 3; } null + trace: { a = { b = { c = 3; }; }; } + => null + ``` + + ::: */ traceSeq = - # The value to trace x: - # The value to return y: trace (builtins.deepSeq x x) y; - /* Like `traceSeq`, but only evaluate down to depth n. - This is very useful because lots of `traceSeq` usages - lead to an infinite recursion. + /** + Like `traceSeq`, but only evaluate down to depth n. + This is very useful because lots of `traceSeq` usages + lead to an infinite recursion. + + + # Inputs + + `depth` + + : 1\. Function argument + + `x` + + : 2\. Function argument + + `y` - Example: - traceSeqN 2 { a.b.c = 3; } null - trace: { a = { b = {…}; }; } - => null + : 3\. Function argument - Type: traceSeqN :: Int -> a -> b -> b - */ + # Type + + ``` + traceSeqN :: Int -> a -> b -> b + ``` + + # Examples + :::{.example} + ## `lib.debug.traceSeqN` usage example + + ```nix + traceSeqN 2 { a.b.c = 3; } null + trace: { a = { b = {…}; }; } + => null + ``` + + ::: + */ traceSeqN = depth: x: y: let snip = v: if isList v then noQuotes "[…]" v else if isAttrs v then noQuotes "{…}" v @@ -118,41 +230,115 @@ rec { in trace (generators.toPretty { allowPrettyValues = true; } (modify depth snip x)) y; - /* A combination of `traceVal` and `traceSeq` that applies a - provided function to the value to be traced after `deepSeq`ing - it. + /** + A combination of `traceVal` and `traceSeq` that applies a + provided function to the value to be traced after `deepSeq`ing + it. + + + # Inputs + + `f` + + : Function to apply + + `v` + + : Value to trace */ traceValSeqFn = - # Function to apply f: - # Value to trace v: traceValFn f (builtins.deepSeq v v); - /* A combination of `traceVal` and `traceSeq`. */ + /** + A combination of `traceVal` and `traceSeq`. + + # Inputs + + `v` + + : Value to trace + + */ traceValSeq = traceValSeqFn id; - /* A combination of `traceVal` and `traceSeqN` that applies a - provided function to the value to be traced. */ + /** + A combination of `traceVal` and `traceSeqN` that applies a + provided function to the value to be traced. + + + # Inputs + + `f` + + : Function to apply + + `depth` + + : 2\. Function argument + + `v` + + : Value to trace + */ traceValSeqNFn = - # Function to apply f: depth: - # Value to trace v: traceSeqN depth (f v) v; - /* A combination of `traceVal` and `traceSeqN`. */ + /** + A combination of `traceVal` and `traceSeqN`. + + # Inputs + + `depth` + + : 1\. Function argument + + `v` + + : Value to trace + */ traceValSeqN = traceValSeqNFn id; - /* Trace the input and output of a function `f` named `name`, - both down to `depth`. + /** + Trace the input and output of a function `f` named `name`, + both down to `depth`. + + This is useful for adding around a function call, + to see the before/after of values as they are transformed. + + + # Inputs + + `depth` + + : 1\. Function argument + + `name` + + : 2\. Function argument + + `f` + + : 3\. Function argument - This is useful for adding around a function call, - to see the before/after of values as they are transformed. + `v` - Example: - traceFnSeqN 2 "id" (x: x) { a.b.c = 3; } - trace: { fn = "id"; from = { a.b = {…}; }; to = { a.b = {…}; }; } - => { a.b.c = 3; } + : 4\. Function argument + + + # Examples + :::{.example} + ## `lib.debug.traceFnSeqN` usage example + + ```nix + traceFnSeqN 2 "id" (x: x) { a.b.c = 3; } + trace: { fn = "id"; from = { a.b = {…}; }; to = { a.b = {…}; }; } + => { a.b.c = 3; } + ``` + + ::: */ traceFnSeqN = depth: name: f: v: let res = f v; @@ -168,66 +354,82 @@ rec { # -- TESTING -- - /* Evaluates a set of tests. - - A test is an attribute set `{expr, expected}`, - denoting an expression and its expected result. - - The result is a `list` of __failed tests__, each represented as - `{name, expected, result}`, - - - expected - - What was passed as `expected` - - result - - The actual `result` of the test - - Used for regression testing of the functions in lib; see - tests.nix for more examples. - - Important: Only attributes that start with `test` are executed. - - - If you want to run only a subset of the tests add the attribute `tests = ["testName"];` - - Example: - - runTests { - testAndOk = { - expr = lib.and true false; - expected = false; - }; - testAndFail = { - expr = lib.and true false; - expected = true; - }; - } - -> - [ - { - name = "testAndFail"; - expected = true; - result = false; - } - ] - - Type: - runTests :: { - tests = [ String ]; - ${testName} :: { - expr :: a; - expected :: a; - }; + /** + Evaluates a set of tests. + + A test is an attribute set `{expr, expected}`, + denoting an expression and its expected result. + + The result is a `list` of __failed tests__, each represented as + `{name, expected, result}`, + + - expected + - What was passed as `expected` + - result + - The actual `result` of the test + + Used for regression testing of the functions in lib; see + tests.nix for more examples. + + Important: Only attributes that start with `test` are executed. + + - If you want to run only a subset of the tests add the attribute `tests = ["testName"];` + + + # Inputs + + `tests` + + : Tests to run + + # Type + + ``` + runTests :: { + tests = [ String ]; + ${testName} :: { + expr :: a; + expected :: a; + }; + } + -> + [ + { + name :: String; + expected :: a; + result :: a; } - -> - [ - { - name :: String; - expected :: a; - result :: a; - } - ] + ] + ``` + + # Examples + :::{.example} + ## `lib.debug.runTests` usage example + + ```nix + runTests { + testAndOk = { + expr = lib.and true false; + expected = false; + }; + testAndFail = { + expr = lib.and true false; + expected = true; + }; + } + -> + [ + { + name = "testAndFail"; + expected = true; + result = false; + } + ] + ``` + + ::: */ runTests = - # Tests to run tests: concatLists (attrValues (mapAttrs (name: test: let testsToRun = if tests ? tests then tests.tests else []; in if (substring 0 4 name == "test" || elem name testsToRun) @@ -237,10 +439,26 @@ rec { then [ { inherit name; expected = test.expected; result = test.expr; } ] else [] ) tests)); - /* Create a test assuming that list elements are `true`. + /** + Create a test assuming that list elements are `true`. + + + # Inputs + + `expr` + + : 1\. Function argument + + + # Examples + :::{.example} + ## `lib.debug.testAllTrue` usage example + + ```nix + { testX = allTrue [ true ]; } + ``` - Example: - { testX = allTrue [ true ]; } + ::: */ testAllTrue = expr: { inherit expr; expected = map (x: true) expr; }; } diff --git a/lib/fileset/default.nix b/lib/fileset/default.nix index e29f30251c690..bb327226731ee 100644 --- a/lib/fileset/default.nix +++ b/lib/fileset/default.nix @@ -1,4 +1,4 @@ -/* +/** []{#sec-fileset} @@ -6,7 +6,7 @@ A file set is a (mathematical) set of local files that can be added to the Nix store for use in Nix derivations. File sets are easy and safe to use, providing obvious and composable semantics with good error messages to prevent mistakes. - ## Overview {#sec-fileset-overview} + # Overview {#sec-fileset-overview} Basics: - [Implicit coercion from paths to file sets](#sec-fileset-path-coercion) @@ -58,7 +58,7 @@ see [this issue](https://github.com/NixOS/nixpkgs/issues/266356) to request it. - ## Implicit coercion from paths to file sets {#sec-fileset-path-coercion} + # Implicit coercion from paths to file sets {#sec-fileset-path-coercion} All functions accepting file sets as arguments can also accept [paths](https://nixos.org/manual/nix/stable/language/values.html#type-path) as arguments. Such path arguments are implicitly coerced to file sets containing all files under that path: @@ -78,7 +78,7 @@ This is in contrast to using [paths in string interpolation](https://nixos.org/manual/nix/stable/language/values.html#type-path), which does add the entire referenced path to the store. ::: - ### Example {#sec-fileset-path-coercion-example} + ## Example {#sec-fileset-path-coercion-example} Assume we are in a local directory with a file hierarchy like this: ``` @@ -157,17 +157,34 @@ let in { - /* + /** Create a file set from a path that may or may not exist: - If the path does exist, the path is [coerced to a file set](#sec-fileset-path-coercion). - If the path does not exist, a file set containing no files is returned. - Type: - maybeMissing :: Path -> FileSet - Example: - # All files in the current directory, but excluding main.o if it exists - difference ./. (maybeMissing ./main.o) + # Inputs + + `path` + + : 1\. Function argument + + # Type + + ``` + maybeMissing :: Path -> FileSet + ``` + + # Examples + :::{.example} + ## `lib.fileset.maybeMissing` usage example + + ```nix + # All files in the current directory, but excluding main.o if it exists + difference ./. (maybeMissing ./main.o) + ``` + + ::: */ maybeMissing = path: @@ -183,7 +200,7 @@ in { else _singleton path; - /* + /** Incrementally evaluate and trace a file set in a pretty way. This function is only intended for debugging purposes. The exact tracing format is unspecified and may change. @@ -194,27 +211,44 @@ in { This variant is useful for tracing file sets in the Nix repl. - Type: - trace :: FileSet -> Any -> Any - - Example: - trace (unions [ ./Makefile ./src ./tests/run.sh ]) null - => - trace: /home/user/src/myProject - trace: - Makefile (regular) - trace: - src (all files in directory) - trace: - tests - trace: - run.sh (regular) - null + + # Inputs + + `fileset` + + : The file set to trace. + + This argument can also be a path, + which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). + + `val` + + : The value to return. + + # Type + + ``` + trace :: FileSet -> Any -> Any + ``` + + # Examples + :::{.example} + ## `lib.fileset.trace` usage example + + ```nix + trace (unions [ ./Makefile ./src ./tests/run.sh ]) null + => + trace: /home/user/src/myProject + trace: - Makefile (regular) + trace: - src (all files in directory) + trace: - tests + trace: - run.sh (regular) + null + ``` + + ::: */ - trace = - /* - The file set to trace. - - This argument can also be a path, - which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). - */ - fileset: + trace = fileset: let # "fileset" would be a better name, but that would clash with the argument name, # and we cannot change that because of https://github.com/nix-community/nixdoc/issues/76 @@ -224,7 +258,7 @@ in { (_printFileset actualFileset) (x: x); - /* + /** Incrementally evaluate and trace a file set in a pretty way. This function is only intended for debugging purposes. The exact tracing format is unspecified and may change. @@ -234,34 +268,47 @@ in { This variant is useful for tracing file sets passed as arguments to other functions. - Type: - traceVal :: FileSet -> FileSet - - Example: - toSource { - root = ./.; - fileset = traceVal (unions [ - ./Makefile - ./src - ./tests/run.sh - ]); - } - => - trace: /home/user/src/myProject - trace: - Makefile (regular) - trace: - src (all files in directory) - trace: - tests - trace: - run.sh (regular) - "/nix/store/...-source" + + # Inputs + + `fileset` + + : The file set to trace and return. + + This argument can also be a path, + which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). + + # Type + + ``` + traceVal :: FileSet -> FileSet + ``` + + # Examples + :::{.example} + ## `lib.fileset.traceVal` usage example + + ```nix + toSource { + root = ./.; + fileset = traceVal (unions [ + ./Makefile + ./src + ./tests/run.sh + ]); + } + => + trace: /home/user/src/myProject + trace: - Makefile (regular) + trace: - src (all files in directory) + trace: - tests + trace: - run.sh (regular) + "/nix/store/...-source" + ``` + + ::: */ - traceVal = - /* - The file set to trace and return. - - This argument can also be a path, - which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). - */ - fileset: + traceVal = fileset: let # "fileset" would be a better name, but that would clash with the argument name, # and we cannot change that because of https://github.com/nix-community/nixdoc/issues/76 @@ -273,7 +320,7 @@ in { # but that would then duplicate work for consumers of the fileset, because then they have to coerce it again actualFileset; - /* + /** Add the local files contained in `fileset` to the store as a single [store path](https://nixos.org/manual/nix/stable/glossary#gloss-store-path) rooted at `root`. The result is the store path as a string-like value, making it usable e.g. as the `src` of a derivation, or in string interpolation: @@ -286,63 +333,13 @@ in { The name of the store path is always `source`. - Type: - toSource :: { - root :: Path, - fileset :: FileSet, - } -> SourceLike - - Example: - # Import the current directory into the store - # but only include files under ./src - toSource { - root = ./.; - fileset = ./src; - } - => "/nix/store/...-source" - - # Import the current directory into the store - # but only include ./Makefile and all files under ./src - toSource { - root = ./.; - fileset = union - ./Makefile - ./src; - } - => "/nix/store/...-source" - - # Trying to include a file outside the root will fail - toSource { - root = ./.; - fileset = unions [ - ./Makefile - ./src - ../LICENSE - ]; - } - => - - # The root needs to point to a directory that contains all the files - toSource { - root = ../.; - fileset = unions [ - ./Makefile - ./src - ../LICENSE - ]; - } - => "/nix/store/...-source" - - # The root has to be a local filesystem path - toSource { - root = "/nix/store/...-source"; - fileset = ./.; - } - => - */ - toSource = { - /* - (required) The local directory [path](https://nixos.org/manual/nix/stable/language/values.html#type-path) that will correspond to the root of the resulting store path. + # Inputs + + Takes an attribute set with the following attributes + + `root` (Path; _required_) + + : The local directory [path](https://nixos.org/manual/nix/stable/language/values.html#type-path) that will correspond to the root of the resulting store path. Paths in [strings](https://nixos.org/manual/nix/stable/language/values.html#type-string), including Nix store paths, cannot be passed as `root`. `root` has to be a directory. @@ -350,10 +347,10 @@ in { Changing `root` only affects the directory structure of the resulting store path, it does not change which files are added to the store. The only way to change which files get added to the store is by changing the `fileset` attribute. ::: - */ - root, - /* - (required) The file set whose files to import into the store. + + `fileset` (FileSet; _required_) + + : The file set whose files to import into the store. File sets can be created using other functions in this library. This argument can also be a path, which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). @@ -362,7 +359,72 @@ in { If a directory does not recursively contain any file, it is omitted from the store path contents. ::: - */ + # Type + + ``` + toSource :: { + root :: Path, + fileset :: FileSet, + } -> SourceLike + ``` + + # Examples + :::{.example} + ## `lib.fileset.toSource` usage example + + ```nix + # Import the current directory into the store + # but only include files under ./src + toSource { + root = ./.; + fileset = ./src; + } + => "/nix/store/...-source" + + # Import the current directory into the store + # but only include ./Makefile and all files under ./src + toSource { + root = ./.; + fileset = union + ./Makefile + ./src; + } + => "/nix/store/...-source" + + # Trying to include a file outside the root will fail + toSource { + root = ./.; + fileset = unions [ + ./Makefile + ./src + ../LICENSE + ]; + } + => + + # The root needs to point to a directory that contains all the files + toSource { + root = ../.; + fileset = unions [ + ./Makefile + ./src + ../LICENSE + ]; + } + => "/nix/store/...-source" + + # The root has to be a local filesystem path + toSource { + root = "/nix/store/...-source"; + fileset = ./.; + } + => + ``` + + ::: + */ + toSource = { + root, fileset, }: let @@ -418,7 +480,7 @@ in { }; - /* + /** The list of file paths contained in the given file set. :::{.note} @@ -432,24 +494,37 @@ in { The resulting list of files can be turned back into a file set using [`lib.fileset.unions`](#function-library-lib.fileset.unions). - Type: - toList :: FileSet -> [ Path ] - Example: - toList ./. - [ ./README.md ./Makefile ./src/main.c ./src/main.h ] + # Inputs + + `fileset` + + : The file set whose file paths to return. This argument can also be a path, which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). + + # Type + + ``` + toList :: FileSet -> [ Path ] + ``` - toList (difference ./. ./src) - [ ./README.md ./Makefile ] + # Examples + :::{.example} + ## `lib.fileset.toList` usage example + + ```nix + toList ./. + [ ./README.md ./Makefile ./src/main.c ./src/main.h ] + + toList (difference ./. ./src) + [ ./README.md ./Makefile ] + ``` + + ::: */ - toList = - # The file set whose file paths to return. - # This argument can also be a path, - # which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). - fileset: + toList = fileset: _toList (_coerce "lib.fileset.toList: Argument" fileset); - /* + /** The file set containing all files that are in either of two given file sets. This is the same as [`unions`](#function-library-lib.fileset.unions), but takes just two file sets instead of a list. @@ -458,26 +533,41 @@ in { The given file sets are evaluated as lazily as possible, with the first argument being evaluated first if needed. - Type: - union :: FileSet -> FileSet -> FileSet - Example: - # Create a file set containing the file `Makefile` - # and all files recursively in the `src` directory - union ./Makefile ./src + # Inputs + + `fileset1` + + : The first file set. This argument can also be a path, which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). + + `fileset2` + + : The second file set. This argument can also be a path, which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). + + # Type + + ``` + union :: FileSet -> FileSet -> FileSet + ``` - # Create a file set containing the file `Makefile` - # and the LICENSE file from the parent directory - union ./Makefile ../LICENSE + # Examples + :::{.example} + ## `lib.fileset.union` usage example + + ```nix + # Create a file set containing the file `Makefile` + # and all files recursively in the `src` directory + union ./Makefile ./src + + # Create a file set containing the file `Makefile` + # and the LICENSE file from the parent directory + union ./Makefile ../LICENSE + ``` + + ::: */ union = - # The first file set. - # This argument can also be a path, - # which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). fileset1: - # The second file set. - # This argument can also be a path, - # which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). fileset2: _unionMany (_coerceMany "lib.fileset.union" [ @@ -491,7 +581,7 @@ in { } ]); - /* + /** The file set containing all files that are in any of the given file sets. This is the same as [`union`](#function-library-lib.fileset.unions), but takes a list of file sets instead of just two. @@ -500,32 +590,46 @@ in { The given file sets are evaluated as lazily as possible, with earlier elements being evaluated first if needed. - Type: - unions :: [ FileSet ] -> FileSet - Example: - # Create a file set containing selected files - unions [ - # Include the single file `Makefile` in the current directory - # This errors if the file doesn't exist - ./Makefile + # Inputs - # Recursively include all files in the `src/code` directory - # If this directory is empty this has no effect - ./src/code + `filesets` - # Include the files `run.sh` and `unit.c` from the `tests` directory - ./tests/run.sh - ./tests/unit.c + : A list of file sets. The elements can also be paths, which get [implicitly coerced to file sets](#sec-fileset-path-coercion). - # Include the `LICENSE` file from the parent directory - ../LICENSE - ] + # Type + + ``` + unions :: [ FileSet ] -> FileSet + ``` + + # Examples + :::{.example} + ## `lib.fileset.unions` usage example + + ```nix + # Create a file set containing selected files + unions [ + # Include the single file `Makefile` in the current directory + # This errors if the file doesn't exist + ./Makefile + + # Recursively include all files in the `src/code` directory + # If this directory is empty this has no effect + ./src/code + + # Include the files `run.sh` and `unit.c` from the `tests` directory + ./tests/run.sh + ./tests/unit.c + + # Include the `LICENSE` file from the parent directory + ../LICENSE + ] + ``` + + ::: */ unions = - # A list of file sets. - # The elements can also be paths, - # which get [implicitly coerced to file sets](#sec-fileset-path-coercion). filesets: if ! isList filesets then throw '' @@ -541,28 +645,43 @@ in { _unionMany ]; - /* + /** The file set containing all files that are in both of two given file sets. See also [Intersection (set theory)](https://en.wikipedia.org/wiki/Intersection_(set_theory)). The given file sets are evaluated as lazily as possible, with the first argument being evaluated first if needed. - Type: - intersection :: FileSet -> FileSet -> FileSet - Example: - # Limit the selected files to the ones in ./., so only ./src and ./Makefile - intersection ./. (unions [ ../LICENSE ./src ./Makefile ]) + # Inputs + + `fileset1` + + : The first file set. This argument can also be a path, which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). + + `fileset2` + + : The second file set. This argument can also be a path, which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). + + # Type + + ``` + intersection :: FileSet -> FileSet -> FileSet + ``` + + # Examples + :::{.example} + ## `lib.fileset.intersection` usage example + + ```nix + # Limit the selected files to the ones in ./., so only ./src and ./Makefile + intersection ./. (unions [ ../LICENSE ./src ./Makefile ]) + ``` + + ::: */ intersection = - # The first file set. - # This argument can also be a path, - # which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). fileset1: - # The second file set. - # This argument can also be a path, - # which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). fileset2: let filesets = _coerceMany "lib.fileset.intersection" [ @@ -580,41 +699,52 @@ in { (elemAt filesets 0) (elemAt filesets 1); - /* + /** The file set containing all files from the first file set that are not in the second file set. See also [Difference (set theory)](https://en.wikipedia.org/wiki/Complement_(set_theory)#Relative_complement). The given file sets are evaluated as lazily as possible, with the first argument being evaluated first if needed. - Type: - union :: FileSet -> FileSet -> FileSet - - Example: - # Create a file set containing all files from the current directory, - # except ones under ./tests - difference ./. ./tests - - let - # A set of Nix-related files - nixFiles = unions [ ./default.nix ./nix ./tests/default.nix ]; - in - # Create a file set containing all files under ./tests, except ones in `nixFiles`, - # meaning only without ./tests/default.nix - difference ./tests nixFiles + + # Inputs + + `positive` + + : The positive file set. The result can only contain files that are also in this file set. This argument can also be a path, which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). + + `negative` + + : The negative file set. The result will never contain files that are also in this file set. This argument can also be a path, which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). + + # Type + + ``` + union :: FileSet -> FileSet -> FileSet + ``` + + # Examples + :::{.example} + ## `lib.fileset.difference` usage example + + ```nix + # Create a file set containing all files from the current directory, + # except ones under ./tests + difference ./. ./tests + + let + # A set of Nix-related files + nixFiles = unions [ ./default.nix ./nix ./tests/default.nix ]; + in + # Create a file set containing all files under ./tests, except ones in `nixFiles`, + # meaning only without ./tests/default.nix + difference ./tests nixFiles + ``` + + ::: */ difference = - # The positive file set. - # The result can only contain files that are also in this file set. - # - # This argument can also be a path, - # which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). positive: - # The negative file set. - # The result will never contain files that are also in this file set. - # - # This argument can also be a path, - # which gets [implicitly coerced to a file set](#sec-fileset-path-coercion). negative: let filesets = _coerceMany "lib.fileset.difference" [ @@ -632,36 +762,15 @@ in { (elemAt filesets 0) (elemAt filesets 1); - /* + /** Filter a file set to only contain files matching some predicate. - Type: - fileFilter :: - ({ - name :: String, - type :: String, - hasExt :: String -> Bool, - ... - } -> Bool) - -> Path - -> FileSet - - Example: - # Include all regular `default.nix` files in the current directory - fileFilter (file: file.name == "default.nix") ./. - - # Include all non-Nix files from the current directory - fileFilter (file: ! file.hasExt "nix") ./. - - # Include all files that start with a "." in the current directory - fileFilter (file: hasPrefix "." file.name) ./. - - # Include all regular files (not symlinks or others) in the current directory - fileFilter (file: file.type == "regular") ./. - */ - fileFilter = - /* - The predicate function to call on all files contained in given file set. + + # Inputs + + `predicate` + + : The predicate function to call on all files contained in given file set. A file is included in the resulting file set if this function returns true for it. This function is called with an attribute set containing these attributes: @@ -678,9 +787,47 @@ in { `hasExt "gitignore"` is true. Other attributes may be added in the future. - */ + + `path` + + : The path whose files to filter + + # Type + + ``` + fileFilter :: + ({ + name :: String, + type :: String, + hasExt :: String -> Bool, + ... + } -> Bool) + -> Path + -> FileSet + ``` + + # Examples + :::{.example} + ## `lib.fileset.fileFilter` usage example + + ```nix + # Include all regular `default.nix` files in the current directory + fileFilter (file: file.name == "default.nix") ./. + + # Include all non-Nix files from the current directory + fileFilter (file: ! file.hasExt "nix") ./. + + # Include all files that start with a "." in the current directory + fileFilter (file: hasPrefix "." file.name) ./. + + # Include all regular files (not symlinks or others) in the current directory + fileFilter (file: file.type == "regular") ./. + ``` + + ::: + */ + fileFilter = predicate: - # The path whose files to filter path: if ! isFunction predicate then throw '' @@ -699,23 +846,37 @@ in { else _fileFilter predicate path; - /* - Create a file set with the same files as a `lib.sources`-based value. - This does not import any of the files into the store. + /** + Create a file set with the same files as a `lib.sources`-based value. + This does not import any of the files into the store. - This can be used to gradually migrate from `lib.sources`-based filtering to `lib.fileset`. + This can be used to gradually migrate from `lib.sources`-based filtering to `lib.fileset`. - A file set can be turned back into a source using [`toSource`](#function-library-lib.fileset.toSource). + A file set can be turned back into a source using [`toSource`](#function-library-lib.fileset.toSource). - :::{.note} - File sets cannot represent empty directories. - Turning the result of this function back into a source using `toSource` will therefore not preserve empty directories. - ::: + :::{.note} + File sets cannot represent empty directories. + Turning the result of this function back into a source using `toSource` will therefore not preserve empty directories. + ::: + + + # Inputs - Type: + `source` + + : 1\. Function argument + + # Type + + ``` fromSource :: SourceLike -> FileSet + ``` + + # Examples + :::{.example} + ## `lib.fileset.fromSource` usage example - Example: + ```nix # There's no cleanSource-like function for file sets yet, # but we can just convert cleanSource to a file set and use it that way toSource { @@ -740,6 +901,9 @@ in { ./Makefile ./src ]); + ``` + + ::: */ fromSource = source: let @@ -768,27 +932,41 @@ in { # If there's no filter, no need to run the expensive conversion, all subpaths will be included _singleton path; - /* + /** Create a file set containing all [Git-tracked files](https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository) in a repository. This function behaves like [`gitTrackedWith { }`](#function-library-lib.fileset.gitTrackedWith) - using the defaults. - Type: - gitTracked :: Path -> FileSet - Example: - # Include all files tracked by the Git repository in the current directory - gitTracked ./. + # Inputs + + `path` - # Include only files tracked by the Git repository in the parent directory - # that are also in the current directory - intersection ./. (gitTracked ../.) + : The [path](https://nixos.org/manual/nix/stable/language/values#type-path) to the working directory of a local Git repository. + This directory must contain a `.git` file or subdirectory. + + # Type + + ``` + gitTracked :: Path -> FileSet + ``` + + # Examples + :::{.example} + ## `lib.fileset.gitTracked` usage example + + ```nix + # Include all files tracked by the Git repository in the current directory + gitTracked ./. + + # Include only files tracked by the Git repository in the parent directory + # that are also in the current directory + intersection ./. (gitTracked ../.) + ``` + + ::: */ gitTracked = - /* - The [path](https://nixos.org/manual/nix/stable/language/values#type-path) to the working directory of a local Git repository. - This directory must contain a `.git` file or subdirectory. - */ path: _fromFetchGit "gitTracked" @@ -796,7 +974,7 @@ in { path {}; - /* + /** Create a file set containing all [Git-tracked files](https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository) in a repository. The first argument allows configuration with an attribute set, while the second argument is the path to the Git working tree. @@ -820,27 +998,40 @@ in { This may change in the future. ::: - Type: - gitTrackedWith :: { recurseSubmodules :: Bool ? false } -> Path -> FileSet - Example: - # Include all files tracked by the Git repository in the current directory - # and any submodules under it - gitTracked { recurseSubmodules = true; } ./. + # Inputs + + `options` (attribute set) + : `recurseSubmodules` (optional, default: `false`) + : Whether to recurse into [Git submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules) to also include their tracked files. + If `true`, this is equivalent to passing the [--recurse-submodules](https://git-scm.com/docs/git-ls-files#Documentation/git-ls-files.txt---recurse-submodules) flag to `git ls-files`. + + `path` + : The [path](https://nixos.org/manual/nix/stable/language/values#type-path) to the working directory of a local Git repository. + This directory must contain a `.git` file or subdirectory. + + # Type + + ``` + gitTrackedWith :: { recurseSubmodules :: Bool ? false } -> Path -> FileSet + ``` + + # Examples + :::{.example} + ## `lib.fileset.gitTrackedWith` usage example + + ```nix + # Include all files tracked by the Git repository in the current directory + # and any submodules under it + gitTracked { recurseSubmodules = true; } ./. + ``` + + ::: */ gitTrackedWith = { - /* - (optional, default: `false`) Whether to recurse into [Git submodules](https://git-scm.com/book/en/v2/Git-Tools-Submodules) to also include their tracked files. - - If `true`, this is equivalent to passing the [--recurse-submodules](https://git-scm.com/docs/git-ls-files#Documentation/git-ls-files.txt---recurse-submodules) flag to `git ls-files`. - */ recurseSubmodules ? false, }: - /* - The [path](https://nixos.org/manual/nix/stable/language/values#type-path) to the working directory of a local Git repository. - This directory must contain a `.git` file or subdirectory. - */ path: if ! isBool recurseSubmodules then throw "lib.fileset.gitTrackedWith: Expected the attribute `recurseSubmodules` of the first argument to be a boolean, but it's a ${typeOf recurseSubmodules} instead." diff --git a/lib/fixed-points.nix b/lib/fixed-points.nix index 3bd18fdd2a5a9..2a31b44f27c17 100644 --- a/lib/fixed-points.nix +++ b/lib/fixed-points.nix @@ -1,6 +1,6 @@ { lib, ... }: rec { - /* + /** `fix f` computes the fixed point of the given function `f`. In other words, the return value is `x` in `x = f x`. `f` must be a lazy function. @@ -63,27 +63,52 @@ rec { See [`extends`](#function-library-lib.fixedPoints.extends) for an example use case. There `self` is also often called `final`. - Type: fix :: (a -> a) -> a - Example: - fix (self: { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; }) - => { bar = "bar"; foo = "foo"; foobar = "foobar"; } + # Inputs - fix (self: [ 1 2 (elemAt self 0 + elemAt self 1) ]) - => [ 1 2 3 ] + `f` + + : 1\. Function argument + + # Type + + ``` + fix :: (a -> a) -> a + ``` + + # Examples + :::{.example} + ## `lib.fixedPoints.fix` usage example + + ```nix + fix (self: { foo = "foo"; bar = "bar"; foobar = self.foo + self.bar; }) + => { bar = "bar"; foo = "foo"; foobar = "foobar"; } + + fix (self: [ 1 2 (elemAt self 0 + elemAt self 1) ]) + => [ 1 2 3 ] + ``` + + ::: */ fix = f: let x = f x; in x; - /* + /** A variant of `fix` that records the original recursive attribute set in the result, in an attribute named `__unfix__`. This is useful in combination with the `extends` function to implement deep overriding. + + + # Inputs + + `f` + + : 1\. Function argument */ fix' = f: let x = f x // { __unfix__ = f; }; in x; - /* + /** Return the fixpoint that `f` converges to when called iteratively, starting with the input `x`. @@ -92,7 +117,22 @@ rec { 0 ``` - Type: (a -> a) -> a -> a + + # Inputs + + `f` + + : 1\. Function argument + + `x` + + : 2\. Function argument + + # Type + + ``` + (a -> a) -> a -> a + ``` */ converge = f: x: let @@ -102,7 +142,7 @@ rec { then x else converge f x'; - /* + /** Extend a function using an overlay. Overlays allow modifying and extending fixed-point functions, specifically ones returning attribute sets. @@ -217,32 +257,50 @@ rec { ``` ::: - Type: - extends :: (Attrs -> Attrs -> Attrs) # The overlay to apply to the fixed-point function - -> (Attrs -> Attrs) # A fixed-point function - -> (Attrs -> Attrs) # The resulting fixed-point function - Example: - f = final: { a = 1; b = final.a + 2; } + # Inputs + + `overlay` - fix f - => { a = 1; b = 3; } + : The overlay to apply to the fixed-point function - fix (extends (final: prev: { a = prev.a + 10; }) f) - => { a = 11; b = 13; } + `f` - fix (extends (final: prev: { b = final.a + 5; }) f) - => { a = 1; b = 6; } + : The fixed-point function - fix (extends (final: prev: { c = final.a + final.b; }) f) - => { a = 1; b = 3; c = 4; } + # Type + + ``` + extends :: (Attrs -> Attrs -> Attrs) # The overlay to apply to the fixed-point function + -> (Attrs -> Attrs) # A fixed-point function + -> (Attrs -> Attrs) # The resulting fixed-point function + ``` + + # Examples + :::{.example} + ## `lib.fixedPoints.extends` usage example + + ```nix + f = final: { a = 1; b = final.a + 2; } + + fix f + => { a = 1; b = 3; } + + fix (extends (final: prev: { a = prev.a + 10; }) f) + => { a = 11; b = 13; } + + fix (extends (final: prev: { b = final.a + 5; }) f) + => { a = 1; b = 6; } + + fix (extends (final: prev: { c = final.a + final.b; }) f) + => { a = 1; b = 3; c = 4; } + ``` + + ::: */ extends = - # The overlay to apply to the fixed-point function overlay: - # The fixed-point function f: - # Wrap with parenthesis to prevent nixdoc from rendering the `final` argument in the documentation # The result should be thought of as a function, the argument of that function is not an argument to `extends` itself ( final: @@ -252,10 +310,29 @@ rec { prev // overlay final prev ); - /* + /** Compose two extending functions of the type expected by 'extends' into one where changes made in the first are available in the 'super' of the second + + + # Inputs + + `f` + + : 1\. Function argument + + `g` + + : 2\. Function argument + + `final` + + : 3\. Function argument + + `prev` + + : 4\. Function argument */ composeExtensions = f: g: final: prev: @@ -263,7 +340,7 @@ rec { prev' = prev // fApplied; in fApplied // g final prev'; - /* + /** Compose several extending functions of the type expected by 'extends' into one where changes made in preceding functions are made available to subsequent ones. @@ -276,7 +353,7 @@ rec { composeManyExtensions = lib.foldr (x: y: composeExtensions x y) (final: prev: {}); - /* + /** Create an overridable, recursive attribute set. For example: ``` @@ -298,9 +375,20 @@ rec { */ makeExtensible = makeExtensibleWithCustomName "extend"; - /* + /** Same as `makeExtensible` but the name of the extending attribute is customized. + + + # Inputs + + `extenderName` + + : 1\. Function argument + + `rattrs` + + : 2\. Function argument */ makeExtensibleWithCustomName = extenderName: rattrs: fix' (self: (rattrs self) // { diff --git a/lib/licenses.nix b/lib/licenses.nix index 7d2a22bc25a47..8dbdf27fa845a 100644 --- a/lib/licenses.nix +++ b/lib/licenses.nix @@ -902,6 +902,17 @@ in mkLicense lset) ({ free = false; }; + ncbiPd = { + spdxId = "NCBI-PD"; + fullname = "NCBI Public Domain Notice"; + # Due to United States copyright law, anything with this "license" does not have a copyright in the + # jurisdiction of the United States. However, other jurisdictions may assign the United States + # government copyright to the work, and the license explicitly states that in such a case, no license + # is granted. This is nonfree and nonredistributable in most jurisdictions other than the United States. + free = false; + redistributable = false; + }; + ncsa = { spdxId = "NCSA"; fullName = "University of Illinois/NCSA Open Source License"; diff --git a/lib/meta.nix b/lib/meta.nix index 675e1912d4be9..9a97afb1aa9b0 100644 --- a/lib/meta.nix +++ b/lib/meta.nix @@ -26,8 +26,12 @@ rec { dontDistribute = drv: addMetaAttrs { hydraPlatforms = []; } drv; - /* Change the symbolic name of a package for presentation purposes - (i.e., so that nix-env users can tell them apart). + /* + Change the [symbolic name of a derivation](https://nixos.org/manual/nix/stable/language/derivations.html#attr-name). + + :::{.warning} + Dependent derivations will be rebuilt when the symbolic name is changed. + ::: */ setName = name: drv: drv // {inherit name;}; diff --git a/lib/systems/default.nix b/lib/systems/default.nix index fbd6c323bf425..d37ff720edce6 100644 --- a/lib/systems/default.nix +++ b/lib/systems/default.nix @@ -93,6 +93,7 @@ let else if final.isAndroid then "bionic" else if final.isLinux /* default */ then "glibc" else if final.isFreeBSD then "fblibc" + else if final.isOpenBSD then "oblibc" else if final.isNetBSD then "nblibc" else if final.isAvr then "avrlibc" else if final.isGhcjs then null diff --git a/lib/systems/examples.nix b/lib/systems/examples.nix index 8a3726f369682..6a9427b2d9de7 100644 --- a/lib/systems/examples.nix +++ b/lib/systems/examples.nix @@ -59,7 +59,7 @@ rec { armv7a-android-prebuilt = { config = "armv7a-unknown-linux-androideabi"; - rustc.config = "armv7-linux-androideabi"; + rust.rustcTarget = "armv7-linux-androideabi"; sdkVer = "28"; ndkVer = "24"; useAndroidPrebuilt = true; @@ -67,7 +67,7 @@ rec { aarch64-android-prebuilt = { config = "aarch64-unknown-linux-android"; - rustc.config = "aarch64-linux-android"; + rust.rustcTarget = "aarch64-linux-android"; sdkVer = "28"; ndkVer = "24"; useAndroidPrebuilt = true; @@ -207,7 +207,7 @@ rec { aarch64-embedded = { config = "aarch64-none-elf"; libc = "newlib"; - rustc.config = "aarch64-unknown-none"; + rust.rustcTarget = "aarch64-unknown-none"; }; aarch64be-embedded = { @@ -342,6 +342,11 @@ rec { useLLVM = true; }; + x86_64-openbsd = { + config = "x86_64-unknown-openbsd"; + useLLVM = true; + }; + # # WASM # diff --git a/lib/systems/parse.nix b/lib/systems/parse.nix index 4890912d7fed4..1d7c95943a794 100644 --- a/lib/systems/parse.nix +++ b/lib/systems/parse.nix @@ -469,6 +469,7 @@ rec { elem (elemAt l 2) [ "wasi" "redox" "mmixware" "ghcjs" "mingw32" ] || hasPrefix "freebsd" (elemAt l 2) || hasPrefix "netbsd" (elemAt l 2) || + hasPrefix "openbsd" (elemAt l 2) || hasPrefix "genode" (elemAt l 2) then { cpu = elemAt l 0; diff --git a/lib/tests/misc.nix b/lib/tests/misc.nix index 6774939023d20..408ea54162938 100644 --- a/lib/tests/misc.nix +++ b/lib/tests/misc.nix @@ -1639,6 +1639,27 @@ runTests { ]; }; + testToGNUCommandLineSeparator = { + expr = cli.toGNUCommandLine { optionValueSeparator = "="; } { + data = builtins.toJSON { id = 0; }; + X = "PUT"; + retry = 3; + retry-delay = null; + url = [ "https://example.com/foo" "https://example.com/bar" ]; + silent = false; + verbose = true; + }; + + expected = [ + "-X=PUT" + "--data={\"id\":0}" + "--retry=3" + "--url=https://example.com/foo" + "--url=https://example.com/bar" + "--verbose" + ]; + }; + testToGNUCommandLineShell = { expr = cli.toGNUCommandLineShell {} { data = builtins.toJSON { id = 0; }; diff --git a/lib/tests/release.nix b/lib/tests/release.nix index 1447e88170913..084fbd94d34c2 100644 --- a/lib/tests/release.nix +++ b/lib/tests/release.nix @@ -24,7 +24,9 @@ in # # https://github.com/NixOS/nixpkgs/issues/272591 # - [(import ../../pkgs/test/release {})] + [(import ../../pkgs/test/release { + inherit pkgs lib nix; + })] ; } diff --git a/lib/trivial.nix b/lib/trivial.nix index 5b7a1ee30f7ad..20a3ffebbc2bb 100644 --- a/lib/trivial.nix +++ b/lib/trivial.nix @@ -403,7 +403,7 @@ in { On each release the first letter is bumped and a new animal is chosen starting with that new letter. */ - codeName = "Uakari"; + codeName = "Vicuna"; /** Returns the current nixpkgs version suffix as string. @@ -623,6 +623,37 @@ in { /** Reads a JSON file. + # Examples + :::{.example} + ## `lib.trivial.importJSON` usage example + + example.json + ```json + { + "title": "Example JSON", + "hello": { + "world": "foo", + "bar": { + "foobar": true + } + } + } + ``` + + ```nix + importJSON ./example.json + => { + title = "Example JSON"; + hello = { + world = "foo"; + bar = { + foobar = true; + }; + }; + } + ``` + + ::: # Inputs @@ -642,6 +673,35 @@ in { /** Reads a TOML file. + # Examples + :::{.example} + ## `lib.trivial.importTOML` usage example + + example.toml + ```toml + title = "TOML Example" + + [hello] + world = "foo" + + [hello.bar] + foobar = true + ``` + + ```nix + importTOML ./example.toml + => { + title = "TOML Example"; + hello = { + world = "foo"; + bar = { + foobar = true; + }; + }; + } + ``` + + ::: # Inputs diff --git a/maintainers/maintainer-list.nix b/maintainers/maintainer-list.nix index f650bb2e9d5bb..babccb8988ce7 100644 --- a/maintainers/maintainer-list.nix +++ b/maintainers/maintainer-list.nix @@ -272,6 +272,12 @@ githubId = 381298; name = "9R"; }; + _9yokuro = { + email = "xzstd099@protonmail.com"; + github = "9yokuro"; + githubId = 119095935; + name = "9yokuro"; + }; A1ca7raz = { email = "aya@wtm.moe"; github = "A1ca7raz"; @@ -571,6 +577,15 @@ fingerprint = "51E4 F5AB 1B82 BE45 B422 9CC2 43A5 E25A A5A2 7849"; }]; }; + aduh95 = { + email = "duhamelantoine1995@gmail.com"; + github = "aduh95"; + githubId = 14309773; + name = "Antoine du Hamel"; + keys = [{ + fingerprint = "C0D6 2484 39F1 D560 4AAF FB40 21D9 00FF DB23 3756"; + }]; + }; aerialx = { email = "aaron+nixos@aaronlindsay.com"; github = "AerialX"; @@ -1023,6 +1038,16 @@ githubId = 60479013; name = "Alma Cemerlic"; }; + alois31 = { + name = "Alois Wohlschlager"; + email = "alois1@gmx-topmail.de"; + matrix = "@aloisw:kde.org"; + github = "alois31"; + githubId = 36605164; + keys = [{ + fingerprint = "CA97 A822 FF24 25D4 74AF 3E4B E0F5 9EA5 E521 6914"; + }]; + }; Alper-Celik = { email = "alper@alper-celik.dev"; name = "Alper Çelik"; @@ -1080,6 +1105,12 @@ fingerprint = "1F73 8879 5E5A 3DFC E2B3 FA32 87D1 AADC D25B 8DEE"; }]; }; + aman9das = { + email = "amandas62640@gmail.com"; + github = "Aman9das"; + githubId = 39594914; + name = "Aman Das"; + }; amanjeev = { email = "aj@amanjeev.com"; github = "amanjeev"; @@ -1168,12 +1199,30 @@ githubId = 858965; name = "Andrew Morsillo"; }; + amyipdev = { + email = "amy@amyip.net"; + github = "amyipdev"; + githubId = 46307646; + name = "Amy Parker"; + keys = [{ + fingerprint = "7786 034B D521 49F5 1B0A 2A14 B112 2F04 E962 DDC5"; + }]; + }; amz-x = { email = "mail@amz-x.com"; github = "amz-x"; githubId = 18249234; name = "Christopher Crouse"; }; + anas = { + email = "anas.elgarhy.dev@gmail.com"; + github = "0x61nas"; + githubId = 44965145; + name = "Anas Elgarhy"; + keys = [{ + fingerprint = "E10B D192 9231 08C7 3C35 7EC3 83E0 3DC6 F383 4086"; + }]; + }; AnatolyPopov = { email = "aipopov@live.ru"; github = "AnatolyPopov"; @@ -1271,6 +1320,13 @@ githubId = 29887; name = "Andrew Smith"; }; + Andy3153 = { + name = "Andrei Dobrete"; + email = "andy3153@protonmail.com"; + matrix = "@andy3153:matrix.org"; + github = "Andy3153"; + githubId = 53472302; + }; andys8 = { github = "andys8"; githubId = 13085980; @@ -1787,6 +1843,12 @@ githubId = 816777; name = "Ashley Gillman"; }; + ashgoldofficial = { + email = "ashley.goldwater@gmail.com"; + github = "ASHGOLDOFFICIAL"; + githubId = 104313094; + name = "Andrey Shaat"; + }; ashkitten = { email = "ashlea@protonmail.com"; github = "ashkitten"; @@ -1855,12 +1917,6 @@ githubId = 7745457; name = "Astavie"; }; - astindev = { - email = "astindev@pm.me"; - github = "astindev"; - githubId = 52360869; - name = "Astin"; - }; astro = { email = "astro@spaceboyz.net"; github = "astro"; @@ -1876,6 +1932,12 @@ fingerprint = "BF47 81E1 F304 1ADF 18CE C401 DE16 C7D1 536D A72F"; }]; }; + astronaut0212 = { + email = "goatastronaut0212@proton.me"; + github = "goatastronaut0212"; + githubId = 119769817; + name = "goatastronaut0212"; + }; astsmtl = { email = "astsmtl@yandex.ru"; github = "astsmtl"; @@ -2029,6 +2091,12 @@ githubId = 1217745; name = "Aldwin Vlasblom"; }; + aveltras = { + email = "romain.viallard@outlook.fr"; + github = "aveltras"; + githubId = 790607; + name = "Romain Viallard"; + }; averagebit = { email = "averagebit@pm.me"; github = "averagebit"; @@ -2138,15 +2206,6 @@ fingerprint = "6309 E212 29D4 DA30 AF24 BDED 754B 5C09 63C4 2C50"; }]; }; - babariviere = { - email = "me@babariviere.com"; - github = "babariviere"; - githubId = 12128029; - name = "Bastien Rivière"; - keys = [{ - fingerprint = "74AA 9AB4 E6FF 872B 3C5A CB3E 3903 5CC0 B75D 1142"; - }]; - }; babbaj = { name = "babbaj"; email = "babbaj45@gmail.com"; @@ -2986,6 +3045,14 @@ githubId = 184563; name = "Bruno Paz"; }; + brsvh = { + email = "bsc@brsvh.org"; + github = "brsvh"; + githubId = 63050399; + keys = [ { fingerprint = "7B74 0DB9 F2AC 6D3B 226B C530 78D7 4502 D92E 0218"; } ]; + matrix = "@brsvh:mozilla.org"; + name = "Burgess Chang"; + }; bryanasdev000 = { email = "bryanasdev000@gmail.com"; matrix = "@bryanasdev000:matrix.org"; @@ -3199,6 +3266,16 @@ githubId = 3212452; name = "Cameron Nemo"; }; + cameronraysmith = { + email = "cameronraysmith@gmail.com"; + matrix = "@cameronraysmith:matrix.org"; + github = "cameronraysmith"; + githubId = 420942; + name = "Cameron Smith"; + keys = [{ + fingerprint = "3F14 C258 856E 88AE E0F9 661E FF04 3B36 8811 DD1C"; + }]; + }; camillemndn = { email = "camillemondon@free.fr"; github = "camillemndn"; @@ -3235,6 +3312,16 @@ github = "CaptainJawZ"; githubId = 43111068; }; + caralice = { + name = "Alice Carroll"; + email = "nix@alice-carroll.pet"; + github = "thecaralice"; + githubId = 43097806; + keys = [ + { fingerprint = "C7EA B182 2AB1 246C 0FB8 DD72 0514 0B67 902C D3AF"; } + { fingerprint = "DA77 EDDB 4AF5 244C 665E 9176 A05E A86A 5834 1AA8"; } + ]; + }; CardboardTurkey = { name = "Kiran Ostrolenk"; email = "kiran@ostrolenk.co.uk"; @@ -3525,6 +3612,16 @@ githubId = 28303440; name = "Max Hausch"; }; + cherrykitten = { + email = "contact@cherrykitten.dev"; + github = "cherrykitten"; + githubId = 20300586; + matrix = "@sammy:cherrykitten.dev"; + name = "CherryKitten"; + keys = [{ + fingerprint = "264C FA1A 194C 585D F822 F673 C01A 7CBB A617 BD5F"; + }]; + }; chessai = { email = "chessai1996@gmail.com"; github = "chessai"; @@ -3582,6 +3679,12 @@ githubId = 1118859; name = "Scott Worley"; }; + chmouel = { + email = "chmouel@chmouel.com"; + github = "chmouel"; + githubId = 98980; + name = "Chmouel Boudjnah"; + }; choochootrain = { email = "hurshal@imap.cc"; github = "choochootrain"; @@ -3683,6 +3786,15 @@ github = "ciferkey"; githubId = 101422; }; + cig0 = { + name = "Martín Cigorraga"; + email = "cig0.github@gmail.com"; + github = "cig0"; + githubId = 394089; + keys = [{ + fingerprint = "1828 B459 DB9A 7EE2 03F4 7E6E AFBE ACC5 5D93 84A0"; + }]; + }; cigrainger = { name = "Christopher Grainger"; email = "chris@amplified.ai"; @@ -3728,6 +3840,12 @@ githubId = 136485; name = "Chad Jablonski"; }; + cjshearer = { + email = "cjshearer@live.com"; + github = "cjshearer"; + githubId = 7173077; + name = "Cody Shearer"; + }; ck3d = { email = "ck3d@gmx.de"; github = "ck3d"; @@ -3762,6 +3880,15 @@ githubId = 199180; name = "Claes Wallin"; }; + clebs = { + email = "borja.clemente@gmail.com"; + github = "clebs"; + githubId = 1059661; + name = "Borja Clemente"; + keys = [{ + fingerprint = "C4E1 58BD FD33 3C77 B6C7 178E 2539 757E F64C 60DD"; + }]; + }; cleeyv = { email = "cleeyv@riseup.net"; github = "cleeyv"; @@ -3846,6 +3973,14 @@ githubId = 180339; name = "Andrew Cobb"; }; + coca = { + github = "Coca162"; + githubId = 62479942; + name = "Coca"; + keys = [{ + fingerprint = "99CB 86FF 62BB 7DA4 8903 B16D 0328 2DF8 8179 AB19"; + }]; + }; coconnor = { email = "coreyoconnor@gmail.com"; github = "coreyoconnor"; @@ -4203,6 +4338,11 @@ githubId = 111202; name = "Henry Bubert"; }; + cryptoluks = { + github = "cryptoluks"; + githubId = 9020527; + name = "cryptoluks"; + }; CrystalGamma = { email = "nixos@crystalgamma.de"; github = "CrystalGamma"; @@ -4521,9 +4661,14 @@ github = "DataHearth"; githubId = 28595242; name = "DataHearth"; - keys = [{ - fingerprint = "A129 2547 0298 BFEE 7EE0 92B3 946E 2D0C 410C 7B3D"; - }]; + keys = [ + { + fingerprint = "A129 2547 0298 BFEE 7EE0 92B3 946E 2D0C 410C 7B3D"; + } + { + fingerprint = "FFC4 92C1 5320 B05D 0F8D 7D58 ABF6 737C 6339 6D35"; + } + ]; }; davegallant = { name = "Dave Gallant"; @@ -5083,6 +5228,12 @@ github = "diniamo"; githubId = 55629891; }; + diogomdp = { + email = "me@diogodp.dev"; + github = "diogomdp"; + githubId = 52360869; + name = "Diogo"; + }; diogotcorreia = { name = "Diogo Correia"; email = "me@diogotc.com"; @@ -6569,6 +6720,16 @@ githubId = 9959940; name = "Andreas Fehn"; }; + felbinger = { + name = "Nico Felbinger"; + email = "nico@felbinger.eu"; + matrix = "@nico:felbinger.eu"; + github = "felbinger"; + githubId = 26925347; + keys = [{ + fingerprint = "0797 D238 9769 CA1E 57B7 2ED9 2BA7 8116 87C9 0DE4"; + }]; + }; felipeqq2 = { name = "Felipe Silva"; email = "nixpkgs@felipeqq2.rocks"; @@ -6813,6 +6974,12 @@ fingerprint = "B722 6464 838F 8BDB 2BEA C8C8 5B0E FDDF BA81 6105"; }]; }; + Forden = { + email = "forden@zuku.tech"; + github = "Forden"; + githubId = 24463229; + name = "Forden"; + }; forkk = { email = "forkk@forkk.net"; github = "Forkk"; @@ -6927,6 +7094,12 @@ githubId = 46672819; name = "Frido Friedemann"; }; + friedow = { + email = "christian@friedow.com"; + github = "friedow"; + githubId = 17351844; + name = "Christian Friedow"; + }; friedrichaltheide = { github = "friedrichaltheide"; githubId = 11352905; @@ -6981,6 +7154,13 @@ githubId = 77672306; name = "Florian Agbuya"; }; + fsnkty = { + name = "fsnkty"; + github = "fsnkty"; + githubId = 153512689; + email = "fsnkty@shimeji.cafe"; + matrix = "@nuko:shimeji.cafe"; + }; fstamour = { email = "fr.st-amour@gmail.com"; github = "fstamour"; @@ -7282,6 +7462,16 @@ fingerprint = "386E D1BF 848A BB4A 6B4A 3C45 FC83 907C 125B C2BC"; }]; }; + geoffreyfrogeye = { + name = "Geoffrey Frogeye"; + email = "geoffrey@frogeye.fr"; + matrix = "@geoffrey:frogeye.fr"; + github = "GeoffreyFrogeye"; + githubId = 1685403; + keys = [{ + fingerprint = "4FBA 930D 314A 0321 5E2C DB0A 8312 C8CA C1BA C289"; + }]; + }; georgesalkhouri = { name = "Georges Alkhouri"; email = "incense.stitch_0w@icloud.com"; @@ -7570,6 +7760,12 @@ fingerprint = "0BAF 2D87 CB43 746F 6237 2D78 DE60 31AB A0BB 269A"; }]; }; + Golo300 = { + email = "lanzingertm@gmail.com"; + github = "Golo300"; + githubId = 58785758; + name = "Tim Lanzinger"; + }; Gonzih = { email = "gonzih@gmail.com"; github = "Gonzih"; @@ -7678,6 +7874,14 @@ fingerprint = "7FC7 98AB 390E 1646 ED4D 8F1F 797F 6238 68CD 00C2"; }]; }; + greaka = { + email = "git@greaka.de"; + github = "greaka"; + githubId = 2805834; + name = "Greaka"; + keys = + [{ fingerprint = "6275 FB5C C9AC 9D85 FF9E 44C5 EE92 A5CD C367 118C"; }]; + }; greg = { email = "greg.hellings@gmail.com"; github = "greg-hellings"; @@ -8031,6 +8235,12 @@ matrix = "@heisfer:matrix.org"; name = "Heisfer"; }; + HeitorAugustoLN = { + email = "IAm.HeitorALN@proton.me"; + github = "HeitorAugustoLN"; + githubId = 44377258; + name = "Heitor Augusto"; + }; helium = { email = "helium.dev@tuta.io"; github = "helium18"; @@ -8249,6 +8459,12 @@ githubId = 896431; name = "Chris Hodapp"; }; + hogcycle = { + email = "nate@gysli.ng"; + github = "hogcycle"; + githubId = 57007241; + name = "hogcycle"; + }; holgerpeters = { name = "Holger Peters"; email = "holger.peters@posteo.de"; @@ -8537,6 +8753,12 @@ githubId = 1550265; name = "Dominic Steinitz"; }; + ifd3f = { + github = "ifd3f"; + githubId = 7308591; + email = "astrid@astrid.tech"; + name = "ifd3f"; + }; iFreilicht = { github = "iFreilicht"; githubId = 9742635; @@ -9292,6 +9514,12 @@ githubId = 2377; name = "Jonathan del Strother"; }; + jdev082 = { + email = "jdev0894@gmail.com"; + github = "jdev082"; + githubId = 92550746; + name = "jdev082"; + }; jdreaver = { email = "johndreaver@gmail.com"; github = "jdreaver"; @@ -9648,6 +9876,12 @@ githubId = 54179289; name = "Jason Miller"; }; + jn-sena = { + email = "jn-sena@proton.me"; + github = "jn-sena"; + githubId = 45771313; + name = "Sena"; + }; jnsgruk = { email = "jon@sgrs.uk"; github = "jnsgruk"; @@ -9678,6 +9912,11 @@ githubId = 1102396; name = "Jussi Maki"; }; + joanmassachs = { + github = "joanmassachs"; + githubId = 22916782; + name = "Joan Massachs"; + }; joaquintrinanes = { email = "hi@joaquint.io"; github = "JoaquinTrinanes"; @@ -9777,6 +10016,12 @@ githubId = 32305209; name = "John Children"; }; + johnjohnstone = { + email = "jjohnstone@riseup.net"; + github = "johnjohnstone"; + githubId = 3208498; + name = "John Johnstone"; + }; johnmh = { email = "johnmh@openblox.org"; github = "JohnMH"; @@ -9825,6 +10070,12 @@ githubId = 25030997; name = "Yuki Okushi"; }; + johnylpm = { + email = "joaoluisparreira@gmail.com"; + github = "Johny-LPM"; + githubId = 168684553; + name = "João Marques"; + }; jojosch = { name = "Johannes Schleifenbaum"; email = "johannes@js-webcoding.de"; @@ -9898,6 +10149,12 @@ githubId = 8580434; name = "Jonny Bolton"; }; + jonochang = { + name = "Jono Chang"; + email = "j.g.chang@gmail.com"; + github = "jonochang"; + githubId = 13179; + }; jonringer = { email = "jonringer117@gmail.com"; matrix = "@jonringer:matrix.org"; @@ -10093,7 +10350,7 @@ githubId = 27734541; }; jtbx = { - email = "jtbx@duck.com"; + email = "jeremy@baxters.nz"; name = "Jeremy Baxter"; github = "jtbx"; githubId = 92071952; @@ -10297,6 +10554,12 @@ github = "k3a"; githubId = 966992; }; + k3yss = { + email = "rsi.dev17@gmail.com"; + name = "Rishi Kumar"; + github = "k3yss"; + githubId = 96657880; + }; k900 = { name = "Ilya K."; email = "me@0upti.me"; @@ -10389,6 +10652,12 @@ githubId = 56224949; name = "Mia Kanashi"; }; + kanielrkirby = { + email = "kanielrkirby@runbox.com"; + github = "kanielrkirby"; + githubId = 77940607; + name = "Kaniel Kirby"; + }; karantan = { name = "Gasper Vozel"; email = "karantan@gmail.com"; @@ -10454,6 +10723,12 @@ githubId = 26346867; name = "K.B.Dharun Krishna"; }; + kbudde = { + email = "kris@budd.ee"; + github = "kbudde"; + githubId = 1072181; + name = "Kris Budde"; + }; kcalvinalvin = { email = "calvin@kcalvinalvin.info"; github = "kcalvinalvin"; @@ -11089,6 +11364,12 @@ githubId = 15742918; name = "Sergey Kuznetsov"; }; + kvendingoldo = { + email = "kvendingoldo@gmail.com"; + github = "kvendingoldo"; + githubId = 11614750; + name = "Alexander Sharov"; + }; kwohlfahrt = { email = "kai.wohlfahrt@gmail.com"; github = "kwohlfahrt"; @@ -11355,6 +11636,11 @@ githubId = 4158274; name = "Michiel Leenaars"; }; + legojames = { + github = "jrobinson-uk"; + githubId = 4701504; + name = "James Robinson"; + }; leifhelm = { email = "jakob.leifhelm@gmail.com"; github = "leifhelm"; @@ -11381,7 +11667,7 @@ name = "Daniel Kuehn"; }; lelgenio = { - email = "lelgenio@disroot.org"; + email = "lelgenio@lelgenio.com"; github = "lelgenio"; githubId = 31388299; name = "Leonardo Eugênio"; @@ -11837,6 +12123,14 @@ githubId = 10626; name = "Andreas Wagner"; }; + lpostula = { + email = "lois@postu.la"; + github = "loispostula"; + githubId = 1423612; + name = "Loïs Postula"; + keys = + [{ fingerprint = "0B4A E7C7 D3B7 53F5 3B3D 774C 3819 3C6A 09C3 9ED1"; }]; + }; lrewega = { email = "lrewega@c32.ca"; github = "lrewega"; @@ -12309,6 +12603,15 @@ githubId = 2321672; name = "Makise Kurisu"; }; + Makuru = { + email = "makuru@makuru.org"; + github = "makuru-dd"; + githubId = 58048293; + name = "Makuru"; + keys = [{ + fingerprint = "5B22 7123 362F DEF1 8F79 BF2B 4792 3A0F EEB5 51C7"; + }]; + }; malbarbo = { email = "malbarbo@gmail.com"; github = "malbarbo"; @@ -12332,6 +12635,11 @@ githubId = 18661391; name = "Malte Janz"; }; + malteneuss = { + github = "malteneuss"; + githubId = 5301202; + name = "Malte Neuss"; + }; malte-v = { email = "nixpkgs@mal.tc"; github = "malte-v"; @@ -12608,6 +12916,12 @@ githubId = 952712; name = "Matt Christ"; }; + matteopacini = { + email = "m@matteopacini.me"; + github = "matteo-pacini"; + githubId = 3139724; + name = "Matteo Pacini"; + }; matthewbauer = { email = "mjbauer95@gmail.com"; github = "matthewbauer"; @@ -12648,6 +12962,12 @@ githubId = 427866; name = "Matthias Beyer"; }; + matthiasq = { + email = "matthias.queitsch@mailbox.org"; + github = "matthias-Q"; + githubId = 35303817; + name = "Matthias Queitsch"; + }; MatthieuBarthel = { email = "matthieu@imatt.ch"; name = "Matthieu Barthel"; @@ -12681,6 +13001,16 @@ githubId = 11810057; name = "Matt Snider"; }; + MattSturgeon = { + email = "matt@sturgeon.me.uk"; + github = "MattSturgeon"; + githubId = 5046562; + matrix = "@mattsturg:matrix.org"; + name = "Matt Sturgeon"; + keys = [{ + fingerprint = "7082 22EA 1808 E39A 83AC 8B18 4F91 844C ED1A 8299"; + }]; + }; matusf = { email = "matus.ferech@gmail.com"; github = "matusf"; @@ -12762,6 +13092,12 @@ fingerprint = "1DE4 424D BF77 1192 5DC4 CF5E 9AED 8814 81D8 444E"; }]; }; + maxstrid = { + email = "mxwhenderson@gmail.com"; + github = "maxstrid"; + githubId = 115441224; + name = "Maxwell Henderson"; + }; maxux = { email = "root@maxux.net"; github = "maxux"; @@ -12935,6 +13271,12 @@ githubId = 14259816; name = "Abin Simon"; }; + me-and = { + name = "Adam Dinwoodie"; + email = "nix.thunder.wayne@post.dinwoodie.org"; + github = "me-and"; + githubId = 1397507; + }; meatcar = { email = "nixpkgs@denys.me"; github = "meatcar"; @@ -13597,6 +13939,12 @@ githubId = 7831184; name = "John Mercier"; }; + modderme123 = { + email = "modderme123@gmail.com"; + github = "modderme123"; + githubId = 14153763; + name = "modderme123"; + }; modulistic = { email = "modulistic@gmail.com"; github = "modulistic"; @@ -14431,6 +14779,12 @@ githubId = 399535; name = "Niklas Hambüchen"; }; + nhnn = { + matrix = "@nhnn:nhnn.dev"; + github = "thenhnn"; + githubId = 162156666; + name = "nhnn"; + }; nhooyr = { email = "anmol@aubble.com"; github = "nhooyr"; @@ -14679,6 +15033,12 @@ githubId = 6930756; name = "Nicolas Mattia"; }; + nmishin = { + email = "sanduku.default@gmail.com"; + github = "Nmishin"; + githubId = 4242897; + name = "Nikolai Mishin"; + }; noaccos = { name = "Francesco Noacco"; email = "francesco.noacco2000@gmail.com"; @@ -14898,13 +15258,6 @@ github = "numkem"; githubId = 332423; }; - nu-nu-ko = { - email = "nuko@shimeji.cafe"; - matrix = "@nuko:shimeji.cafe"; - github = "nu-nu-ko"; - githubId = 153512689; - name = "nuko"; - }; nviets = { email = "nathan.g.viets@gmail.com"; github = "nviets"; @@ -14948,6 +15301,13 @@ github = "nyawox"; githubId = 93813719; }; + nydragon = { + name = "nydragon"; + github = "nydragon"; + email = "nix@ccnlc.eu"; + githubId = 56591727; + keys = [ { fingerprint = "25FF 8464 F062 7EC0 0129 6A43 14AA 30A8 65EA 1209"; } ]; + }; nzbr = { email = "nixos@nzbr.de"; github = "nzbr"; @@ -14964,6 +15324,12 @@ githubId = 30825096; name = "Ning Zhang"; }; + o0th = { + email = "o0th@pm.me"; + name = "Sabato Luca Guadagno"; + github = "o0th"; + githubId = 22490354; + }; oaksoaj = { email = "oaksoaj@riseup.net"; name = "Oaksoaj"; @@ -15838,6 +16204,12 @@ githubId = 43863; name = "Philip Taron"; }; + philtaken = { + email = "philipp.herzog@protonmail.com"; + github = "philtaken"; + githubId = 13309623; + name = "Philipp Herzog"; + }; phip1611 = { email = "phip1611@gmail.com"; github = "phip1611"; @@ -16002,6 +16374,12 @@ githubId = 4622652; name = "Pedro Magalhães"; }; + pjungkamp = { + email = "philipp@jungkamp.dev"; + github = "PJungkamp"; + githubId = 56401138; + name = "Philipp Jungkamp"; + }; pkharvey = { email = "kayharvey@protonmail.com"; github = "pkharvey"; @@ -16556,6 +16934,12 @@ github = "PhilippWoelfel"; githubId = 19400064; }; + pyle = { + name = "Adam Pyle"; + email = "adam@pyle.dev"; + github = "pyle"; + githubId = 7279609; + }; pyrolagus = { email = "pyrolagus@gmail.com"; github = "PyroLagus"; @@ -16643,6 +17027,12 @@ githubId = 22085373; name = "Luis Hebendanz"; }; + qubitnano = { + name = "qubitnano"; + email = "qubitnano@protonmail.com"; + github = "qubitnano"; + githubId = 146656568; + }; queezle = { email = "git@queezle.net"; github = "queezle42"; @@ -16682,6 +17072,12 @@ githubId = 2141853; name = "Bang Lee"; }; + qwqawawow = { + email = "eihqnh@outlook.com"; + github = "qwqawawow"; + githubId = 40905037; + name = "qwqawawow"; + }; qyliss = { email = "hi@alyssa.is"; github = "alyssais"; @@ -16964,6 +17360,15 @@ githubId = 52847440; name = "Ryan Burns"; }; + rconybea = { + email = "n1xpkgs@hushmail.com"; + github = "rconybea"; + githubId = 8570969; + name = "Roland Conybeare"; + keys = [{ + fingerprint = "bw5Cr/4ul1C2UvxopphbZbFI1i5PCSnOmPID7mJ/Ogo"; + }]; + }; rdnetto = { email = "rdnetto@gmail.com"; github = "rdnetto"; @@ -17522,6 +17927,12 @@ github = "rosehobgoblin"; githubId = 84164410; }; + roshaen = { + name = "Roshan Kumar"; + email = "roshaen09@gmail.com"; + github = "roshaen"; + githubId = 58213083; + }; rossabaker = { name = "Ross A. Baker"; email = "ross@rossabaker.com"; @@ -17531,8 +17942,12 @@ RossComputerGuy = { name = "Tristan Ross"; email = "tristan.ross@midstall.com"; + matrix = "@rosscomputerguy:matrix.org"; github = "RossComputerGuy"; githubId = 19699320; + keys = [{ + fingerprint = "FD5D F7A8 85BB 378A 0157 5356 B09C 4220 3566 9AF8"; + }]; }; rostan-t = { name = "Rostan Tabet"; @@ -17552,6 +17967,11 @@ githubId = 7439756; name = "Rowan Goemans"; }; + roydubnium = { + github = "RoyDubnium"; + githubId = 72664566; + name = "Roy Davison"; + }; royneary = { email = "christian@ulrich.earth"; github = "royneary"; @@ -17915,6 +18335,12 @@ githubId = 6022042; name = "Sam Parkinson"; }; + samemrecebi = { + name = "Emre Çebi"; + email = "emre@cebi.io"; + github = "samemrecebi"; + githubId = 64419750; + }; samhug = { email = "s@m-h.ug"; github = "samhug"; @@ -18297,6 +18723,11 @@ github = "sei40kr"; githubId = 11665236; }; + seineeloquenz = { + name = "Alexander Linder"; + github = "SeineEloquenz"; + githubId = 34923333; + }; seirl = { name = "Antoine Pietri"; email = "antoine.pietri1@gmail.com"; @@ -18875,6 +19306,11 @@ githubId = 106779009; name = "Slambert"; }; + slashformotion = { + github = "slashformotion"; + githubId = 45801817; + name = "slashformotion"; + }; slbtty = { email = "shenlebantongying@gmail.com"; github = "shenlebantongying"; @@ -19599,12 +20035,6 @@ githubId = 36031171; name = "Supa"; }; - superbo = { - email = "supernbo@gmail.com"; - github = "SuperBo"; - githubId = 2666479; - name = "Y Nguyen"; - }; superherointj = { email = "sergiomarcelo@yandex.com"; github = "superherointj"; @@ -20220,6 +20650,12 @@ github = "thefossguy"; githubId = 44400303; }; + thehans255 = { + name = "Hans Jorgensen"; + email = "foss-contact@thehans255.com"; + github = "thehans255"; + githubId = 15896573; + }; thekostins = { name = "Konstantin"; email = "anisimovkosta19@gmail.com"; @@ -20440,6 +20876,12 @@ githubId = 14172; name = "Tim Cuthbertson"; }; + timhae = { + email = "tim.haering@posteo.net"; + githubId = 6264882; + github = "timhae"; + name = "Tim Häring"; + }; timma = { email = "kunduru.it.iitb@gmail.com"; github = "ktrsoft"; @@ -20571,6 +21013,12 @@ fingerprint = "7944 74B7 D236 DAB9 C9EF E7F9 5CCE 6F14 66D4 7C9E"; }]; }; + toasteruwu = { + email = "Aki@ToasterUwU.com"; + github = "ToasterUwU"; + githubId = 43654377; + name = "Aki"; + }; tobiasBora = { email = "tobias.bora.list@gmail.com"; github = "tobiasBora"; @@ -20583,6 +21031,12 @@ githubId = 858790; name = "Tobias Mayer"; }; + tobz619 = { + email = "toloke@yahoo.co.uk"; + github = "tobz619"; + githubId = 93312805; + name = "Tobi Oloke"; + }; tochiaha = { email = "tochiahan@proton.me"; github = "Tochiaha"; @@ -20634,11 +21088,14 @@ name = "Tomkoid"; }; tomodachi94 = { - email = "tomodachi94+nixpkgs@protonmail.com"; + email = "tomodachi94@protonmail.com"; matrix = "@tomodachi94:matrix.org"; github = "tomodachi94"; githubId = 68489118; name = "Tomodachi94"; + keys = [{ + fingerprint = "B208 D6E5 B8ED F47D 5687 627B 2E27 5F21 C4D5 54A3"; + }]; }; tomsiewert = { email = "tom@siewert.io"; @@ -20703,6 +21160,12 @@ github = "tpwrules"; githubId = 208010; }; + traverseda = { + email = "traverse.da@gmail.com"; + github = "traverseda"; + githubId = 2125828; + name = "Alex Davies"; + }; travisbhartwell = { email = "nafai@travishartwell.net"; github = "travisbhartwell"; @@ -21221,6 +21684,12 @@ githubId = 6943308; name = "Varun Patro"; }; + vasissualiyp = { + email = "vaspust@gmail.com"; + github = "vasissualiyp"; + githubId = 110242808; + name = "Vasilii Pustovoit"; + }; vbgl = { email = "Vincent.Laporte@gmail.com"; github = "vbgl"; @@ -21550,6 +22019,12 @@ name = "Kostas Karachalios"; githubId = 81346; }; + vringar = { + email = "git@zabka.it"; + github = "vringar"; + name = "Stefan Zabka"; + githubId = 13276717; + }; vrthra = { email = "rahul@gopinath.org"; github = "vrthra"; @@ -21684,6 +22159,12 @@ github = "wegank"; githubId = 9713184; }; + weitzj = { + name = "Jan Weitz"; + email = "nixpkgs@janweitz.de"; + github = "weitzj"; + githubId = 829277; + }; welteki = { email = "welteki@pm.me"; github = "welteki"; @@ -22068,6 +22549,12 @@ githubId = 474343; name = "Xavier Zwirtz"; }; + XBagon = { + name = "XBagon"; + email = "xbagon@outlook.de"; + github = "XBagon"; + githubId = 1523292; + }; xbreak = { email = "xbreak@alphaware.se"; github = "xbreak"; @@ -22163,6 +22650,11 @@ githubId = 46590321; name = "xrelkd"; }; + xtrayambak = { + github = "xTrayambak"; + githubId = 59499552; + name = "Trayambak Rai"; + }; xurei = { email = "olivier.bourdoux@gmail.com"; github = "xurei"; @@ -22388,6 +22880,11 @@ githubId = 40352765; name = "Yoctocell"; }; + yomaq = { + name = "yomaq"; + github = "yomaq"; + githubId = 112864332; + }; yorickvp = { email = "yorickvanpelt@gmail.com"; matrix = "@yorickvp:matrix.org"; @@ -22527,6 +23024,15 @@ githubId = 5253988; name = "yvt"; }; + yzx9 = { + email = "yuan.zx@outlook.com"; + github = "yzx9"; + githubId = 41458459; + name = "Zexin Yuan"; + keys = [{ + fingerprint = "FE16 B281 90EF 6C3F F661 6441 C2DD 1916 FE47 1BE2"; + }]; + }; zachcoyle = { email = "zach.coyle@gmail.com"; github = "zachcoyle"; @@ -22651,6 +23157,16 @@ fingerprint = "1127 F188 280A E312 3619 3329 87E1 7EEF 9B18 B6C9"; }]; }; + zeorin = { + name = "Xandor Schiefer"; + email = "me@xandor.co.za"; + matrix = "@zeorin:matrix.org"; + github = "zeorin"; + githubId = 1187078; + keys = [{ + fingerprint = "863F 093A CF82 D2C8 6FD7 FB74 5E1C 0971 FE4F 665A"; + }]; + }; zeratax = { email = "mail@zera.tax"; github = "zeratax"; @@ -22703,6 +23219,12 @@ githubId = 3248; name = "zimbatm"; }; + zimeg = { + email = "zim@o526.net"; + github = "zimeg"; + githubId = 18134219; + name = "zimeg"; + }; Zimmi48 = { email = "theo.zimmermann@telecom-paris.fr"; github = "Zimmi48"; diff --git a/maintainers/scripts/copy-tarballs.pl b/maintainers/scripts/copy-tarballs.pl index b17cd82f4d1c8..30fbac6f002d9 100755 --- a/maintainers/scripts/copy-tarballs.pl +++ b/maintainers/scripts/copy-tarballs.pl @@ -1,5 +1,5 @@ #! /usr/bin/env nix-shell -#! nix-shell -i perl -p perl perlPackages.NetAmazonS3 perlPackages.FileSlurp perlPackages.JSON perlPackages.LWPProtocolHttps nixUnstable nixUnstable.perl-bindings +#! nix-shell -i perl -p perl perlPackages.NetAmazonS3 perlPackages.FileSlurp perlPackages.JSON perlPackages.LWPProtocolHttps nix nix.perl-bindings # This command uploads tarballs to tarballs.nixos.org, the # content-addressed cache used by fetchurl as a fallback for when diff --git a/maintainers/scripts/kde/collect-missing-deps.py b/maintainers/scripts/kde/collect-missing-deps.py index 9625da71c3e51..3ec1411986c85 100755 --- a/maintainers/scripts/kde/collect-missing-deps.py +++ b/maintainers/scripts/kde/collect-missing-deps.py @@ -80,6 +80,11 @@ "plasma-desktop": { "scim", # upstream is dead, not packaged in Nixpkgs }, + "poppler-qt6": { + "gobject-introspection-1.0", # we don't actually want to build the GTK variant + "gdk-pixbuf-2.0", + "gtk+-3.0", + }, "powerdevil": { "DDCUtil", # cursed, intentionally disabled }, @@ -87,6 +92,9 @@ "Qt6Qml", # tests only "Qt6Quick", }, + "skladnik": { + "POVRay", # too expensive to rerender all the assets + }, "syntax-highlighting": { "XercesC", # only used for extra validation at build time } diff --git a/maintainers/scripts/luarocks-packages.csv b/maintainers/scripts/luarocks-packages.csv index 0091e93b7d58c..d4b6190f19259 100644 --- a/maintainers/scripts/luarocks-packages.csv +++ b/maintainers/scripts/luarocks-packages.csv @@ -1,5 +1,6 @@ name,rockspec,ref,server,version,luaversion,maintainers alt-getopt,,,,,,arobyn +ansicolors,,,,,,Freed-Wu bit32,,,,5.3.0-1,5.1,lblasc argparse,,,,,, basexx,,,,,, @@ -76,7 +77,9 @@ lualdap,,,,,,aanderse lualogging,,,,,, luaossl,,,,,5.1, luaposix,,,,34.1.1-1,,vyp lblasc +luaprompt,,,,,,Freed-Wu luarepl,,,,,, +luarocks,,,,,,mrcjkb teto luarocks-build-rust-mlua,,,,,,mrcjkb luarocks-build-treesitter-parser,,,,,,mrcjkb luasec,,,,,,flosse @@ -97,6 +100,7 @@ luuid,,,,20120509-2,, luv,,,,1.44.2-1,, lush.nvim,,,https://luarocks.org/dev,,,teto lyaml,,,,,,lblasc +lz.n,,,,,,mrcjkb magick,,,,,5.1,donovanglover markdown,,,,,, mediator_lua,,,,,, @@ -112,6 +116,7 @@ nvim-nio,,,,,,mrcjkb pathlib.nvim,,,,,, penlight,,,,,,alerque plenary.nvim,https://raw.githubusercontent.com/nvim-lua/plenary.nvim/master/plenary.nvim-scm-1.rockspec,,,,5.1, +psl,,,,0.3,, rapidjson,,,,,, rest.nvim,,,,,5.1,teto rocks.nvim,,,,,,mrcjkb diff --git a/maintainers/scripts/nixpkgs-lint.nix b/maintainers/scripts/nixpkgs-lint.nix index b400ce034b3e0..979ec286d8090 100644 --- a/maintainers/scripts/nixpkgs-lint.nix +++ b/maintainers/scripts/nixpkgs-lint.nix @@ -1,18 +1,22 @@ { stdenv, lib, makeWrapper, perl, perlPackages }: stdenv.mkDerivation { - name = "nixpkgs-lint-1"; + pname = "nixpkgs-lint"; + version = "1"; nativeBuildInputs = [ makeWrapper ]; buildInputs = [ perl perlPackages.XMLSimple ]; dontUnpack = true; - buildPhase = "true"; + dontBuild = true; installPhase = '' mkdir -p $out/bin cp ${./nixpkgs-lint.pl} $out/bin/nixpkgs-lint + # make the built version hermetic + substituteInPlace $out/bin/nixpkgs-lint \ + --replace-fail "#! /usr/bin/env nix-shell" "#! ${lib.getExe perl}" wrapProgram $out/bin/nixpkgs-lint --set PERL5LIB $PERL5LIB ''; diff --git a/maintainers/scripts/pluginupdate.py b/maintainers/scripts/pluginupdate.py index 239f529f9eaa3..8ae86e2e93a49 100644 --- a/maintainers/scripts/pluginupdate.py +++ b/maintainers/scripts/pluginupdate.py @@ -108,7 +108,7 @@ def __init__(self, uri: str, branch: str) -> None: @property def name(self): - return self.uri.split("/")[-1] + return self.uri.strip("/").split("/")[-1] @property def branch(self): diff --git a/maintainers/team-list.nix b/maintainers/team-list.nix index e0c1629a6f23a..2bc124d6066a9 100644 --- a/maintainers/team-list.nix +++ b/maintainers/team-list.nix @@ -236,7 +236,6 @@ with lib.maintainers; { members = [ cole-h grahamc - hoverbear ]; scope = "Group registration for packages maintained by Determinate Systems."; shortName = "Determinate Systems employees"; @@ -345,6 +344,16 @@ with lib.maintainers; { shortName = "freedesktop.org packaging"; }; + fslabs = { + # Verify additions to this team with at least one already existing member of the team. + members = [ + greaka + lpostula + ]; + scope = "Group registration for packages maintained by Foresight Spatial Labs."; + shortName = "Foresight Spatial Labs employees"; + }; + gcc = { members = [ synthetica @@ -419,7 +428,6 @@ with lib.maintainers; { bandresen hlolli glittershark - babariviere ericdallo thiagokokada ]; @@ -680,6 +688,7 @@ with lib.maintainers; { dandellion sumnerevans nickcao + teutat3s ]; scope = "Maintain the ecosystem around Matrix, a decentralized messenger."; shortName = "Matrix"; @@ -953,6 +962,12 @@ with lib.maintainers; { shortName = "SageMath"; }; + sdl = { + members = [ ]; + scope = "Maintain SDL libraries."; + shortName = "SDL"; + }; + sphinx = { members = [ ]; scope = "Maintain Sphinx related packages."; diff --git a/nixos/README.md b/nixos/README.md index 07e82bf0ad938..5f751e10e20a0 100644 --- a/nixos/README.md +++ b/nixos/README.md @@ -48,7 +48,7 @@ Reviewing process: - Description, default and example should be provided. - Ensure that option changes are backward compatible. - `mkRenamedOptionModuleWith` provides a way to make renamed option backward compatible. - - Use `lib.versionAtLeast config.system.stateVersion "23.11"` on backward incompatible changes which may corrupt, change or update the state stored on existing setups. + - Use `lib.versionAtLeast config.system.stateVersion "24.05"` on backward incompatible changes which may corrupt, change or update the state stored on existing setups. - Ensure that removed options are declared with `mkRemovedOptionModule`. - Ensure that changes that are not backward compatible are mentioned in release notes. - Ensure that documentations affected by the change is updated. diff --git a/nixos/doc/manual/development/bootspec.chapter.md b/nixos/doc/manual/development/bootspec.chapter.md index 96c12f24e7f1f..eb307c43088ed 100644 --- a/nixos/doc/manual/development/bootspec.chapter.md +++ b/nixos/doc/manual/development/bootspec.chapter.md @@ -1,17 +1,17 @@ -# Experimental feature: Bootspec {#sec-experimental-bootspec} +# Bootspec {#sec-bootspec} -Bootspec is a experimental feature, introduced in the [RFC-0125 proposal](https://github.com/NixOS/rfcs/pull/125), the reference implementation can be found [there](https://github.com/NixOS/nixpkgs/pull/172237) in order to standardize bootloader support -and advanced boot workflows such as SecureBoot and potentially more. +Bootspec is a feature introduced in [RFC-0125](https://github.com/NixOS/rfcs/pull/125) in order to standardize bootloader support and advanced boot workflows such as SecureBoot and potentially more. +The reference implementation can be found [here](https://github.com/NixOS/nixpkgs/pull/172237). -You can enable the creation of bootspec documents through [`boot.bootspec.enable = true`](options.html#opt-boot.bootspec.enable), which will prompt a warning until [RFC-0125](https://github.com/NixOS/rfcs/pull/125) is officially merged. +The creation of bootspec documents is enabled by default. -## Schema {#sec-experimental-bootspec-schema} +## Schema {#sec-bootspec-schema} The bootspec schema is versioned and validated against [a CUE schema file](https://cuelang.org/) which should considered as the source of truth for your applications. You will find the current version [here](../../../modules/system/activation/bootspec.cue). -## Extensions mechanism {#sec-experimental-bootspec-extensions} +## Extensions mechanism {#sec-bootspec-extensions} Bootspec cannot account for all usecases. @@ -29,8 +29,9 @@ An example for SecureBoot is to get the Nix store path to `/etc/os-release` in o To reduce incompatibility and prevent names from clashing between applications, it is **highly recommended** to use a unique namespace for your extensions. -## External bootloaders {#sec-experimental-bootspec-external-bootloaders} +## External bootloaders {#sec-bootspec-external-bootloaders} It is possible to enable your own bootloader through [`boot.loader.external.installHook`](options.html#opt-boot.loader.external.installHook) which can wrap an existing bootloader. -Currently, there is no good story to compose existing bootloaders to enrich their features, e.g. SecureBoot, etc. It will be necessary to reimplement or reuse existing parts. +Currently, there is no good story to compose existing bootloaders to enrich their features, e.g. SecureBoot, etc. +It will be necessary to reimplement or reuse existing parts. diff --git a/nixos/doc/manual/development/option-declarations.section.md b/nixos/doc/manual/development/option-declarations.section.md index 325f4d11cb083..ee4540d0cf6fd 100644 --- a/nixos/doc/manual/development/option-declarations.section.md +++ b/nixos/doc/manual/development/option-declarations.section.md @@ -173,7 +173,7 @@ lib.mkOption { ## Extensible Option Types {#sec-option-declarations-eot} -Extensible option types is a feature that allow to extend certain types +Extensible option types is a feature that allows to extend certain types declaration through multiple module files. This feature only work with a restricted set of types, namely `enum` and `submodules` and any composed forms of them. diff --git a/nixos/doc/manual/development/running-nixos-tests-interactively.section.md b/nixos/doc/manual/development/running-nixos-tests-interactively.section.md index 4b8385d7e0d94..422dbf174ad56 100644 --- a/nixos/doc/manual/development/running-nixos-tests-interactively.section.md +++ b/nixos/doc/manual/development/running-nixos-tests-interactively.section.md @@ -44,7 +44,7 @@ As an alternative, you can proxy the guest shell to a local TCP server by first starting a TCP server in a terminal using the command: ```ShellSession -$ socat 'READLINE,PROMPT=$ ' tcp-listen:4444,reuseaddr` +$ socat 'READLINE,PROMPT=$ ' tcp-listen:4444,reuseaddr ``` In the terminal where the test driver is running, connect to this server by diff --git a/nixos/doc/manual/installation/upgrading.chapter.md b/nixos/doc/manual/installation/upgrading.chapter.md index 11fc65502f953..1a3fc10ec8005 100644 --- a/nixos/doc/manual/installation/upgrading.chapter.md +++ b/nixos/doc/manual/installation/upgrading.chapter.md @@ -6,7 +6,7 @@ expressions and associated binaries. The NixOS channels are updated automatically from NixOS's Git repository after certain tests have passed and all packages have been built. These channels are: -- *Stable channels*, such as [`nixos-23.11`](https://channels.nixos.org/nixos-23.11). +- *Stable channels*, such as [`nixos-24.05`](https://channels.nixos.org/nixos-24.05). These only get conservative bug fixes and package upgrades. For instance, a channel update may cause the Linux kernel on your system to be upgraded from 4.19.34 to 4.19.38 (a minor bug fix), but not @@ -19,7 +19,7 @@ passed and all packages have been built. These channels are: radical changes between channel updates. It's not recommended for production systems. -- *Small channels*, such as [`nixos-23.11-small`](https://channels.nixos.org/nixos-23.11-small) +- *Small channels*, such as [`nixos-24.05-small`](https://channels.nixos.org/nixos-24.05-small) or [`nixos-unstable-small`](https://channels.nixos.org/nixos-unstable-small). These are identical to the stable and unstable channels described above, except that they contain fewer binary packages. This means they get updated @@ -38,8 +38,8 @@ supported stable release. When you first install NixOS, you're automatically subscribed to the NixOS channel that corresponds to your installation source. For -instance, if you installed from a 23.11 ISO, you will be subscribed to -the `nixos-23.11` channel. To see which NixOS channel you're subscribed +instance, if you installed from a 24.05 ISO, you will be subscribed to +the `nixos-24.05` channel. To see which NixOS channel you're subscribed to, run the following as root: ```ShellSession @@ -54,16 +54,16 @@ To switch to a different NixOS channel, do ``` (Be sure to include the `nixos` parameter at the end.) For instance, to -use the NixOS 23.11 stable channel: +use the NixOS 24.05 stable channel: ```ShellSession -# nix-channel --add https://channels.nixos.org/nixos-23.11 nixos +# nix-channel --add https://channels.nixos.org/nixos-24.05 nixos ``` If you have a server, you may want to use the "small" channel instead: ```ShellSession -# nix-channel --add https://channels.nixos.org/nixos-23.11-small nixos +# nix-channel --add https://channels.nixos.org/nixos-24.05-small nixos ``` And if you want to live on the bleeding edge: @@ -117,6 +117,6 @@ modules. You can also specify a channel explicitly, e.g. ```nix { - system.autoUpgrade.channel = "https://channels.nixos.org/nixos-23.11"; + system.autoUpgrade.channel = "https://channels.nixos.org/nixos-24.05"; } ``` diff --git a/nixos/doc/manual/release-notes/release-notes.md b/nixos/doc/manual/release-notes/release-notes.md index 0514a1b0044af..24494ed95ca88 100644 --- a/nixos/doc/manual/release-notes/release-notes.md +++ b/nixos/doc/manual/release-notes/release-notes.md @@ -3,6 +3,7 @@ This section lists the release notes for each stable version of NixOS and current unstable revision. ```{=include=} sections +rl-2411.section.md rl-2405.section.md rl-2311.section.md rl-2305.section.md diff --git a/nixos/doc/manual/release-notes/rl-2111.section.md b/nixos/doc/manual/release-notes/rl-2111.section.md index 8edf4fd35e4fb..4143f440f2890 100644 --- a/nixos/doc/manual/release-notes/rl-2111.section.md +++ b/nixos/doc/manual/release-notes/rl-2111.section.md @@ -146,7 +146,7 @@ In addition to numerous new and upgraded packages, this release has the followin - [touchegg](https://github.com/JoseExposito/touchegg), a multi-touch gesture recognizer. Available as [services.touchegg](#opt-services.touchegg.enable). -- [pantheon-tweaks](https://github.com/pantheon-tweaks/pantheon-tweaks), an unofficial system settings panel for Pantheon. Available as [programs.pantheon-tweaks](#opt-programs.pantheon-tweaks.enable). +- [pantheon-tweaks](https://github.com/pantheon-tweaks/pantheon-tweaks), an unofficial system settings panel for Pantheon. Available as `programs.pantheon-tweaks`. - [joycond](https://github.com/DanielOgorchock/joycond), a service that uses `hid-nintendo` to provide nintendo joycond pairing and better nintendo switch pro controller support. diff --git a/nixos/doc/manual/release-notes/rl-2211.section.md b/nixos/doc/manual/release-notes/rl-2211.section.md index 77cb6c9baadbc..4630b0987436c 100644 --- a/nixos/doc/manual/release-notes/rl-2211.section.md +++ b/nixos/doc/manual/release-notes/rl-2211.section.md @@ -366,7 +366,7 @@ In addition to numerous new and upgraded packages, this release includes the fol __Note:__ secrets from these files will be leaked into the store unless you use a [**file**-provider or env-var](https://grafana.com/docs/grafana/latest/setup-grafana/configure-grafana/#file-provider) for secrets! - - [services.grafana.provision.notifiers](#opt-services.grafana.provision.notifiers) is not affected by this change because + - `services.grafana.provision.notifiers` is not affected by this change because this feature is deprecated by Grafana and will probably be removed in Grafana 10. It's recommended to use `services.grafana.provision.alerting.contactPoints` instead. diff --git a/nixos/doc/manual/release-notes/rl-2405.section.md b/nixos/doc/manual/release-notes/rl-2405.section.md index d6b8ffe8609fa..165e3e13a78ef 100644 --- a/nixos/doc/manual/release-notes/rl-2405.section.md +++ b/nixos/doc/manual/release-notes/rl-2405.section.md @@ -1,4 +1,4 @@ -# Release 24.05 (“Uakari”, 2024.05/??) {#sec-release-24.05} +# Release 24.05 (“Uakari”, 2024.05/31) {#sec-release-24.05} Support is planned until the end of December 2024, handing over to 24.11. @@ -6,60 +6,29 @@ Support is planned until the end of December 2024, handing over to 24.11. In addition to numerous new and upgraded packages, this release has the following highlights: - - -- `cryptsetup` has been upgraded from 2.6.1 to 2.7.0. Cryptsetup is a critical component enabling LUKS-based (but not only) full disk encryption. - Take the time to review [the release notes](https://gitlab.com/cryptsetup/cryptsetup/-/raw/v2.7.0/docs/v2.7.0-ReleaseNotes). - One of the highlights is that it is now possible to use hardware OPAL-based encryption of your disk with `cryptsetup`. It has a lot of caveats, see the above notes for the full details. - -- `screen`'s module has been cleaned, and will now require you to set `programs.screen.enable` in order to populate `screenrc` and add the program to the environment. - -- `linuxPackages_testing_bcachefs` is now fully deprecated by `linuxPackages_latest`, and is therefore no longer available. + - The default kernel package has been updated from 6.1 to 6.6. All supported kernels remain available. +- For each supporting version of the Linux kernel, firmware blobs + are compressed with zstd. For firmware blobs this means an increase of 4.4% in size, however + a significantly higher decompression speed. + - NixOS now installs a stub ELF loader that prints an informative error message when users attempt to run binaries not made for NixOS. - - This can be disabled through the `environment.stub-ld.enable` option. - - If you use `programs.nix-ld.enable`, no changes are needed. The stub will be disabled automatically. + - This can be disabled through the `environment.stub-ld.enable` option. + - If you use `programs.nix-ld.enable`, no changes are needed. The stub will be disabled automatically. - On flake-based NixOS configurations using `nixpkgs.lib.nixosSystem`, NixOS will automatically set `NIX_PATH` and the system-wide flake registry (`/etc/nix/registry.json`) to point `` and the unqualified flake path `nixpkgs` to the version of nixpkgs used to build the system. This makes `nix run nixpkgs#hello` and `nix-build '' -A hello` work out of the box with no added configuration, reusing dependencies already on the system. - This may be undesirable if nix commands are not going to be run on the built system since it adds nixpkgs to the system closure. For such closure-size-constrained non-interactive systems, this setting should be disabled. - - To disable this, set [nixpkgs.flake.setNixPath](#opt-nixpkgs.flake.setNixPath) and [nixpkgs.flake.setFlakeRegistry](#opt-nixpkgs.flake.setFlakeRegistry) to false. - -- `nixVersions.unstable` was removed. Instead the following attributes are provided: - - `nixVersions.git` which tracks the latest Nix master and is roughly updated once a week. This is intended to enable people to easily test unreleased changes of Nix to catch regressions earlier. - - `nixVersions.latest` which points to the latest Nix version packaged in nixpkgs. - -- `julia` environments can now be built with arbitrary packages from the ecosystem using the `.withPackages` function. For example: `julia.withPackages ["Plots"]`. - -- `pipewire` and `wireplumber` modules have removed support for using -`environment.etc."pipewire/..."` and `environment.etc."wireplumber/..."`. -Use `services.pipewire.extraConfig` or `services.pipewire.configPackages` for PipeWire and -`services.pipewire.wireplumber.configPackages` for WirePlumber instead." - -- `teleport` has been upgraded from major version 14 to major version 15. - Refer to upstream [upgrade instructions](https://goteleport.com/docs/management/operations/upgrading/) - and release notes for [v15](https://goteleport.com/docs/changelog/#1500-013124). - -- `systemd.sysusers.enable` option was added. If enabled, users and - groups are created with systemd-sysusers instead of with a custom perl script. - -- `virtualisation.docker.enableNvidia` and `virtualisation.podman.enableNvidia` options are deprecated. `hardware.nvidia-container-toolkit.enable` should be used instead. This option will expose GPUs on containers with the `--device` CLI option. This is supported by Docker 25, Podman 3.2.0 and Singularity 4. Any container runtime that supports the CDI specification will take advantage of this feature. - -- `system.etc.overlay.enable` option was added. If enabled, `/etc` is - mounted via an overlayfs instead of being created by a custom perl script. + This may be undesirable if Nix commands are not going to be run on the built system since it adds nixpkgs to the system closure. For such closure-size-constrained non-interactive systems, this setting should be disabled. -- For each supporting version of the Linux kernel firmware blobs - are compressed with zstd. For firmware blobs this means an increase of 4.4% in size, however - a significantly higher decompression speed. + To disable it, set [nixpkgs.flake.setNixPath](#opt-nixpkgs.flake.setNixPath) and [nixpkgs.flake.setFlakeRegistry](#opt-nixpkgs.flake.setFlakeRegistry) to false. - NixOS AMIs are now uploaded regularly to a new AWS Account. Instructions on how to use them can be found on . - We are working on integration the data into the NixOS homepage. + We are working on integrating the data into the NixOS homepage. The list in `nixos/modules/virtualisation/amazon-ec2-amis.nix` will stop being updated and will be removed in the future. @@ -73,274 +42,318 @@ Use `services.pipewire.extraConfig` or `services.pipewire.configPackages` for Pi } ``` -- `virtialisation.incus` now defaults to the newly-added `incus-lts` release (v6.0.x). Users who wish to continue using the non-LTS release will need to set `virtualisation.incus.package = pkgs.incus`. Stable release users are encouraged to stay on the LTS release as non-LTS releases will by default not be backported. +- Cinnamon has been updated to 6.0. Please be aware that the [Wayland session](https://blog.linuxmint.com/?p=4591) is still experimental in this release and could potentially [affect Xorg sessions](https://blog.linuxmint.com/?p=4639). We suggest a reboot when switching between sessions. -- Canonical `lxd` has been upgraded to v5.21.x, an LTS release. The LTS release is now the only supported LXD release. Users are encouraged to [migrate to Incus](https://linuxcontainers.org/incus/docs/main/howto/server_migrate_lxd/) for better support on NixOS. +- GNOME has been updated to 46 "Kathmandu". Refer to the [release notes](https://release.gnome.org/46/) for more details. Notably this release brings experimental VRR support, default GTK renderer changes and WebDAV support in Online Accounts. This release we have also stopped including the legacy and unsupported Adwaita-Dark theme by default. -- `lua` interpreters default LUA_PATH and LUA_CPATH are not overriden by nixpkgs - anymore, we patch LUA_ROOT instead which is more respectful to upstream. +- Lomiri (formerly known as Unity8) desktop mode, using Mir 2.x to function as a Wayland compositor, is now available and can be installed with `services.desktopManager.lomiri.enable = true`. Note that some core applications, services and indicators have yet to be packaged, and some functions may remain incomplete, but the base experience should be there. -- `plasma6` is now available and can be installed with `services.xserver.desktopManager.plasma6.enable = true;`. Plasma 5 will likely be deprecated in the next release (24.11). Note that Plasma 6 runs as Wayland by default, and the X11 session needs to be explicitly selected if necessary. +- LXQt has been updated to 2.0, which is based on Qt 6 and features Wayland support for many applications. -- `lomiri` (formerly known as Unity8) desktop mode, using Mir 2.x to function as a Wayland compositor, is now available and can be installed with `services.desktopManager.lomiri.enable = true`. Note that some core applications, services and indicators have yet to be packaged, and some functions may remain incomplete, but the base experience should be there. +- MATE has been updated to 1.28. + - To properly support panel plugins built with Wayland (in-process) support, we are introducing the `services.xserver.desktopManager.mate.extraPanelApplets` option, please use that for installing panel applets. + - Similarly, please use the `services.xserver.desktopManager.mate.extraCajaExtensions` option for installing Caja extensions. + - To use the Wayland session, enable `services.xserver.desktopManager.mate.enableWaylandSession`. This is opt-in for now as it is in early an stage and introduces a new set of Wayfire closures. Due to [known issues with LightDM](https://github.com/canonical/lightdm/issues/63), we suggest using SDDM as the display manager. -## New Services {#sec-release-24.05-new-services} +- Plasma 6 is now available and can be installed with `services.desktopManager.plasma6.enable = true;`. Plasma 5 will likely be deprecated in the next release (24.11). Note that Plasma 6 runs as Wayland by default, and the X11 session needs to be explicitly selected if necessary. - +## New Services {#sec-release-24.05-new-services} -- [ownCloud Infinite Scale Stack](https://owncloud.com/infinite-scale-4-0/), a modern and scalable rewrite of ownCloud. + -- [Handheld Daemon](https://github.com/hhd-dev/hhd), support for gaming handhelds like the Legion Go, ROG Ally, and GPD Win. Available as [services.handheld-daemon](#opt-services.handheld-daemon.enable). +- [Anki Sync Server](https://docs.ankiweb.net/sync-server.html), the official sync server built into recent versions of Anki. Available as [services.anki-sync-server](#opt-services.anki-sync-server.enable). +The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been marked deprecated and will be dropped after 24.05 due to lack of maintenance of the anki-sync-server software. -- [Guix](https://guix.gnu.org), a functional package manager inspired by Nix. Available as [services.guix](#opt-services.guix.enable). +- [ALVR](https://github.com/alvr-org/alvr), a VR desktop streamer. Available as [programs.alvr](#opt-programs.alvr.enable). -- [PhotonVision](https://photonvision.org/), a free, fast, and easy-to-use computer vision solution for the FIRST® Robotics Competition. +- [AppImage](https://appimage.org/), a tool to package desktop applications, now has a `binfmt` option to support running AppImages seamlessly on NixOS. Available as [programs.appimage.binfmt](#opt-programs.appimage.binfmt). -- [clatd](https://github.com/toreanderson/clatd), a CLAT / SIIT-DC Edge Relay implementation for Linux. +- [armagetronad](https://wiki.armagetronad.org), a mid-2000s 3D lightcycle game widely played at iD Tech Camps. You can define multiple servers using `services.armagetronad..enable`. -- [pyLoad](https://pyload.net/), a FOSS download manager written in Python. Available as [services.pyload](#opt-services.pyload.enable). +- [BenchExec](https://github.com/sosy-lab/benchexec), a framework for reliable benchmarking and resource measurement, available as [programs.benchexec](#opt-programs.benchexec.enable), + as well as related programs + [CPU Energy Meter](https://github.com/sosy-lab/cpu-energy-meter), available as [programs.cpu-energy-meter](#opt-programs.cpu-energy-meter.enable), and + [PQoS Wrapper](https://gitlab.com/sosy-lab/software/pqos-wrapper), available as [programs.pqos-wrapper](#opt-programs.pqos-wrapper.enable). -- [maubot](https://github.com/maubot/maubot), a plugin-based Matrix bot framework. Available as [services.maubot](#opt-services.maubot.enable). +- [Bluemap](https://bluemap.bluecolored.de/), a 3D minecraft map renderer. Available as [services.bluemap](#opt-services.bluemap.enable). -- [ryzen-monitor-ng](https://github.com/mann1x/ryzen_monitor_ng), a desktop AMD CPU power monitor and controller, similar to Ryzen Master but for Linux. Available as [programs.ryzen-monitor-ng](#opt-programs.ryzen-monitor-ng.enable). +- [clatd](https://github.com/toreanderson/clatd), a CLAT / SIIT-DC Edge Relay implementation for Linux. -- [ryzen-smu](https://gitlab.com/leogx9r/ryzen_smu), Linux kernel driver to expose the SMU (System Management Unit) for certain AMD Ryzen Processors. Includes the userspace program `monitor_cpu`. Available at [hardward.cpu.amd.ryzen-smu](#opt-hardware.cpu.amd.ryzen-smu.enable). +- [Clevis](https://github.com/latchset/clevis), a pluggable framework for automated decryption, used to unlock encrypted devices in initrd. Available as [boot.initrd.clevis.enable](#opt-boot.initrd.clevis.enable). -- `systemd`'s `gateway`, `upload`, and `remote` services, which provide ways of sending journals across the network. Enable using [services.journald.gateway](#opt-services.journald.gateway.enable), [services.journald.upload](#opt-services.journald.upload.enable), and [services.journald.remote](#opt-services.journald.remote.enable). +- [CommaFeed](https://github.com/Athou/commafeed), a Google Reader-inspired self-hosted RSS reader. Available as [services.commafeed](#opt-services.commafeed.enable). -- [GNS3](https://www.gns3.com/), a network software emulator. Available as [services.gns3-server](#opt-services.gns3-server.enable). +- [davis](https://github.com/tchapi/davis), a simple CardDav and CalDav server inspired by Baïkal. Available as [services.davis](#opt-services.davis.enable). -- [pretalx](https://github.com/pretalx/pretalx), a conference planning tool. Available as [services.pretalx](#opt-services.pretalx.enable). +- [db-rest](https://github.com/derhuerst/db-rest), a wrapper around Deutsche Bahn's internal API for public transport data. Available as [services.db-rest](#opt-services.db-rest.enable). - [dnsproxy](https://github.com/AdguardTeam/dnsproxy), a simple DNS proxy with DoH, DoT, DoQ and DNSCrypt support. Available as [services.dnsproxy](#opt-services.dnsproxy.enable). -- [manticoresearch](https://manticoresearch.com), easy to use open source fast database for search. Available as [services.manticore](#opt-services.manticore.enable). +- [FCast Receiver](https://fcast.org), an open-source alternative to Chromecast and AirPlay. Available as [programs.fcast-receiver](#opt-programs.fcast-receiver.enable). -- [rspamd-trainer](https://gitlab.com/onlime/rspamd-trainer), script triggered by a helper which reads mails from a specific mail inbox and feeds them into rspamd for spam/ham training. +- [FileSender](https://filesender.org/), a file sharing software. Available as [services.filesender](#opt-services.filesender.enable). -- [ollama](https://ollama.ai), server for running large language models locally. +- [Firefly-iii](https://www.firefly-iii.org), a free and open source personal finance manager. Available as [services.firefly-iii](#opt-services.firefly-iii.enable). -- [Mihomo](https://github.com/MetaCubeX/mihomo/tree/Alpha), a rule-based proxy in Go. Available as [services.mihomo.enable](#opt-services.mihomo.enable). +- [Flarum](https://flarum.org/), a delightfully simple discussion platform for your website. Available as [services.flarum](#opt-services.flarum.enable). -- [hebbot](https://github.com/haecker-felix/hebbot), a Matrix bot to generate "This Week in X" like blog posts. Available as [services.hebbot](#opt-services.hebbot.enable). +- [fritz-exporter](https://github.com/pdreker/fritz_exporter), a Prometheus exporter for extracting metrics from [FRITZ!](https://avm.de/produkte/) devices. Available as [services.prometheus.exporters.fritz](#opt-services.prometheus.exporters.fritz.enable). -- [Workout-tracker](https://github.com/jovandeginste/workout-tracker), a workout tracking web application for personal use. +- [GNS3](https://www.gns3.com/), a network software emulator. Available as [services.gns3-server](#opt-services.gns3-server.enable). -- [Python Matter Server](https://github.com/home-assistant-libs/python-matter-server), a - Matter Controller Server exposing websocket connections for use with other services, notably Home Assistant. - Available as [services.matter-server](#opt-services.matter-server.enable). +- [go-camo](https://github.com/cactus/go-camo), a secure image proxy server. Available as [services.go-camo](#opt-services.go-camo.enable). -- [db-rest](https://github.com/derhuerst/db-rest), a wrapper around Deutsche Bahn's internal API for public transport data. Available as [services.db-rest](#opt-services.db-rest.enable). +- [Guix](https://guix.gnu.org), a functional package manager inspired by Nix. Available as [services.guix](#opt-services.guix.enable). -- [mautrix-signal](https://github.com/mautrix/signal), a Matrix-Signal puppeting bridge. Available as [services.mautrix-signal](#opt-services.mautrix-signal.enable). +- [Handheld Daemon](https://github.com/hhd-dev/hhd), support for gaming handhelds like the Legion Go, ROG Ally, and GPD Win. Available as [services.handheld-daemon](#opt-services.handheld-daemon.enable). -- [Anki Sync Server](https://docs.ankiweb.net/sync-server.html), the official sync server built into recent versions of Anki. Available as [services.anki-sync-server](#opt-services.anki-sync-server.enable). -The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been marked deprecated and will be dropped after 24.05 due to lack of maintenance of the anki-sync-server software. +- [hebbot](https://github.com/haecker-felix/hebbot), a Matrix bot to generate "This Week in X" like blog posts. Available as [services.hebbot](#opt-services.hebbot.enable). -- [mautrix-meta](https://github.com/mautrix/meta), a Matrix <-> Facebook and Matrix <-> Instagram hybrid puppeting/relaybot bridge. Available as services.mautrix-meta. +- [inadyn](https://github.com/troglobit/inadyn), a Dynamic DNS client with built-in support for multiple providers. Available as [services.inadyn](#opt-services.inadyn.enable). + +- [intel-gpu-tools](https://drm.pages.freedesktop.org/igt-gpu-tools), tools for development and testing of the Intel DRM driver. Available as [hardware.intel-gpu-tools](#opt-hardware.intel-gpu-tools.enable). + +- [isolate](https://github.com/ioi/isolate), a sandbox for securely executing untrusted programs. Available as [security.isolate](#opt-security.isolate.enable). - [Jottacloud Command-line Tool](https://docs.jottacloud.com/en/articles/1436834-jottacloud-command-line-tool), a CLI for the [Jottacloud](https://jottacloud.com/) cloud storage provider. Available as [services.jotta-cli](#opt-services.jotta-cli.enable). -- [transfer-sh](https://github.com/dutchcoders/transfer.sh), a tool that supports easy and fast file sharing from the command-line. Available as [services.transfer-sh](#opt-services.transfer-sh.enable). +- [keto](https://www.ory.sh/keto/), a permission & access control server, the first open source implementation of [*Zanzibar: Google's Consistent, Global Authorization System*](https://research.google/pubs/zanzibar-googles-consistent-global-authorization-system/). -- [FCast Receiver](https://fcast.org), an open-source alternative to Chromecast and AirPlay. Available as [programs.fcast-receiver](#opt-programs.fcast-receiver.enable). +- [manticoresearch](https://manticoresearch.com), easy to use open source fast database for search. Available as [services.manticore](#opt-services.manticore.enable). -- [MollySocket](https://github.com/mollyim/mollysocket) which allows getting Signal notifications via UnifiedPush. +- [maubot](https://github.com/maubot/maubot), a plugin-based Matrix bot framework. Available as [services.maubot](#opt-services.maubot.enable). -- [Suwayomi Server](https://github.com/Suwayomi/Suwayomi-Server), a free and open source manga reader server that runs extensions built for [Tachiyomi](https://tachiyomi.org). Available as [services.suwayomi-server](#opt-services.suwayomi-server.enable). +- [mautrix-meta](https://github.com/mautrix/meta), a Matrix <-> Facebook and Matrix <-> Instagram hybrid puppeting/relaybot bridge. Available as services.mautrix-meta. -- [Netbird](https://netbird.io), an open-source VPN management platform, now has a self-hosted management server. Available as [services.netbird.server](#opt-services.netbird.server.enable). +- [mautrix-signal](https://github.com/mautrix/signal), a Matrix-Signal puppeting bridge. Available as [services.mautrix-signal](#opt-services.mautrix-signal.enable). -- [ping_exporter](https://github.com/czerwonk/ping_exporter), a Prometheus exporter for ICMP echo requests. Available as [services.prometheus.exporters.ping](#opt-services.prometheus.exporters.ping.enable). +- [Mealie](https://nightly.mealie.io/), a self-hosted recipe manager and meal planner with a RestAPI backend and a reactive frontend application built in NuxtJS for a pleasant user experience for the whole family. Available as [services.mealie](#opt-services.mealie.enable). -- [Prometheus DNSSEC Exporter](https://github.com/chrj/prometheus-dnssec-exporter), check for validity and expiration in DNSSEC signatures and expose metrics for Prometheus. Available as [services.prometheus.exporters.dnssec](#opt-services.prometheus.exporters.dnssec.enable). +- [MollySocket](https://github.com/mollyim/mollysocket) which allows getting Signal notifications via UnifiedPush. -- [TigerBeetle](https://tigerbeetle.com/), a distributed financial accounting database designed for mission critical safety and performance. Available as [services.tigerbeetle](#opt-services.tigerbeetle.enable). +- [microsocks](https://github.com/rofl0r/microsocks), a tiny, portable SOCKS5 server with very moderate resource usage. Available as [services.microsocks](#opt-services.microsocks.enable). -- [go-camo](https://github.com/cactus/go-camo), a secure image proxy server. Available as [services.go-camo](#opt-services.go-camo.enable). +- [Mihomo](https://github.com/MetaCubeX/mihomo/tree/Alpha), a rule-based proxy in Go. Available as [services.mihomo.enable](#opt-services.mihomo.enable). - [Monado](https://monado.freedesktop.org/), an open source XR runtime. Available as [services.monado](#opt-services.monado.enable). -- [intel-gpu-tools](https://drm.pages.freedesktop.org/igt-gpu-tools), tools for development and testing of the Intel DRM driver. Available as [hardware.intel-gpu-tools](#opt-hardware.intel-gpu-tools.enable). +- [Netbird](https://netbird.io), an open-source VPN management platform, now has a self-hosted management server. Available as [services.netbird.server](#opt-services.netbird.server.enable). -- [Pretix](https://pretix.eu/about/en/), an open source ticketing software for events. Available as [services.pretix](#opt-services.pretix.enable). +- [nh](https://github.com/viperML/nh), yet another Nix CLI helper. Available as [programs.nh](#opt-programs.nh.enable). -- [microsocks](https://github.com/rofl0r/microsocks), a tiny, portable SOCKS5 server with very moderate resource usage. Available as [services.microsocks](#opt-services.microsocks.enable). +- [oink](https://github.com/rlado/oink), a dynamic DNS client for Porkbun. Available as [services.oink](#opt-services.oink.enable). -- [inadyn](https://github.com/troglobit/inadyn), a Dynamic DNS client with built-in support for multiple providers. Available as [services.inadyn](#opt-services.inadyn.enable). +- [ollama](https://ollama.ai), server for running large language models locally. -- [Clevis](https://github.com/latchset/clevis), a pluggable framework for automated decryption, used to unlock encrypted devices in initrd. Available as [boot.initrd.clevis.enable](#opt-boot.initrd.clevis.enable). +- [nextjs-ollama-llm-ui](https://github.com/jakobhoeg/nextjs-ollama-llm-ui), light-weight frontend server to chat with Ollama models through a web app. -- [fritz-exporter](https://github.com/pdreker/fritz_exporter), a Prometheus exporter for extracting metrics from [FRITZ!](https://avm.de/produkte/) devices. Available as [services.prometheus.exporters.fritz](#opt-services.prometheus.exporters.fritz.enable). +- [ownCloud Infinite Scale Stack](https://owncloud.com/infinite-scale-4-0/), a modern and scalable rewrite of ownCloud. -- [armagetronad](https://wiki.armagetronad.org), a mid-2000s 3D lightcycle game widely played at iD Tech Camps. You can define multiple servers using `services.armagetronad..enable`. +- [PhotonVision](https://photonvision.org/), a free, fast, and easy-to-use computer vision solution for the FIRST® Robotics Competition. -- [wyoming-satellite](https://github.com/rhasspy/wyoming-satellite), a voice assistant satellite for Home Assistant using the Wyoming protocol. Available as [services.wyoming.satellite](#opt-services.wyoming.satellite.enable). +- [ping_exporter](https://github.com/czerwonk/ping_exporter), a Prometheus exporter for ICMP echo requests. Available as [services.prometheus.exporters.ping](#opt-services.prometheus.exporters.ping.enable). -- [TuxClocker](https://github.com/Lurkki14/tuxclocker), a hardware control and monitoring program. Available as [programs.tuxclocker](#opt-programs.tuxclocker.enable). +- [Pretix](https://pretix.eu/about/en/), an open source ticketing software for events. Available as [services.pretix](#opt-services.pretix.enable). -- [AppImage](https://appimage.org/), a tool to package desktop applications, now has a `binfmt` option to support running AppImages seamlessly on NixOS. Available as [programs.appimage.binfmt](#opt-programs.appimage.binfmt). +- [pretalx](https://github.com/pretalx/pretalx), a conference planning tool. Available as [services.pretalx](#opt-services.pretalx.enable). -- [nh](https://github.com/viperML/nh), yet another Nix CLI helper. Available as [programs.nh](#opt-programs.nh.enable). +- [private-gpt](https://github.com/zylon-ai/private-gpt), a service to interact with your documents using the power of LLMs, 100% privately, no data leaks. Available as [services.private-gpt](#opt-services.private-gpt.enable). -- [ALVR](https://github.com/alvr-org/alvr), a VR desktop streamer. Available as [programs.alvr](#opt-programs.alvr.enable). +- [Prometheus DNSSEC Exporter](https://github.com/chrj/prometheus-dnssec-exporter): check for validity and expiration in DNSSEC signatures and expose metrics for Prometheus. Available as [services.prometheus.exporters.dnssec](#opt-services.prometheus.exporters.dnssec.enable). -- [xdg-terminal-exec](https://github.com/Vladimir-csp/xdg-terminal-exec), the proposed Default Terminal Execution Specification. +- [prometheus-nats-exporter](https://github.com/nats-io/prometheus-nats-exporter), a Prometheus exporter for NATS. Available as [services.prometheus.exporters.nats](#opt-services.prometheus.exporters.nats.enable). -- [your_spotify](https://github.com/Yooooomi/your_spotify), a self hosted Spotify tracking dashboard. Available as [services.your_spotify](#opt-services.your_spotify.enable) +- [pyLoad](https://pyload.net/), a FOSS download manager written in Python. Available as [services.pyload](#opt-services.pyload.enable). + +- [Python Matter Server](https://github.com/home-assistant-libs/python-matter-server), a + Matter Controller Server exposing websocket connections for use with other services, notably Home Assistant. + Available as [services.matter-server](#opt-services.matter-server.enable). - [RustDesk](https://rustdesk.com), a full-featured open source remote control alternative for self-hosting and security with minimal configuration. Alternative to TeamViewer. Available as [services.rustdesk-server](#opt-services.rustdesk-server.enable). +- [ryzen-monitor-ng](https://github.com/mann1x/ryzen_monitor_ng), a desktop AMD CPU power monitor and controller, similar to Ryzen Master but for Linux. Available as [programs.ryzen-monitor-ng](#opt-programs.ryzen-monitor-ng.enable). + +- [ryzen-smu](https://gitlab.com/leogx9r/ryzen_smu), Linux kernel driver to expose the SMU (System Management Unit) for certain AMD Ryzen Processors. Includes the userspace program `monitor_cpu`. Available at [hardward.cpu.amd.ryzen-smu](#opt-hardware.cpu.amd.ryzen-smu.enable). + - [Scrutiny](https://github.com/AnalogJ/scrutiny), a S.M.A.R.T monitoring tool for hard disks with a web frontend. Available as [services.scrutiny](#opt-services.scrutiny.enable). -- [davis](https://github.com/tchapi/davis), a simple CardDav and CalDav server inspired by Baïkal. Available as [services.davis](#opt-services.davis.enable). +- [SimpleSAMLphp](https://simplesamlphp.org/), an application written in native PHP that deals with authentication (SQL, .htpasswd, YubiKey, LDAP, PAPI, Radius). Available as [services.simplesamlphp](#opt-services.simplesamlphp). -- [Firefly-iii](https://www.firefly-iii.org), a free and open source personal finance manager. Available as [services.firefly-iii](#opt-services.firefly-iii.enable). +- `systemd`'s `gateway`, `upload`, and `remote` services, which provide ways of sending journals across the network. Enable using [services.journald.gateway](#opt-services.journald.gateway.enable), [services.journald.upload](#opt-services.journald.upload.enable), and [services.journald.remote](#opt-services.journald.remote.enable). - [systemd-lock-handler](https://git.sr.ht/~whynothugo/systemd-lock-handler/), a bridge between logind D-Bus events and systemd targets. Available as [services.systemd-lock-handler.enable](#opt-services.systemd-lock-handler.enable). -- [wastebin](https://github.com/matze/wastebin), a pastebin server written in rust. Available as [services.wastebin](#opt-services.wastebin.enable). - -- [Mealie](https://nightly.mealie.io/), a self-hosted recipe manager and meal planner with a RestAPI backend and a reactive frontend application built in NuxtJS for a pleasant user experience for the whole family. Available as [services.mealie](#opt-services.mealie.enable). +- [rspamd-trainer](https://gitlab.com/onlime/rspamd-trainer), script triggered by a helper which reads mails from a specific mail inbox and feeds them into rspamd for spam/ham training. - [Sunshine](https://app.lizardbyte.dev/Sunshine), a self-hosted game stream host for Moonlight. Available as [services.sunshine](#opt-services.sunshine.enable). -- [Uni-Sync](https://github.com/EightB1ts/uni-sync), a synchronization tool for Lian Li Uni Controllers. Available as [hardware.uni-sync](#opt-hardware.uni-sync.enable). +- [Suwayomi Server](https://github.com/Suwayomi/Suwayomi-Server), a free and open source manga reader server that runs extensions built for [Tachiyomi](https://tachiyomi.org). Available as [services.suwayomi-server](#opt-services.suwayomi-server.enable). -- [prometheus-nats-exporter](https://github.com/nats-io/prometheus-nats-exporter), a Prometheus exporter for NATS. Available as [services.prometheus.exporters.nats](#opt-services.prometheus.exporters.nats.enable). +- [TigerBeetle](https://tigerbeetle.com/), a distributed financial accounting database designed for mission critical safety and performance. Available as [services.tigerbeetle](#opt-services.tigerbeetle.enable). -- [isolate](https://github.com/ioi/isolate), a sandbox for securely executing untrusted programs. Available as [security.isolate](#opt-security.isolate.enable). +- [transfer-sh](https://github.com/dutchcoders/transfer.sh), a tool that supports easy and fast file sharing from the command-line. Available as [services.transfer-sh](#opt-services.transfer-sh.enable). -- [ydotool](https://github.com/ReimuNotMoe/ydotool), a generic command-line automation tool now has a module. Available as [programs.ydotool](#opt-programs.ydotool.enable). +- [TuxClocker](https://github.com/Lurkki14/tuxclocker), a hardware control and monitoring program. Available as [programs.tuxclocker](#opt-programs.tuxclocker.enable). -- [private-gpt](https://github.com/zylon-ai/private-gpt), a service to interact with your documents using the power of LLMs, 100% privately, no data leaks. Available as [services.private-gpt](#opt-services.private-gpt.enable). +- [Uni-Sync](https://github.com/EightB1ts/uni-sync), a synchronization tool for Lian Li Uni Controllers. Available as [hardware.uni-sync](#opt-hardware.uni-sync.enable). -- [keto](https://www.ory.sh/keto/), a permission & access control server, the first open source implementation of ["Zanzibar: Google's Consistent, Global Authorization System"](https://research.google/pubs/zanzibar-googles-consistent-global-authorization-system/). +- [wastebin](https://github.com/matze/wastebin), a pastebin server written in rust. Available as [services.wastebin](#opt-services.wastebin.enable). -## Backward Incompatibilities {#sec-release-24.05-incompatibilities} +- [watchdogd](https://troglobit.com/projects/watchdogd/), a system and process supervisor using watchdog timers. Available as [services.watchdogd](#opt-services.watchdogd.enable). - +- [Workout-tracker](https://github.com/jovandeginste/workout-tracker), a workout tracking web application for personal use. -- `k3s`: was updated to version [v1.29](https://github.com/k3s-io/k3s/releases/tag/v1.29.1%2Bk3s2), all previous versions (k3s_1_26, k3s_1_27, k3s_1_28) will be removed. See [changelog and upgrade notes](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.29.md#urgent-upgrade-notes) for more information. +- [wyoming-satellite](https://github.com/rhasspy/wyoming-satellite), a voice assistant satellite for Home Assistant using the Wyoming protocol. Available as [services.wyoming.satellite](#opt-services.wyoming.satellite.enable). -- `himalaya` was updated to v1.0.0-beta.4, which introduces breaking changes. Check out the [release note](https://github.com/soywod/himalaya/releases/tag/v1.0.0-beta.4) for details. +- [xdg-terminal-exec](https://github.com/Vladimir-csp/xdg-terminal-exec), the proposed Default Terminal Execution Specification. -- `security.pam.enableSSHAgentAuth` was replaced by the `sshAgentAuth` attrset, and **only** - `authorized_keys` files listed in [`sshAgentAuth.authorizedKeysFiles`] are trusted, - defaulting to `/etc/ssh/authorized_keys.d/%u`. - ::: {.warning} - Users of {manpage}`pam_ssh_agent_auth(8)` must take care that the pubkeys they use (for instance with `sudo`) - are listed in [`sshAgentAuth.authorizedKeysFiles`]. - ::: - ::: {.note} - Previously, all `services.openssh.authorizedKeysFiles` were trusted, including `~/.ssh/authorized_keys`, - which results in an **insecure** configuration; see [#31611](https://github.com/NixOS/nixpkgs/issues/31611). - ::: +- [ydotool](https://github.com/ReimuNotMoe/ydotool), a generic command-line automation tool now has a module. Available as [programs.ydotool](#opt-programs.ydotool.enable). -[`sshAgentAuth.authorizedKeysFiles`]: #opt-security.pam.sshAgentAuth.authorizedKeysFiles +- [your_spotify](https://github.com/Yooooomi/your_spotify), a self hosted Spotify tracking dashboard. Available as [services.your_spotify](#opt-services.your_spotify.enable) -- The `power.ups` module now generates `upsd.conf`, `upsd.users` and `upsmon.conf` automatically from a set of new configuration options. This breaks compatibility with existing `power.ups` setups where these files were created manually. Back up these files before upgrading NixOS. +- [RKE2](https://github.com/rancher/rke2), also known as RKE Government, is Rancher's next-generation Kubernetes distribution. Available as [services.rke2](#opt-services.rke2.enable). -- `programs.nix-ld.libraries` no longer sets `baseLibraries` via the option's default but in config and now merges any additional libraries with the default ones. - This means that `lib.mkForce` must be used to clear the list of default libraries. +## Backward Incompatibilities {#sec-release-24.05-incompatibilities} -- `cudaPackages.autoAddOpenGLRunpathHook` and `cudaPackages.autoAddDriverRunpath` have been deprecated for `pkgs.autoAddDriverRunpath`. Functionality has not changed, but the setuphook has been renamed and moved to the top-level package scope. + -- `cudaPackages.autoFixElfFiles` has been deprecated for `pkgs.autoFixElfFiles`. Functionality has not changed, but the setuphook has been renamed and moved to the top-level package scope. +- `akkoma` now requires explicitly setting the base URL for uploaded media (`settings."Pleroma.Upload".base_url`), as well as for the media proxy if enabled (`settings."Media"`). + This is recommended to be a separate (sub)domain to the one Akkoma is hosted at. + See [here](https://meta.akkoma.dev/t/akkoma-stable-2024-03-securer-i-barely-know-her/681#explicit-upload-and-media-proxy-domains-5) for more details. - `appimageTools.wrapAppImage` now creates the binary at `$out/bin/${pname}` rather than `$out/bin/${pname}-${version}`, which will break downstream workarounds. -- `pdns` was updated to version [v4.9.x](https://doc.powerdns.com/authoritative/changelog/4.9.html), which introduces breaking changes. Check out the [Upgrade Notes](https://doc.powerdns.com/authoritative/upgrading.html#to-4-9-0) for details. +- `azure-cli` now has extension support. For example, to install the `aks-preview` extension, use -- `unrar` was updated to v7. See [changelog](https://www.rarlab.com/unrar7notes.htm) for more information. + ```nix + environment.systemPackages = [ + (azure-cli.withExtensions [ azure-cli.extensions.aks-preview ]) + ]; + ``` + To make the `azure-cli` immutable and prevent clashes in case `azure-cli` is also installed via other package managers, some configuration files were moved into the derivation. + This can be disabled by overriding `withImmutableConfig = false` when building `azure-cli`. -- `git-town` was updated from version 11 to 13. See the [changelog](https://github.com/git-town/git-town/blob/main/CHANGELOG.md#1300-2024-03-22) for breaking changes. +- `boot.supportedFilesystems` and `boot.initrd.supportedFilesystems` are now attribute sets instead of lists. Assignment from lists as done previously is still supported, but checking whether a filesystem is enabled must now by done using `supportedFilesystems.fs or false` instead of using `lib.elem "fs" supportedFilesystems` as was done previously. -- `k9s` was updated to v0.31. There have been various breaking changes in the config file format, - check out the changelog of [v0.29](https://github.com/derailed/k9s/releases/tag/v0.29.0), - [v0.30](https://github.com/derailed/k9s/releases/tag/v0.30.0) and - [v0.31](https://github.com/derailed/k9s/releases/tag/v0.31.0) for details. It is recommended - to back up your current configuration and let k9s recreate the new base configuration. +- `buildGoModule` now throws an error when `vendorHash` is not specified. `vendorSha256`, deprecated in Nixpkgs 23.11, is now ignored and is no longer a `vendorHash` alias. -- the .csv format used to define lua packages to be updated via - `luarocks-packages-updater` has changed: `src` (URL towards a git repository) has now become `rockspec` (URL towards a rockspec) to remove ambiguity regarding which rockspec to use and simplify implementation. +- `chromium` and `ungoogled-chromium` had a long-standing issue regarding Widevine DRM handling in nixpkgs fixed. + `chromium` now no longer automatically downloads Widevine when encountering DRM protected content. + To be able to play DRM protected content in `chromium`, you now have to explicitly opt-in as originally intended using `chromium.override { enableWideVine = true; }`. + This override was added almost 10 years ago. -- NixOS AMIs are now uploaded regularly to a new AWS Account. - Instructions on how to use them can be found on . - We are working on integration the data into the NixOS homepage. - The list in `nixos/modules/virtualisation/amazon-ec2-amis.nix` will stop - being updated and will be removed in the future. +- `craftos-pc` package has been updated to v2.8, which includes [breaking changes](https://github.com/MCJack123/craftos2/releases/tag/v2.8). + - Files are now handled in binary mode; this could break programs with embedded UTF-8 characters. + - The ROM was updated to match ComputerCraft version v1.109.2. + - The bundled Lua was updated to Lua v5.2, which includes breaking changes. See the [Lua manual](https://www.lua.org/manual/5.2/manual.html#8) for more information. + - The WebSocket API [was rewritten](https://github.com/MCJack123/craftos2/issues/337), which introduced breaking changes. -- The option `services.postgresql.ensureUsers._.ensurePermissions` has been removed as it is - not declarative and is broken with newer postgresql versions. Consider using - [](#opt-services.postgresql.ensureUsers._.ensureDBOwnership) - instead or a tool that is more suited for managing the data inside a postgresql database. +- `cryptsetup` has been upgraded from 2.6.1 to 2.7.0. Cryptsetup is a critical component enabling LUKS-based (but not only) full disk encryption. + Take the time to review [the release notes](https://gitlab.com/cryptsetup/cryptsetup/-/raw/v2.7.0/docs/v2.7.0-ReleaseNotes). + One of the highlights is that it is now possible to use hardware OPAL-based encryption of your disk with `cryptsetup`. It has a lot of caveats, see the above notes for the full details. -- `idris2` was updated to v0.7.0. This version introduces breaking changes. Check out the [changelog](https://github.com/idris-lang/Idris2/blob/v0.7.0/CHANGELOG.md#v070) for details. +- `crystal` package has been updated to 1.11.x, which has some breaking changes. + Refer to crystal's changelog for more information. ([v1.10](https://github.com/crystal-lang/crystal/blob/master/CHANGELOG.md#1100-2023-10-09), [v1.11](https://github.com/crystal-lang/crystal/blob/master/CHANGELOG.md#1110-2024-01-08)) -- `nvtop` family of packages was reorganized into nested attrset. `nvtop` has been renamed to `nvtopPackages.full`, and all `nvtop-{amd,nvidia,intel,msm}` packages are now named as `nvtopPackages.{amd,nvidia,intel,msm}`. +- `cudaPackages` package scope has been updated to `cudaPackages_12`. -- `neo4j` has been updated to version 5. You may want to read the [release notes for Neo4j 5](https://neo4j.com/release-notes/database/neo4j-5/). +- `cudaPackages.autoAddOpenGLRunpathHook` and `cudaPackages.autoAddDriverRunpath` have been deprecated for `pkgs.autoAddDriverRunpath`. Functionality has not changed, but the setuphook has been renamed and moved to the top-level package scope. -- `services.neo4j.allowUpgrade` was removed and no longer has any effect. Neo4j 5 supports automatic rolling upgrades. +- `cudaPackages.cudatoolkit` has been deprecated and replaced with a + symlink-based wrapper for the splayed redistributable CUDA packages. The + wrapper only includes tools and libraries necessary to build common packages + such as tensorflow. The original runfile-based `cudatoolkit` is still + available as `cudatoolkit-legacy-runfile`. -- `unifiLTS`, `unifi5` and `unifi6` have been removed, as they require MongoDB versions which are end-of-life. All these versions can be upgraded to `unifi7` directly. +- `cudaPackages.nsight_systems` now has most vendored third-party libraries removed, though we now only ship it for `cudaPackages_11_8` and later, due to outdated dependencies. Users comfortable with the vendored dependencies may use `overrideAttrs` to amend the `postPatch` phase and the `meta.broken` correspondingly. Alternatively, one could package the deprecated `boost170` locally, as required for `cudaPackages_11_4.nsight_systems`. -- `mongodb-4_4` has been removed as it has reached end of life. Consequently, `unifi7` and `unifi8` now use MongoDB 5.0 by default. +- `cudaPackages.autoFixElfFiles` has been deprecated for `pkgs.autoFixElfFiles`. Functionality has not changed, but the setuphook has been renamed and moved to the top-level package scope. -- `mongodb-5_0` and newer requires a cpu with the avx instruction set to run. +- `davfs2`'s `services.davfs2.extraConfig` setting has been deprecated and converted to the free-form type option named `services.davfs2.settings` according to RFC42. -- `nitter` requires a `guest_accounts.jsonl` to be provided as a path or loaded into the default location at `/var/lib/nitter/guest_accounts.jsonl`. See [Guest Account Branch Deployment](https://github.com/zedeus/nitter/wiki/Guest-Account-Branch-Deployment) for details. +- `dwarf-fortress` has been updated to version 50, which is identical to the version on Steam, but without the paid elements like tilepacks. + dfhack and Dwarf Therapist still work, and older versions are still packaged in case you'd like to roll back. Note that DF 50 saves will not be compatible with DF 0.47 and earlier. + See [Bay 12 Games](http://www.bay12games.com/dwarves/) for more details on what's new in Dwarf Fortress. -- `boot.supportedFilesystems` and `boot.initrd.supportedFilesystems` are now attribute sets instead of lists. Assignment from lists as done previously is still supported, but checking whether a filesystem is enabled must now by done using `supportedFilesystems.fs or false` instead of using `lib.elem "fs" supportedFilesystems` as was done previously. + - Running an earlier version can be achieved through an override: `dwarf-fortress-packages.dwarf-fortress-full.override { dfVersion = "0.47.5"; }` -- `services.aria2.rpcSecret` has been replaced with `services.aria2.rpcSecretFile`. - This was done so that secrets aren't stored in the world-readable nix store. - To migrate, you will have to create a file with the same exact string, and change - your module options to point to that file. For example, `services.aria2.rpcSecret = - "mysecret"` becomes `services.aria2.rpcSecretFile = "/path/to/secret_file"` - where the file `secret_file` contains the string `mysecret`. + - Ruby plugin support has been disabled in DFHack. Many of the Ruby plugins have been converted to Lua, and support was removed upstream due to frequent crashes. -- The `system.forbiddenDependenciesRegex` option has been renamed to `system.forbiddenDependenciesRegexes` and now has the type of `listOf string` instead of `string` to accept multiple regexes. +- `erlang-ls` package no longer ships the `els_dap` binary as of v0.51.0. -- `openssh`, `openssh_hpn` and `openssh_gssapi` are now compiled without support for the DSA signature algorithm as it is being deprecated upstream. Users still relying on DSA keys should consider upgrading - to another signature algorithm. However, for the time being it is possible to restore DSA key support using `override` to set `dsaKeysSupport = true`. +- `erlang_node_short_name`, `erlang_node_name`: `port` and `options` configuration parameters are gone, and have been replaced with an `environment` parameter. + Use the appropriate [environment variables](https://hexdocs.pm/livebook/readme.html#environment-variables) inside `environment` to configure the service instead. -- `buildGoModule` now throws an error when `vendorHash` is not specified. `vendorSha256`, deprecated in Nixpkgs 23.11, is now ignored and is no longer a `vendorHash` alias. +- `firefox-devedition`, `firefox-beta`, `firefox-esr` executable file names for now match their package names, which is consistent with the `firefox-*-bin` packages. The desktop entries are also updated so that you can have multiple editions of firefox in your app launcher. -- `services.invidious.settings.db.user`, the default database username has changed from `kemal` to `invidious`. Setups involving an externally-provisioned database (i.e. `services.invidious.database.createLocally == false`) should adjust their configuration accordingly. The old `kemal` user will not be removed automatically even when the database is provisioned automatically.(https://github.com/NixOS/nixpkgs/pull/265857). +- `gauge` now supports installing plugins using Nix. For the old imperative approach, switch to `gauge-unwrapped`. + You can load plugins from an existing gauge manifest file using `gauge.fromManifest ./path/to/manifest.json` or + specify plugins in Nix using `gauge.withPlugins (p: with p; [ js html-report xml-report ])`. -- `writeReferencesToFile` is deprecated in favour of the new trivial build helper `writeClosure`. The latter accepts a list of paths and has an unambiguous name and cleaner implementation. +- `gitea` has been updated to 1.21, which introduces several breaking changes, including: + - Custom themes and other assets that were previously stored in `custom/public/*` now belong in `custom/public/assets/*` + - New instances of Gitea using MySQL now ignore the `[database].CHARSET` config option and always use the `utf8mb4` charset, existing instances should migrate via the `gitea doctor convert` CLI command. -- `inetutils` now has a lower priority to avoid shadowing the commonly used `util-linux`. If one wishes to restore the default priority, simply use `lib.setPrio 5 inetutils` or override with `meta.priority = 5`. +- `git-town` was updated from version 11 to 13. See the [changelog](https://github.com/git-town/git-town/blob/main/CHANGELOG.md#1300-2024-03-22) for breaking changes. -- `paperless`' `services.paperless.extraConfig` setting has been removed and converted to the free-form type and option named `services.paperless.settings`. +- `gonic` has been updated to v0.16.4. Config now requires `playlists-path` to be set. See the rest of the [v0.16.0 release notes](https://github.com/sentriz/gonic/releases/tag/v0.16.0) for more details. -- `davfs2`' `services.davfs2.extraConfig` setting has been deprecated and converted to the free-form type option named `services.davfs2.settings` according to RFC42. +- `go-ethereum` has been updated to v1.14.3. Geth v1.14.0 introduced a brand new live-tracing feature, + which required a number of breaking internal API changes. If you had your own native tracers implemented before this change, + the [changelog](https://github.com/ethereum/go-ethereum/blob/master/core/tracing/CHANGELOG.md) contains the necessary steps needed to update your old code for the new APIs. + Geth v1.14.0 drops support for running pre-merge networks ([#29169](https://github.com/ethereum/go-ethereum/pull/29169)). + It also stops automatically constructing the pending block ([#28623](https://github.com/ethereum/go-ethereum/pull/28623)), + removes support for filtering pending logs, switched to using Go v1.22 by default (#28946), which means we've dropped support for Go v1.20. + See [the 1.14.0 release notes](https://github.com/ethereum/go-ethereum/releases/tag/v1.14.0) for more details. -- `services.homepage-dashboard` now takes its configuration using native Nix expressions, rather than dumping templated configurations into `/var/lib/homepage-dashboard` where they were previously managed manually. There are now new options which allow the configuration of bookmarks, services, widgets and custom CSS/JS natively in Nix. +- `grafana-loki` has been updated to 3.0.0, which includes [breaking changes](https://github.com/grafana/loki/releases/tag/v3.0.0). + +- `gtest` package has been updated past v1.13.0, which requires C++14 or higher. - `hare` may now be cross-compiled. For that to work, however, `haredoc` needed to stop being built together with it. Thus, the latter is now its own package with the name of `haredoc`. -- `network-interfaces.target` system target was removed as it has been deprecated for a long time. Use `network.target` instead. +- `himalaya` has been updated to v1.0.0-beta.4, which introduces breaking changes. Check out the [release note](https://github.com/soywod/himalaya/releases/tag/v1.0.0-beta.4) for details. -- `services.redis.vmOverCommit` now defaults to `true` and no longer enforces Transparent Hugepages (THP) to be disabled. Redis only works with THP configured to `madvise` which is the kernel's default. +- `halloy` has been updated to 2024.5, which introduced a breaking change by switching the config format from YAML to TOML. See for details. -- `azure-cli` now has extension support. For example, to install the `aks-preview` extension, use +- `hvm` was updated to version 2. - ```nix - environment.systemPackages = [ - (azure-cli.withExtensions [ azure-cli.extensions.aks-preview ]) - ]; - ``` - To make the `azure-cli` immutable and prevent clashes in case `azure-cli` is also installed via other package managers, some configuration files were moved into the derivation. - This can be disabled by overriding `withImmutableConfig = false` when building `azure-cli`. +- `icu` no longer includes `install-sh` and `mkinstalldirs` in the shared folder. -- `services.frp.settings` now generates the frp configuration file in TOML format as [recommended by upstream](https://github.com/fatedier/frp#configuration-files), instead of the legacy INI format. This has also introduced other changes in the configuration file structure and options. - - The `settings.common` section in the configuration is no longer valid and all the options form inside it now goes directly under `settings`. - - The `_` separating words in the configuration options is removed so the options are now in camel case. For example: `server_addr` becomes `serverAddr`, `server_port` becomes `serverPort` etc. - - Proxies are now defined with a new option `settings.proxies` which takes a list of proxies. - - Consult the [upstream documentation](https://github.com/fatedier/frp#example-usage) for more details on the changes. +- `idris2` was updated to v0.7.0. This version introduces breaking changes. Check out the [changelog](https://github.com/idris-lang/Idris2/blob/v0.7.0/CHANGELOG.md#v070) for details. + +- `inetutils` now has a lower priority to avoid shadowing the commonly-used `util-linux`. If one wishes to restore the default priority, simply use `lib.setPrio 5 inetutils` or override with `meta.priority = 5`. + +- `jdt-language-server` package now uses upstream's provided python wrapper instead of our own custom wrapper. This results in the following breaking and notable changes: + + - The main binary for the package is now named `jdtls` instead of `jdt-language-server`, equivalent to what most editors expect the binary to be named. + + - JVM arguments should now be provided with the `--jvm-arg` flag instead of setting `JAVA_OPTS`. + + - The `-data` path is no longer required to run the package, and will be set to point to a folder in `$TMP` if missing. + +- `julia` environments can now be built with arbitrary packages from the ecosystem using the `.withPackages` function. For example: `julia.withPackages ["Plots"]`. + +- `k3s` has been updated to version [v1.30](https://github.com/k3s-io/k3s/releases/tag/v1.30.0%2Bk3s1), previous supported versions are available under release-specific names (e.g. k3s_1_27, k3s_1_28, and k3s_1_29) in order to help you migrate to the latest supported version. See [changelog and upgrade notes](https://github.com/kubernetes/kubernetes/blob/master/CHANGELOG/CHANGELOG-1.30.md#changelog-since-v1290) for more information. + +- `k9s` was updated to v0.31. There have been various breaking changes in the config file format, + check out the changelog of [v0.29](https://github.com/derailed/k9s/releases/tag/v0.29.0), + [v0.30](https://github.com/derailed/k9s/releases/tag/v0.30.0) and + [v0.31](https://github.com/derailed/k9s/releases/tag/v0.31.0) for details. It is recommended + to back up your current configuration and let k9s recreate the new base configuration. + +- `kanata` package has been updated to v1.6.1, which includes breaking changes. Check out the changelog of [v1.5.0](https://github.com/jtroo/kanata/releases/tag/v1.5.0) and [v1.6.0](https://github.com/jtroo/kanata/releases/tag/v1.6.0) for details. + +- `linuxPackages_testing_bcachefs` is now fully deprecated by `linuxPackages_latest`, and is therefore no longer available. + +- `livebook` package is now built as a `mix release` instead of an `escript`. + This means that configuration now has to be done using [environment variables](https://hexdocs.pm/livebook/readme.html#environment-variables) instead of command line arguments. + This has the further consequence that the `livebook` service configuration has changed. + +- `lua` interpreters default LUA_PATH and LUA_CPATH are not overriden by nixpkgs + anymore, we patch LUA_ROOT instead which is more respectful to upstream. + +- `luarocks-packages-updater`'s .csv format, used to define lua packages to be updated, has changed: `src` (URL of a git repository) has now become `rockspec` (URL of a rockspec) to remove ambiguity regarding which rockspec to use and simplify implementation. - `mkosi` was updated to v22. Parts of the user interface have changed. Consult the release notes of [v19](https://github.com/systemd/mkosi/releases/tag/v19), @@ -348,80 +361,121 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m [v21](https://github.com/systemd/mkosi/releases/tag/v21) and [v22](https://github.com/systemd/mkosi/releases/tag/v22) for a list of changes. -- `gonic` has been updated to v0.16.4. Config now requires `playlists-path` to be set. See the rest of the [v0.16.0 release notes](https://github.com/sentriz/gonic/releases/tag/v0.16.0) for more details. +- `mongodb-4_4` has been removed as it has reached end of life. Consequently, `unifi7` and `unifi8` now use MongoDB 5.0 by default. -- `services.vikunja` systemd service now uses `vikunja` as dynamic user instead of `vikunja-api`. Database users might need to be changed. +- `mongodb-5_0` and newer requires a cpu with the AVX instruction set to run. -- `services.vikunja.setupNginx` setting has been removed. Users now need to setup the webserver configuration on their own with a proxy pass to the vikunja service. +- `neo4j` has been updated to version 5. You may want to read the [release notes for Neo4j 5](https://neo4j.com/release-notes/database/neo4j-5/). -- `services.vmagent` module deprecates `dataDir`, `group` and `user` setting in favor of systemd provided CacheDirectory and DynamicUser. +- `netbox` was updated to v3.7. `services.netbox.package` still defaults + to v3.6 if `stateVersion` is earlier than 24.05. Refer to upstream's breaking + changes [for + v3.7.0](https://github.com/netbox-community/netbox/releases/tag/v3.7.0) and + upgrade NetBox by changing `services.netbox.package`. Database migrations + will be run automatically. -- `services.vmagent.remoteWriteUrl` setting has been renamed to `services.vmagent.remoteWrite.url` and now defaults to `null`. +- `network-interfaces.target` system target was removed as it has been deprecated for a long time. Use `network.target` instead. -- `woodpecker-*` packages have been updated to v2 which includes [breaking changes](https://woodpecker-ci.org/docs/next/migrations#200). +- `networking.iproute2.enable` now does not set `environment.etc."iproute2/rt_tables".text`. -- `services.nginx` will no longer advertise HTTP/3 availability automatically. This must now be manually added, preferably to each location block. - Example: + Setting `environment.etc."iproute2/{CONFIG_FILE_NAME}".text` will override the whole configuration file instead of appending it to the upstream configuration file. - ```nix - { - locations."/".extraConfig = '' - add_header Alt-Svc 'h3=":$server_port"; ma=86400'; - ''; - locations."^~ /assets/".extraConfig = '' - add_header Alt-Svc 'h3=":$server_port"; ma=86400'; - ''; - } - ``` + `CONFIG_FILE_NAME` includes `bpf_pinning`, `ematch_map`, `group`, `nl_protos`, `rt_dsfield`, `rt_protos`, `rt_realms`, `rt_scopes`, and `rt_tables`. + +- `nextcloud26` has been removed since it's not maintained anymore by upstream. The latest available version of Nextcloud is now v29 (available as `pkgs.nextcloud29`). The installation logic is as follows: + - If [`services.nextcloud.package`](#opt-services.nextcloud.package) is specified explicitly, this package will be installed (**recommended**). + - If [`system.stateVersion`](#opt-system.stateVersion) is >=24.05, `pkgs.nextcloud29` will be installed by default. + - If [`system.stateVersion`](#opt-system.stateVersion) is >=23.11, `pkgs.nextcloud27` will be installed by default. + - Please note that an upgrade from v27 (or older) to v29 directly is not possible. Please upgrade to `nextcloud28` (or earlier) first. Nextcloud prohibits skipping major versions while upgrading. You can upgrade by declaring [`services.nextcloud.package = pkgs.nextcloud28;`](options.html#opt-services.nextcloud.package). + - Known warnings after the upgrade are documented in [](#module-services-nextcloud-known-warnings) from now on. + - The "Photos" app only displays Media from inside the `Photos` directory. This can be changed manually in the "Photos" tab below "Photos settings". + +- `nitter` requires a `guest_accounts.jsonl` to be provided as a path or loaded into the default location at `/var/lib/nitter/guest_accounts.jsonl`. See [Guest Account Branch Deployment](https://github.com/zedeus/nitter/wiki/Guest-Account-Branch-Deployment) for details. + +- `nixVersions.unstable` was removed. Instead the following attributes are provided: + - `nixVersions.git` which tracks the latest Nix master and is roughly updated once a week. This is intended to enable people to easily test unreleased changes of Nix to catch regressions earlier. + - `nixVersions.latest` which points to the latest Nix version packaged in nixpkgs. + +- `nomad` has been updated - note that HashiCorp recommends updating one minor version at a time. Please check [their upgrade guide](https://developer.hashicorp.com/nomad/docs/upgrade) for information on safely updating clusters and potential breaking changes. + + - `nomad` is now Nomad 1.7.x. + + - `nomad_1_4` has been removed, as it is now unsupported upstream. + +- `nvtop` family of packages was reorganized into a nested attrset. `nvtop` has been renamed to `nvtopPackages.full`, and all `nvtop-{amd,nvidia,intel,msm}` packages are renamed to `nvtopPackages.{amd,nvidia,intel,msm}`. + +- `openssh`, `openssh_hpn` and `openssh_gssapi` are now compiled without support for the DSA signature algorithm as it is being deprecated upstream. Users still relying on DSA keys should consider upgrading + to another signature algorithm. However, for the time being it is possible to restore DSA key support using `override` to set `dsaKeysSupport = true`. - `optparse-bash` is now dropped due to upstream inactivity. Alternatives available in Nixpkgs include [`argc`](https://github.com/sigoden/argc), [`argbash`](https://github.com/matejak/argbash), [`bashly`](https://github.com/DannyBen/bashly) and [`gum`](https://github.com/charmbracelet/gum), to name a few. -- `kanata` package has been updated to v1.6.1, which includes breaking changes. Check out the changelog of [v1.5.0](https://github.com/jtroo/kanata/releases/tag/v1.5.0) and [v1.6.0](https://github.com/jtroo/kanata/releases/tag/v1.6.0) for details. +- `paperless`' `services.paperless.extraConfig` setting has been removed and converted to the free-form type and option named `services.paperless.settings`. -- `craftos-pc` package has been updated to v2.8, which includes [breaking changes](https://github.com/MCJack123/craftos2/releases/tag/v2.8). - - Files are now handled in binary mode; this could break programs with embedded UTF-8 characters. - - The ROM was updated to match ComputerCraft version v1.109.2. - - The bundled Lua was updated to Lua v5.2, which includes breaking changes. See the [Lua manual](https://www.lua.org/manual/5.2/manual.html#8) for more information. - - The WebSocket API [was rewritten](https://github.com/MCJack123/craftos2/issues/337), which introduced breaking changes. +- `pdns` was updated to version [v4.9.x](https://doc.powerdns.com/authoritative/changelog/4.9.html), which introduces breaking changes. Check out the [Upgrade Notes](https://doc.powerdns.com/authoritative/upgrading.html#to-4-9-0) for details. -- `gtest` package has been updated past v1.13.0, which requires C++14 or higher. +- `percona-server` now follows [the same two-fold release cycle](https://www.percona.com/blog/lts-and-innovation-releases-for-percona-server-for-mysql/) as Oracle MySQL and provides a *Long-Term-Support (LTS)* in parallel with a continuous-delivery *Innovation* release. `percona-server` defaults to `percona-server_lts`, will be backed by the same release branch throughout the lifetime of this stable NixOS release, and is still available under the versioned attribute `percona-server_8_0`. + The `percona-server_innovation` releases however have support periods shorter than the lifetime of this NixOS release and will continuously be updated to newer Percona releases. Note that Oracle considers the *Innovation* releases to be production-grade, but each release might include backwards-incompatible changes, even in its on-disk format. + The same release scheme is applied to the supporting `percona-xtrabackup` tool as well. -- Nextcloud 26 has been removed since it's not maintained anymore by upstream. +- `pipewire` and `wireplumber` modules have removed support for using +`environment.etc."pipewire/..."` and `environment.etc."wireplumber/..."`. +Use `services.pipewire.extraConfig` or `services.pipewire.configPackages` for PipeWire and +`services.pipewire.wireplumber.configPackages` for WirePlumber instead. -- The latest available version of Nextcloud is v29 (available as `pkgs.nextcloud29`). The installation logic is as follows: - - If [`services.nextcloud.package`](#opt-services.nextcloud.package) is specified explicitly, this package will be installed (**recommended**) - - If [`system.stateVersion`](#opt-system.stateVersion) is >=24.05, `pkgs.nextcloud29` will be installed by default. - - If [`system.stateVersion`](#opt-system.stateVersion) is >=23.11, `pkgs.nextcloud27` will be installed by default. - - Please note that an upgrade from v27 (or older) to v29 directly is not possible. Please upgrade to `nextcloud28` (or earlier) first. Nextcloud prohibits skipping major versions while upgrading. You can upgrade by declaring [`services.nextcloud.package = pkgs.nextcloud28;`](options.html#opt-services.nextcloud.package). - - Known warnings after the upgrade are documented in [](#module-services-nextcloud-known-warnings) from now on. - - The "Photos" app only displays Media from inside the `Photos` directory. This can be changed manually in the "Photos" tab below "Photos settings". +- `power.ups` now generates `upsd.conf`, `upsd.users` and `upsmon.conf` automatically from a set of new configuration options. This breaks compatibility with existing `power.ups` setups where these files were created manually. Back up these files before upgrading NixOS. -- The vendored third party libraries have been mostly removed from `cudaPackages.nsight_systems`, which we now only ship for `cudaPackages_11_8` and later due to outdated dependencies. Users comfortable with the vendored dependencies may use `overrideAttrs` to amend the `postPatch` phase and the `meta.broken` correspondingly. Alternatively, one could package the deprecated `boost170` locally, as required for `cudaPackages_11_4.nsight_systems`. +- `programs.nix-ld.libraries` no longer sets `baseLibraries` via the option's default but in config and now merges any additional libraries with the default ones. + This means that `lib.mkForce` must be used to clear the list of default libraries. -- `cudaPackages` package scope has been updated to `cudaPackages_12`. +- `screen`'s module has been cleaned, and will now require you to set `programs.screen.enable` in order to populate `screenrc` and add the program to the environment. -- The deprecated `cudaPackages.cudatoolkit` has been replaced with a - symlink-based wrapper for the splayed redistributable CUDA packages. The - wrapper only includes tools and libraries necessary to build common packages - like e.g. tensorflow. The original runfile-based `cudatoolkit` is still - available as `cudatoolkit-legacy-runfile`. +- `security.acme.defaults.server` now has a default value instead of `null`. + This effectively uses the same server, the Let's Encrypt production server, + but makes the default explicit, instead of relying on the Lego default. -- `halloy` package was updated past 2024.5 which introduced a breaking change by switching the config format from YAML to TOML. See https://github.com/squidowl/halloy/releases/tag/2024.5 for details. + A side effect of this is that the directory in which account data is stored + changes and the ACME module will request a new account and new certificates + for all domains. This may cause issues if you pin an `acccounturl` in a CAA + DNS record. To avoid this, you + may set `security.acme.defaults.server = null` to keep the old hashes. -- If `services.smokeping.webService` was enabled, smokeping is now served via nginx instead of thttpd. This change brings the following consequences: - - The default port for smokeping is now the nginx default port 80 instead of 8081. - - The option `services.smokeping.port` has been removed. To customize the port, use `services.nginx.virtualHosts.smokeping.listen.*.port`. +- `security.pam.sshAgentAuth.enable` now requires `services.openssh.authorizedKeysFiles` to be non-empty, + which is the case when `services.openssh.enable` is true. Previously, `pam_ssh_agent_auth` silently failed to work. -- The `wpaperd` package has a breaking change moving to 1.0.1, previous version 0.3.0 had 2 different configuration files, one for wpaperd and one for the wallpapers. Remove the former and move the latter (`wallpaper.toml`) to `config.toml`. +- `security.pam.enableSSHAgentAuth` was replaced by the `sshAgentAuth` attrset, and **only** + `authorized_keys` files listed in [`sshAgentAuth.authorizedKeysFiles`] are trusted, + defaulting to `/etc/ssh/authorized_keys.d/%u`. + ::: {.warning} + Users of {manpage}`pam_ssh_agent_auth(8)` must take care that the pubkeys they use (for instance with `sudo`) + are listed in [`sshAgentAuth.authorizedKeysFiles`]. + ::: + ::: {.note} + Previously, all `services.openssh.authorizedKeysFiles` were trusted, including `~/.ssh/authorized_keys`, + which results in an **insecure** configuration; see [#31611](https://github.com/NixOS/nixpkgs/issues/31611). + ::: -- Ada packages (libraries and tools) have been moved into the `gnatPackages` scope. `gnatPackages` uses the default GNAT compiler, `gnat12Packages` and `gnat13Packages` use the respective matching compiler version. +[`sshAgentAuth.authorizedKeysFiles`]: #opt-security.pam.sshAgentAuth.authorizedKeysFiles -- Paths provided as `restartTriggers` and `reloadTriggers` for systemd units will now be copied into the nix store to make the behavior consistent. - Previously, `restartTriggers = [ ./config.txt ]`, if defined in a flake, would trigger a restart when any part of the flake changed; and if not defined in a flake, would never trigger a restart even if the contents of `config.txt` changed. +- `services.archisteamfarm` no longer uses the abbreviation `asf` for its state directory (`/var/lib/asf`), user and group (both `asf`). Instead the long name `archisteamfarm` is used. + Configurations with `system.stateVersion` 23.11 or earlier, default to the old stateDirectory until the 24.11 release and must either set the option explicitly or move the data to the new directory. -- `spark2014` has been renamed to `gnatprove`. A version of `gnatprove` matching different GNAT versions is available from the different `gnatPackages` sets. +- `frr` was updated to 10.0, which introduces the default of `enforce-first-as` for BGP. Please disable again if needed. + +- `services.aria2.rpcSecret` has been replaced with `services.aria2.rpcSecretFile`. + This was done so that secrets aren't stored in the world-readable Nix store. + To migrate, you will have to create a file with the same exact string, and change + your module options to point to that file. For example, `services.aria2.rpcSecret = + "mysecret"` becomes `services.aria2.rpcSecretFile = "/path/to/secret_file"` + where the file `secret_file` contains the string `mysecret`. + +- `services.avahi.nssmdns` was split into `services.avahi.nssmdns4` and `services.avahi.nssmdns6` which enable the mDNS NSS switches for IPv4 and IPv6 respectively. + Since most mDNS responders only register IPv4 addresses, most users want to keep the IPv6 support disabled to avoid long timeouts. -- `services.resolved.fallbackDns` can now be used to disable the upstream fallback servers entirely by setting it to an empty list. To get the previous behaviour of the upstream defaults set it to null, the new default, instead. +- `services.frp.settings` now generates the frp configuration file in TOML format as [recommended by upstream](https://github.com/fatedier/frp#configuration-files), instead of the legacy INI format. This has also introduced other changes in the configuration file structure and options: + - The `settings.common` section in the configuration is no longer valid and all the options form inside it now go directly under `settings`. + - Configuration option names have been changed from snake_case to camelCase. For example: `server_addr` becomes `serverAddr`, `server_port` becomes `serverPort` etc. + - Proxies are now defined with a new option, `settings.proxies`, which takes a list of proxies. + - Consult the [upstream documentation](https://github.com/fatedier/frp#example-usage) for more details on the changes. - `services.hledger-web.capabilities` options has been replaced by a new option `services.hledger-web.allow`. @@ -430,119 +484,133 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m - `allow = "edit"` means `capabilities = { view = true; add = true; edit = true }`; - `allow = "sandstorm"` reads permissions from the `X-Sandstorm-Permissions` request header. -- `xxd` has been moved from `vim` default output to its own output to reduce closure size. The canonical way to reference it across all platforms is `unixtools.xxd`. - -- `stalwart-mail` package has been updated to v0.5.3, which includes [breaking changes](https://github.com/stalwartlabs/mail-server/blob/v0.5.3/UPGRADING.md). +- `services.homepage-dashboard` now takes its configuration using native Nix expressions, rather than dumping templated configurations into `/var/lib/homepage-dashboard` where they were previously managed manually. There are now new options which allow the configuration of bookmarks, services, widgets and custom CSS/JS natively in Nix. -- `services.zope2` has been removed as `zope2` is unmaintained and was relying on Python2. +- `services.invidious.settings.db.user`, the default database username has changed from `kemal` to `invidious`. Setups involving an externally-provisioned database (i.e. `services.invidious.database.createLocally == false`) should adjust their configuration accordingly. The old `kemal` user will not be removed automatically even when the database is provisioned automatically.(https://github.com/NixOS/nixpkgs/pull/265857). - `services.oauth2_proxy` was renamed to `services.oauth2-proxy`. Also the corresponding service, user and group were renamed. -- `services.avahi.nssmdns` got split into `services.avahi.nssmdns4` and `services.avahi.nssmdns6` which enable the mDNS NSS switch for IPv4 and IPv6 respectively. - Since most mDNS responders only register IPv4 addresses, most users want to keep the IPv6 support disabled to avoid long timeouts. +- `services.smokeping` now has an option `webService`. When enabled, smokeping is now served via nginx instead of thttpd. This change brings the following consequences: + - The default port for smokeping is now the nginx default port 80 instead of 8081. + - The option `services.smokeping.port` has been removed. To customize the port, use `services.nginx.virtualHosts.smokeping.listen.*.port`. -- A warning has been added for services that are - `after = [ "network-online.target" ]` but do not depend on it (e.g. using - `wants`), because the dependency that `multi-user.target` has on - `network-online.target` is planned for removal. +- `services.neo4j.allowUpgrade` was removed and no longer has any effect. Neo4j 5 supports automatic rolling upgrades. + +- `services.nextcloud` has the following options moved into [`services.nextcloud.settings`](#opt-services.nextcloud.settings) and renamed to match the name from Nextcloud's `config.php`: + - `logLevel` -> [`loglevel`](#opt-services.nextcloud.settings.loglevel), + - `logType` -> [`log_type`](#opt-services.nextcloud.settings.log_type), + - `defaultPhoneRegion` -> [`default_phone_region`](#opt-services.nextcloud.settings.default_phone_region), + - `overwriteProtocol` -> [`overwriteprotocol`](#opt-services.nextcloud.settings.overwriteprotocol), + - `skeletonDirectory` -> [`skeletondirectory`](#opt-services.nextcloud.settings.skeletondirectory), + - `globalProfiles` -> [`profile.enabled`](#opt-services.nextcloud.settings._profile.enabled_), + - `extraTrustedDomains` -> [`trusted_domains`](#opt-services.nextcloud.settings.trusted_domains) and + - `trustedProxies` -> [`trusted_proxies`](#opt-services.nextcloud.settings.trusted_proxies). + +- `services.nginx` will no longer advertise HTTP/3 availability automatically. This must now be manually added, preferably to each location block. + Example: + + ```nix + { + locations."/".extraConfig = '' + add_header Alt-Svc 'h3=":$server_port"; ma=86400'; + ''; + locations."^~ /assets/".extraConfig = '' + add_header Alt-Svc 'h3=":$server_port"; ma=86400'; + ''; + } + ``` - `services.pgbouncer` now has systemd support enabled and will log to journald. The default setting for `services.pgbouncer.logFile` is now `null` to disable logging to a separate log file. -- `services.archisteamfarm` no longer uses the abbreviation `asf` for its state directory (`/var/lib/asf`), user and group (both `asf`). Instead the long name `archisteamfarm` is used. - Configurations with `system.stateVersion` 23.11 or earlier, default to the old stateDirectory until the 24.11 release and must either set the option explicitly or move the data to the new directory. +- `services.postgresql.ensureUsers._.ensurePermissions` has been removed as it is + not declarative and is broken with newer postgresql versions. Consider using + [](#opt-services.postgresql.ensureUsers._.ensureDBOwnership) + instead or a tool that is more suited for managing the data inside a postgresql database. -- `xfsprogs` was updated to version 6.6.0, which enables reverse mapping (rmapbt) and large extent counts (nrext64) by default. - Support for these features was added in kernel 4.9 and 5.19 and nrext64 was deemed stable in kernel 6.5. - Format your filesystems with `mkfs.xfs -i nrext64=0`, if they need to be readable by GRUB2 before 2.12 or kernels older than 5.19. +- `services.redis.vmOverCommit` now defaults to `true` and no longer enforces Transparent Hugepages (THP) to be disabled. Redis only works with THP configured to `madvise` which is the kernel's default. -- `networking.iproute2.enable` now does not set `environment.etc."iproute2/rt_tables".text`. +- `services.resolved.fallbackDns` + - can now be used to disable the upstream fallback servers entirely by setting it to `[]` + - to get previous behaviour of upstream defaults, set it to `null` + - default value has changed from `[]` to `null`, in order to preserve default behaviour - Setting `environment.etc."iproute2/{CONFIG_FILE_NAME}".text` will override the whole configuration file instead of appending it to the upstream configuration file. +- `services.vikunja` systemd service now uses `vikunja` as dynamic user instead of `vikunja-api`. Database users might need to be changed. - `CONFIG_FILE_NAME` includes `bpf_pinning`, `ematch_map`, `group`, `nl_protos`, `rt_dsfield`, `rt_protos`, `rt_realms`, `rt_scopes`, and `rt_tables`. +- `services.vikunja.setupNginx` setting has been removed. Users now need to set up the webserver configuration on their own with a proxy pass to the vikunja service. -- `netbox` was updated to v3.7. `services.netbox.package` still defaults - to v3.6 if `stateVersion` is earlier than 24.05. Refer to upstream's breaking - changes [for - v3.7.0](https://github.com/netbox-community/netbox/releases/tag/v3.7.0) and - upgrade NetBox by changing `services.netbox.package`. Database migrations - will be run automatically. +- `services.vmagent` module deprecates `dataDir`, `group` and `user` settings in favor of the systemd-provided CacheDirectory and DynamicUser. -- `gauge` now supports installing plugins using nix. For the old imperative approach, switch to `gauge-unwrapped`. - You can load plugins from an existing gauge manifest file using `gauge.fromManifest ./path/to/manifest.json` or - specify plugins in nix using `gauge.withPlugins (p: with p; [ js html-report xml-report ])`. +- `services.vmagent.remoteWriteUrl` setting has been renamed to `services.vmagent.remoteWrite.url` and now defaults to `null`. -- `firefox-devedition`, `firefox-beta`, `firefox-esr` executable file names for now match their package names, which is consistent with the `firefox-*-bin` packages. The desktop entries are also updated so that you can have multiple editions of firefox in your app launcher. +- `services.zope2` has been removed, as `zope2` is unmaintained and was relying on Python 2. -- `chromium` and `ungoogled-chromium` had a long stanging issue regarding Widevine DRM handling in nixpkgs fixed. - `chromium` now no longer automatically downloads Widevine when encountering DRM protected content. - To be able to play DRM protected content in `chromium` now, you have to explicitly opt-in as originally intended using `chromium.override { enableWideVine = true; }`. - This override has been added almost 10 years ago. +- `spark2014` has been renamed to `gnatprove`. A version of `gnatprove` matching different GNAT versions is available from the different `gnatPackages` sets. -- switch-to-configuration does not directly call systemd-tmpfiles anymore. - Instead, the new artificial sysinit-reactivation.target is introduced which - allows to restart multiple services that are ordered before sysinit.target - and respect the ordering between the services. +- `stalwart-mail` has been updated to v0.5.3, which includes [breaking changes](https://github.com/stalwartlabs/mail-server/blob/v0.5.3/UPGRADING.md). + +- `system.etc.overlay.enable` option was added. If enabled, `/etc` is + mounted via an overlayfs instead of being created by a custom perl script. -- `systemd.oomd` module behavior is changed as: +- `system.forbiddenDependenciesRegex` has been renamed to `system.forbiddenDependenciesRegexes` and now has the type of `listOf string` instead of `string` to accept multiple regexes. + +- `systemd.oomd` module behavior has changed: - Raise ManagedOOMMemoryPressureLimit from 50% to 80%. This should make systemd-oomd kill things less often, and fix issues like [this](https://pagure.io/fedora-workstation/issue/358). Reference: [commit](https://src.fedoraproject.org/rpms/systemd/c/806c95e1c70af18f81d499b24cd7acfa4c36ffd6?branch=806c95e1c70af18f81d499b24cd7acfa4c36ffd6). - Remove swap policy. This helps prevent killing processes when user's swap is small. - - Expand the memory pressure policy to system.slice, user-.slice, and all user owned slices. Reference: [commit](https://src.fedoraproject.org/rpms/systemd/c/7665e1796f915dedbf8e014f0a78f4f576d609bb). - - - `systemd.oomd.enableUserServices` is renamed to `systemd.oomd.enableUserSlices`. - -- `security.pam.enableSSHAgentAuth` now requires `services.openssh.authorizedKeysFiles` to be non-empty, - which is the case when `services.openssh.enable` is true. Previously, `pam_ssh_agent_auth` silently failed to work. + - Expand the memory pressure policy to `system.slice`, `user-.slice`, and all user-owned slices. Reference: [commit](https://src.fedoraproject.org/rpms/systemd/c/7665e1796f915dedbf8e014f0a78f4f576d609bb). -- The configuration format for `services.prometheus.exporters.snmp` changed with release 0.23.0. - The module now includes an optional config check, that is enabled by default, to make the change obvious before any deployment. - More information about the configuration syntax change is available in the [upstream repository](https://github.com/prometheus/snmp_exporter/blob/b75fc6b839ee3f3ccbee68bee55f1ae99555084a/auth-split-migration.md). + - Rename `systemd.oomd.enableUserServices` to `systemd.oomd.enableUserSlices`. -- [watchdogd](https://troglobit.com/projects/watchdogd/), a system and process supervisor using watchdog timers. Available as [services.watchdogd](#opt-services.watchdogd.enable). +- `systemd.sysusers.enable` option was added. If enabled, users and + groups are created with systemd-sysusers instead of with a custom perl script. -- `jdt-language-server` package now uses upstream's provided python wrapper instead of our own custom wrapper. This results in the following breaking and notable changes: +- `teleport` has been upgraded from major version 14 to major version 15. + Refer to upstream [upgrade instructions](https://goteleport.com/docs/management/operations/upgrading/) + and release notes for [v15](https://goteleport.com/docs/changelog/#1500-013124). - - The main binary for the package is now named `jdtls` instead of `jdt-language-server`, equivalent to what most editors expect the binary to be named. +- `unifiLTS`, `unifi5` and `unifi6` have been removed, as they require MongoDB versions which are end-of-life. All these versions can be upgraded to `unifi7` directly. - - JVM arguments should now be provided with the `--jvm-arg` flag instead of setting `JAVA_OPTS`. +- `unrar` was updated to v7. See [changelog](https://www.rarlab.com/unrar7notes.htm) for more information. - - The `-data` path is no longer required to run the package, and will be set to point to a folder in `$TMP` if missing. +- `virtualisation.docker.enableNvidia` and `virtualisation.podman.enableNvidia` options are deprecated. `hardware.nvidia-container-toolkit.enable` should be used instead. This option will expose GPUs on containers with the `--device` CLI option. This is supported by Docker 25, Podman 3.2.0 and Singularity 4. Any container runtime that supports the CDI specification will take advantage of this feature. -- `nomad` has been updated - note that HashiCorp recommends updating one minor version at a time. Please check [their upgrade guide](https://developer.hashicorp.com/nomad/docs/upgrade) for information on safely updating clusters and potential breaking changes. +- `virtialisation.incus` now defaults to the newly-added `incus-lts` release (v6.0.x). Users who wish to continue using the non-LTS release will need to set `virtualisation.incus.package = pkgs.incus`. Stable release users are encouraged to stay on the LTS release as non-LTS releases will by default not be backported. - - `nomad` is now Nomad 1.7.x. +- `woodpecker-*` packages have been updated to v2 which includes [breaking changes](https://woodpecker-ci.org/docs/next/migrations#200). - - `nomad_1_4` has been removed, as it is now unsupported upstream. +- `wpaperd` has been updated to 1.0.1, which has a breaking change: previous version 0.3.0 had 2 different configuration files, one for wpaperd and one for the wallpapers. Remove the former and move the latter (`wallpaper.toml`) to `config.toml`. -- Dwarf Fortress has been updated to version 50, and its derivations continue to menace with spikes of Nix and bash. Version 50 is identical to the version on Steam, but without the paid elements like tilepacks. - dfhack and Dwarf Therapist still work, and older versions are still packaged in case you'd like to roll back. Note that DF 50 saves will not be compatible with DF 0.47 and earlier. - See [Bay 12 Games](http://www.bay12games.com/dwarves/) for more details on what's new in Dwarf Fortress. +- `writeReferencesToFile` is deprecated in favour of the new trivial build helper `writeClosure`. The latter accepts a list of paths and has an unambiguous name and cleaner implementation. - - Running an earlier version can be achieved through an override: `dwarf-fortress-packages.dwarf-fortress-full.override { dfVersion = "0.47.5"; }` +- `xfsprogs` was updated to version 6.6.0, which enables reverse mapping (rmapbt) and large extent counts (nrext64) by default. + Support for these features was added in kernel 4.9 and 5.19 and nrext64 was deemed stable in kernel 6.5. + Format your filesystems with `mkfs.xfs -i nrext64=0`, if they need to be readable by GRUB2 before 2.12 or kernels older than 5.19. - - Ruby plugin support has been disabled in DFHack. Many of the Ruby plugins have been converted to Lua, and support was removed upstream due to frequent crashes. +- `xxd` has been moved from `vim` default output to its own output to reduce closure size. The canonical way to reference it across all platforms is `unixtools.xxd`. -- `livebook` package is now built as a `mix release` instead of an `escript`. - This means that configuration now has to be done using [environment variables](https://hexdocs.pm/livebook/readme.html#environment-variables) instead of command line arguments. - This has the further implication that the `livebook` service configuration has changed: +- `youtrack` was bumped to 2023.3. The update is not performed automatically, it requires manual interaction. See the YouTrack section in the manual for details. -- `erlang_node_short_name`, `erlang_node_name`, `port` and `options` configuration parameters are gone, and have been replaced with an `environment` parameter. - Use the appropriate [environment variables](https://hexdocs.pm/livebook/readme.html#environment-variables) inside `environment` to configure the service instead. +- Ada packages (libraries and tools) have been moved into the `gnatPackages` scope. `gnatPackages` uses the default GNAT compiler, `gnat12Packages` and `gnat13Packages` use the respective matching compiler version. -- `akkoma` now requires explicitly setting the base URL for uploaded media (`settings."Pleroma.Upload".base_url`), as well as for the media proxy if enabled (`settings."Media"`). - This is recommended to be a separate (sub)domain to the one Akkoma is hosted at. - See [here](https://meta.akkoma.dev/t/akkoma-stable-2024-03-securer-i-barely-know-her/681#explicit-upload-and-media-proxy-domains-5) for more details. +- Paths provided as `restartTriggers` and `reloadTriggers` for systemd units will now be copied into the Nix store to make the behavior consistent. + Previously, `restartTriggers = [ ./config.txt ]`, if defined in a flake, would trigger a restart when any part of the flake changed; and if not defined in a flake, would never trigger a restart even if the contents of `config.txt` changed. -- `crystal` package has been updated to 1.11.x, which has some breaking changes. - Refer to crystal's changelog for more information. ([v1.10](https://github.com/crystal-lang/crystal/blob/master/CHANGELOG.md#1100-2023-10-09), [v1.11](https://github.com/crystal-lang/crystal/blob/master/CHANGELOG.md#1110-2024-01-08)) +- A warning has been added for services that are + `after = [ "network-online.target" ]` but do not depend on it (e.g. using + `wants`), because the dependency that `multi-user.target` has on + `network-online.target` is planned for removal. -- `erlang-ls` package no longer ships the `els_dap` binary as of v0.51.0. +- switch-to-configuration does not directly call systemd-tmpfiles anymore. + Instead, the new artificial sysinit-reactivation.target is introduced which + allows to restart multiple services that are ordered before sysinit.target + and respect the ordering between the services. -- `icu` no longer includes `install-sh` and `mkinstalldirs` in the shared folder. +- `services.prometheus.exporters.snmp`'s configuration format changed with release 0.23.0. + The module now includes an optional config check, that is enabled by default, to make the change obvious before any deployment. + More information about the configuration syntax change is available in the [upstream repository](https://github.com/prometheus/snmp_exporter/blob/b75fc6b839ee3f3ccbee68bee55f1ae99555084a/auth-split-migration.md). ## Other Notable Changes {#sec-release-24.05-notable-changes} @@ -550,146 +618,104 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m - `addDriverRunpath` has been added to facilitate the deprecation of the old `addOpenGLRunpath` setuphook. This change is motivated by the evolution of the setuphook to include all hardware acceleration. -- `cinnamon` has been updated to 6.0. Please beware that the [Wayland session](https://blog.linuxmint.com/?p=4591) is still experimental in this release and could potentially [affect Xorg sessions](https://blog.linuxmint.com/?p=4639). We suggest a reboot when switching between sessions. - -- `mate` has been updated to 1.28. - - To properly support panel plugins built with Wayland (in-process) support, we are introducing `services.xserver.desktopManager.mate.extraPanelApplets` option, please use that for installing panel applets. - - Similarly, please use `services.xserver.desktopManager.mate.extraCajaExtensions` option for installing Caja extensions. - - To use the Wayland session, enable `services.xserver.desktopManager.mate.enableWaylandSession`. This is opt-in for now as it is in early stage and introduces a new set of Wayfire closure. Due to [known issues with LightDM](https://github.com/canonical/lightdm/issues/63), we suggest using SDDM for display manager. - -- `services.xserver.desktopManager.budgie` installs `gnome.gnome-terminal` by default (instead of `mate.mate-terminal`). - -- New `boot.loader.systemd-boot.xbootldrMountPoint` allows setting up a separate [XBOOTLDR partition](https://uapi-group.org/specifications/specs/boot_loader_specification/) to store boot files. Useful on systems with a small EFI System partition that cannot be easily repartitioned. - -- `boot.loader.systemd-boot` will now verify that `efiSysMountPoint` (and `xbootldrMountPoint` if configured) are mounted partitions. +- `appimage`, `appimageTools.wrapAppImage` and `buildFHSEnvBubblewrap` now properly accept `pname` and `version`. -- `services.postgresql.extraPlugins` changed its type from just a list of packages to also a function that returns such a list. - For example a config line like ``services.postgresql.extraPlugins = with pkgs.postgresql_11.pkgs; [ postgis ];`` is recommended to be changed to ``services.postgresql.extraPlugins = ps: with ps; [ postgis ];``; - -- `services.openssh` now has an option `authorizedKeysInHomedir`, controlling whether `~/.ssh/authorizedKeys` is - added to `authorizedKeysFiles`. - ::: {.note} - This option currently defaults to `true` for NixOS 24.05, preserving the previous behaviour. - This is expected to change in NixOS 24.11. - ::: - ::: {.warning} - Users should check that their SSH keys are in `users.users.*.openssh`, or that they have another way to access - and administer the system, before setting this option to `false`. - ::: - -- [`matrix-synapse`](https://element-hq.github.io/synapse/) homeserver module now supports configuring UNIX domain socket [`listeners`](#opt-services.matrix-synapse.settings.listeners) through the `path` option. - The default replication worker on the main instance has been migrated away from TCP sockets to UNIX domain sockets. +- `bacula` now allows to configure `TLS` for encrypted communication. - `boot.initrd.network.ssh.authorizedKeyFiles` is a new option in the initrd ssh daemon module, for adding authorized keys via list of files. -- `appimage`, `appimageTools.wrapAppImage` and `buildFHSEnvBubblewrap` now properly accepts `pname` and `version`. +- `boot.kernel.sysctl."net.core.wmem_max"` changed from a string to an integer because of the addition of a custom merge option (taking the highest value defined to avoid conflicts between 2 services trying to set that value), just as `boot.kernel.sysctl."net.core.rmem_max"` since 22.11. -- Programs written in [Nim](https://nim-lang.org/) are built with libraries selected by lockfiles. - The `nimPackages` and `nim2Packages` sets have been removed. - See https://nixos.org/manual/nixpkgs/unstable#nim for more information. +- `boot.loader.systemd-boot.xbootldrMountPoint` is a new option for setting up a separate [XBOOTLDR partition](https://uapi-group.org/specifications/specs/boot_loader_specification/) to store boot files. Useful on systems with a small EFI System partition that cannot be easily repartitioned. + +- `boot.loader.systemd-boot` will now verify that `efiSysMountPoint` (and `xbootldrMountPoint` if configured) are mounted partitions. - `buildDubPackage` can now be used to build Programs written in [D](https://dlang.org/) using the `dub` build system and package manager. See the [D section](https://nixos.org/manual/nixpkgs/unstable#dlang) in the manual for more information. -- [`portunus`](https://github.com/majewsky/portunus) has been updated to major version 2. - This version of Portunus supports strong password hashes, but the legacy hash SHA-256 is also still supported to ensure a smooth migration of existing user accounts. - After upgrading, follow the instructions on the [upstream release notes](https://github.com/majewsky/portunus/releases/tag/v2.0.0) to upgrade all user accounts to strong password hashes. - Support for weak password hashes will be removed in NixOS 24.11. - -- A stdenv's default set of hardening flags can now be set via its `bintools-wrapper`'s `defaultHardeningFlags` argument. A convenient stdenv adapter, `withDefaultHardeningFlags`, can be used to override an existing stdenv's `defaultHardeningFlags`. +- `castopod` has some migration actions to be taken in case of a S3 setup. Some new features may also need some manual migration actions. See [https://code.castopod.org/adaures/castopod/-/releases](https://code.castopod.org/adaures/castopod/-/releases) for more information. -- `libass` now uses the native CoreText backend on Darwin, which may fix subtitle rendering issues with `mpv`, `ffmpeg`, etc. +- `documentation.man.mandoc` now, by default, uses `MANPATH` to set the directories where mandoc will search for manual pages. + This enables mandoc to find manual pages in Nix profiles. To set the manual search paths via the `mandoc.conf` configuration file like before, use `documentation.man.mandoc.settings.manpath` instead. -- [`lilypond`](https://lilypond.org/index.html) and [`denemo`](https://www.denemo.org) are now compiled with Guile 3.0. +- `drbd` out-of-tree Linux kernel driver has been added in version 9.2.7. With it the DRBD 9.x features can be used instead of the 8.x features provided by the 8.4.11 in-tree driver. - `garage` has been updated to v1.x.x. Users should read the [upstream release notes](https://git.deuxfleurs.fr/Deuxfleurs/garage/releases/tag/v1.0.0) and follow the documentation when changing over their `services.garage.package` and performing this manual upgrade. -- The EC2 image module now enables the [Amazon SSM Agent](https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent.html) by default. +- `hardware.pulseaudio` module now sets permissions of pulse user home directory to 755 when running in systemWide mode. It fixes [issue 114399](https://github.com/NixOS/nixpkgs/issues/114399). -- The following options of the Nextcloud module were moved into [`services.nextcloud.settings`](#opt-services.nextcloud.settings) and renamed to match the name from Nextcloud's `config.php`: - - `logLevel` -> [`loglevel`](#opt-services.nextcloud.settings.loglevel), - - `logType` -> [`log_type`](#opt-services.nextcloud.settings.log_type), - - `defaultPhoneRegion` -> [`default_phone_region`](#opt-services.nextcloud.settings.default_phone_region), - - `overwriteProtocol` -> [`overwriteprotocol`](#opt-services.nextcloud.settings.overwriteprotocol), - - `skeletonDirectory` -> [`skeletondirectory`](#opt-services.nextcloud.settings.skeletondirectory), - - `globalProfiles` -> [`profile.enabled`](#opt-services.nextcloud.settings._profile.enabled_), - - `extraTrustedDomains` -> [`trusted_domains`](#opt-services.nextcloud.settings.trusted_domains) and - - `trustedProxies` -> [`trusted_proxies`](#opt-services.nextcloud.settings.trusted_proxies). - -- `services.nextcloud.config.dbport` option of the Nextcloud module was removed to match upstream. - The port can be specified in [`services.nextcloud.config.dbhost`](#opt-services.nextcloud.config.dbhost). +- `kavita` has been updated to 0.8.0, requiring a manual forced library scan on all libraries for migration. Refer to upstream's [release notes](https://github.com/Kareadita/Kavita/releases/tag/v0.8.0) for details. -- A new abstraction to create both read-only as well as writable overlay file - systems was added. Available via - [fileSystems.overlay](#opt-fileSystems._name_.overlay.lowerdir). See also the - [NixOS docs](#sec-overlayfs). +- `krb5` module has been rewritten and moved to `security.krb5`, moving all options but `security.krb5.enable` and `security.krb5.package` into `security.krb5.settings`. -- `systemd` units can now specify the `Upholds=` and `UpheldBy=` unit dependencies via the aptly - named `upholds` and `upheldBy` options. These options get systemd to enforce that the - dependencies remain continuosly running for as long as the dependent unit is in a running state. +- `libass` now uses the native CoreText backend on Darwin, which may fix subtitle rendering issues with `mpv`, `ffmpeg`, etc. -- `stdenv`: The `--replace` flag in `substitute`, `substituteInPlace`, `substituteAll`, `substituteAllStream`, and `substituteStream` is now deprecated if favor of the new `--replace-fail`, `--replace-warn` and `--replace-quiet`. The deprecated `--replace` equates to `--replace-warn`. +- `libjxl` version was bumped from 0.8.2 to 0.9.1 [dropped support for the butteraugli API](https://github.com/libjxl/libjxl/pull/2576). You will no longer be able to set `enableButteraugli` on `libaom`. -- A new hardening flag, `zerocallusedregs` was made available, corresponding to the gcc/clang option `-fzero-call-used-regs=used-gpr`. +- [`lilypond`](https://lilypond.org/index.html) and [`denemo`](https://www.denemo.org) are now compiled with Guile 3.0. -- A new hardening flag, `trivialautovarinit` was made available, corresponding to the gcc/clang option `-ftrivial-auto-var-init=pattern`. +- `lxd` has been upgraded to v5.21.x, an LTS release. The LTS release is now the only supported LXD release. Users are encouraged to [migrate to Incus](https://linuxcontainers.org/incus/docs/main/howto/server_migrate_lxd/) for better support on NixOS. -- New options were added to the dnsdist module to enable and configure a DNSCrypt endpoint (see `services.dnsdist.dnscrypt.enable`, etc.). - The module can generate the DNSCrypt provider key pair, certificates and also performs their rotation automatically with no downtime. +- [`matrix-synapse`](https://element-hq.github.io/synapse/) homeserver module now supports configuring UNIX domain socket [`listeners`](#opt-services.matrix-synapse.settings.listeners) through the `path` option. + The default replication worker on the main instance has been migrated away from TCP sockets to UNIX domain sockets. -- `sonarr` version bumped to from 3.0.10 to 4.0.3. Consequently existing config database files will be upgraded automatically, but note that some old apparently-working configs [might actually be corrupt and fail to upgrade cleanly](https://forums.sonarr.tv/t/sonarr-v4-released/33089). +- `mockgen` has changed to the [go.uber.org/mock](https://github.com/uber-go/mock) fork because [the original repository is no longer maintained](https://github.com/golang/mock#gomock). -- The kernel Yama LSM is now enabled by default, which prevents ptracing - non-child processes. This means you will not be able to attach gdb to an - existing process, but will need to start that process from gdb (so it is a - child). Or you can set `boot.kernel.sysctl."kernel.yama.ptrace_scope"` to 0. +- `mpich` now requires `withPm` to be a list, e.g. `"hydra:gforker"` becomes `[ "hydra" "gforker" ]`. -- `netbird` module now allows running multiple tunnels in parallel through [`services.netbird.tunnels`](#opt-services.netbird.tunnels). +- `nextcloud-setup.service` no longer changes the group of each file and directory inside `/var/lib/nextcloud/{config,data,store-apps}` if one of these directories has the wrong owner group. This was part of transitioning the group used for `/var/lib/nextcloud`, but isn't necessary anymore. -- [Nginx virtual hosts](#opt-services.nginx.virtualHosts) using `forceSSL` or - `globalRedirect` can now have redirect codes other than 301 through `redirectCode`. +- `oils-for-unix`, the oil shell's C++ version is now available. The Python version is still available as `oil`. -- `bacula` now allows to configure `TLS` for encrypted communication. +- `pkgsExtraHardening`, a new top-level package set, was added. This is a set of packages built with stricter hardening flags - those that have not yet received enough testing to be applied universally, those that are more likely to cause build failures or those that have drawbacks to their use (e.g. performance or required hardware features). -- `libjxl` version bumped from 0.8.2 to 0.9.1 [dropped support for the butteraugli API](https://github.com/libjxl/libjxl/pull/2576). You will no longer be able to set `enableButteraugli` on `libaom`. +- [`portunus`](https://github.com/majewsky/portunus) has been updated to major version 2. + This version of Portunus supports strong password hashes, but the legacy hash SHA-256 is also still supported to ensure a smooth migration of existing user accounts. + After upgrading, follow the instructions on the [upstream release notes](https://github.com/majewsky/portunus/releases/tag/v2.0.0) to upgrade all user accounts to strong password hashes. + Support for weak password hashes will be removed in NixOS 24.11. -- `mockgen` package source has changed to the [go.uber.org/mock](https://github.com/uber-go/mock) fork because [the original repository is no longer maintained](https://github.com/golang/mock#gomock). +- `programs.fish.package` now allows you to override the package used in the `fish` module. -- [](#opt-boot.kernel.sysctl._net.core.wmem_max_) changed from a string to an integer because of the addition of a custom merge option (taking the highest value defined to avoid conflicts between 2 services trying to set that value), just as [](#opt-boot.kernel.sysctl._net.core.rmem_max_) since 22.11. +- `qt6.qtmultimedia` has changed its default backend to `QT_MEDIA_BACKEND=ffmpeg` (previously `gstreamer` on Linux or `darwin` on macOS). + The previous native backends remain available but are now minimally maintained. Refer to [upstream documentation](https://doc.qt.io/qt-6/qtmultimedia-index.html#ffmpeg-as-the-default-backend) for further details about each platform. -- `pkgsExtraHardening`, a new top-level package set, was added. This is a set of packages built with stricter hardening flags - those that have not yet received enough testing to be applied universally, those that are more likely to cause build failures or those that have drawbacks to their use (e.g. performance or required hardware features). +- `services.btrbk` now automatically selects and provides required compression + program depending on the configured `stream_compress` option. Since this + replaces the need for the `extraPackages` option, this option will be + deprecated in future releases. -- `services.zfs.zed.enableMail` now uses the global `sendmail` wrapper defined by an email module - (such as msmtp or Postfix). It no longer requires using a special ZFS build with email support. +- `services.github-runner` module has been removed. To configure a single GitHub Actions Runner refer to `services.github-runners.*`. Note that this will trigger a new runner registration. -- `castopod` has some migration actions to be taken in case of a S3 setup. Some new features may also need some manual migration actions. See [https://code.castopod.org/adaures/castopod/-/releases](https://code.castopod.org/adaures/castopod/-/releases) for more informations. +- `services.networkmanager.extraConfig` was renamed to `services.networkmanager.settings` and changed to use the ini type instead of using a multiline string. -- `nextcloud-setup.service` no longer changes the group of each file & directory inside `/var/lib/nextcloud/{config,data,store-apps}` if one of these directories has the wrong owner group. This was part of transitioning the group used for `/var/lib/nextcloud`, but isn't necessary anymore. +- `services.nextcloud.config.dbport` option of the Nextcloud module was removed to match upstream. + The port can be specified in [`services.nextcloud.config.dbhost`](#opt-services.nextcloud.config.dbhost). - `services.kavita` now uses the free-form option `services.kavita.settings` for the application settings file. The options `services.kavita.ipAdresses` and `services.kavita.port` now exist at `services.kavita.settings.IpAddresses` and `services.kavita.settings.IpAddresses`. The file at `services.kavita.tokenKeyFile` now needs to contain a secret with 512+ bits instead of 128+ bits. -- `kavita` has been updated to 0.8.0, requiring a manual forced library scan on all libraries for migration. Refer to upstream's [release notes](https://github.com/Kareadita/Kavita/releases/tag/v0.8.0) for details. - -- `krb5` module has been rewritten and moved to `security.krb5`, moving all options but `security.krb5.enable` and `security.krb5.package` into `security.krb5.settings`. +- `services.netbird` now allows running multiple tunnels in parallel through [`services.netbird.tunnels`](#opt-services.netbird.tunnels). -- `services.soju` now has a wrapper for the `sojuctl` command, pointed at the service config file. It also has the new option `adminSocket.enable`, which creates a unix admin socket at `/run/soju/admin`. +- `services.nginx.virtualHosts` using `forceSSL` or + `globalRedirect` can now have redirect codes other than 301 through `redirectCode`. -- `gitea` upgrade to 1.21 has several breaking changes, including: - - Custom themes and other assets that were previously stored in `custom/public/*` now belong in `custom/public/assets/*` - - New instances of Gitea using MySQL now ignore the `[database].CHARSET` config option and always use the `utf8mb4` charset, existing instances should migrate via the `gitea doctor convert` CLI command. +- `services.openssh` now has an option `authorizedKeysInHomedir`, controlling whether `~/.ssh/authorizedKeys` is + added to `authorizedKeysFiles`. + ::: {.note} + This option currently defaults to `true` for NixOS 24.05, preserving the previous behaviour. + This is expected to change in NixOS 24.11. + ::: + ::: {.warning} + Users should check that their SSH keys are in `users.users.*.openssh`, or that they have another way to access + and administer the system, before setting this option to `false`. + ::: - `services.paperless` module no longer uses the previously downloaded NLTK data stored in `/var/cache/paperless/nltk`. This directory can be removed. -- `services.teeworlds` module now has a wealth of configuration options, including a new `package` option. - -- `hardware.pulseaudio` module now sets permission of pulse user home directory to 755 when running in "systemWide" mode. It fixes [issue 114399](https://github.com/NixOS/nixpkgs/issues/114399). - -- `services.networkmanager.extraConfig` was renamed to `services.networkmanager.settings` and was changed to use the ini type instead of using a multiline string. - -- `services.github-runner` module has been removed. To configure a single GitHub Actions Runner refer to `services.github-runners.*`. Note that this will trigger a new runner registration. +- `services.postgresql.extraPlugins`' type has expanded. Previously it was a list of packages, now it can also be a function that returns such a list. + For example a config line like ``services.postgresql.extraPlugins = with pkgs.postgresql_11.pkgs; [ postgis ];`` is recommended to be changed to ``services.postgresql.extraPlugins = ps: with ps; [ postgis ];``; - `services.slskd` has been refactored to include more configuation options in the free-form `services.slskd.settings` option, and some defaults (including listen ports) @@ -697,34 +723,102 @@ The pre-existing [services.ankisyncd](#opt-services.ankisyncd.enable) has been m disabled by default, and the log rotation timer has been removed. The nginx virtualhost option is now of the `vhost-options` type. -- `services.btrbk` now automatically selects and provides required compression - program depending on the configured `stream_compress` option. Since this - replaces the need for the `extraPackages` option, this option will be - deprecated in future releases. +- `services.soju` now has a wrapper for the `sojuctl` command, pointed at the service config file. It also has the new option `adminSocket.enable`, which creates a unix admin socket at `/run/soju/admin`. + +- `services.stalwart-mail` uses the legacy version 0.6.X as default because newer `stalwart-mail` versions require a [manual upgrade process](https://github.com/stalwartlabs/mail-server/blob/main/UPGRADING.md). Change [`services.stalwart-mail.package`](#opt-services.stalwart-mail.package) to `pkgs.stalwart-mail` if you wish to switch to the new version. -- `mpich` package expression now requires `withPm` to be a list, e.g. `"hydra:gforker"` becomes `[ "hydra" "gforker" ]`. +- `services.teeworlds` module now has a wealth of configuration options, including a new `package` option. + +- `services.xserver.desktopManager.budgie` installs `gnome.gnome-terminal` by default (instead of `mate.mate-terminal`). + +- `services.zfs.zed.enableMail` now uses the global `sendmail` wrapper defined by an email module + (such as msmtp or Postfix). It no longer requires using a special ZFS build with email support. + +- `sonarr` version was bumped to from 3.0.10 to 4.0.3. Consequently existing config database files will be upgraded automatically, but note that some old apparently-working configs [might actually be corrupt and fail to upgrade cleanly](https://forums.sonarr.tv/t/sonarr-v4-released/33089). + +- `stdenv`: The `--replace` flag in `substitute`, `substituteInPlace`, `substituteAll`, `substituteAllStream`, and `substituteStream` is now deprecated if favor of the new `--replace-fail`, `--replace-warn` and `--replace-quiet`. The deprecated `--replace` equates to `--replace-warn`. - `systemd`: when merging unit options (of type `unitOption`), if at least one definition is a list, all those which aren't are now lifted into a list, making it possible to accumulate definitions without resorting to `mkForce`, hence to retain the definitions not anticipating that need. -- Lisp modules: previously deprecated interface based on `common-lisp.sh` has now been removed. +- `systemd` units can now specify the `Upholds=` and `UpheldBy=` unit dependencies via the aptly + named `upholds` and `upheldBy` options. These options get systemd to enforce that the + dependencies remain continuosly running for as long as the dependent unit is in a running state. -- `youtrack` is bumped to 2023.3. The update is not performed automatically, it requires manual interaction. See the YouTrack section in the manual for details. +- A stdenv's default set of hardening flags can now be set via its `bintools-wrapper`'s `defaultHardeningFlags` argument. A convenient stdenv adapter, `withDefaultHardeningFlags`, can be used to override an existing stdenv's `defaultHardeningFlags`. -- `qt6.qtmultimedia` has changed its default backend to `QT_MEDIA_BACKEND=ffmpeg` (previously `gstreamer` on Linux or `darwin` on MacOS). - The previous native backends remain available but are now minimally maintained. Refer to [upstream documentation](https://doc.qt.io/qt-6/qtmultimedia-index.html#ffmpeg-as-the-default-backend) for further details about each platform. +- Programs written in [Nim](https://nim-lang.org/) are built with libraries selected by lockfiles. + The `nimPackages` and `nim2Packages` sets have been removed. + See https://nixos.org/manual/nixpkgs/unstable#nim for more information. -- `drbd` out-of-tree Linux kernel driver has been added in version 9.2.7. With it the DRBD 9.x features can be used instead of the 8.x features provided by the 8.4.11 in-tree driver. +- The EC2 image module now enables the [Amazon SSM Agent](https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent.html) by default. + +- A new abstraction to create both read-only as well as writable overlay file + systems was added. Available via + [fileSystems.overlay](#opt-fileSystems._name_.overlay.lowerdir). See also the + [NixOS docs](#sec-overlayfs). -- `oils-for-unix`, the oil shell's c++ version is now available. The python version is still available as `oil`. +- A new hardening flag, `zerocallusedregs` was made available, corresponding to the gcc/clang option `-fzero-call-used-regs=used-gpr`. -- `documentation.man.mandoc` now by default uses `MANPATH` to set the directories where mandoc will search for manual pages. - This enables mandoc to find manual pages in Nix profiles. To set the manual search paths via the `mandoc.conf` configuration file like before, use `documentation.man.mandoc.settings.manpath` instead. +- A new hardening flag, `trivialautovarinit` was made available, corresponding to the gcc/clang option `-ftrivial-auto-var-init=pattern`. + +- `dnsdist` has new options to enable and configure a DNSCrypt endpoint (see `services.dnsdist.dnscrypt.enable`, etc.). + The module can generate the DNSCrypt provider key pair and certificates, and also rotates them automatically with no downtime. + +- The kernel Yama LSM is now enabled by default, which prevents ptracing + non-child processes. This means you will not be able to attach gdb to an + existing process, but will need to start that process from gdb (so it is a + child). Or you can set `boot.kernel.sysctl."kernel.yama.ptrace_scope"` to 0. + +- Lisp modules: previously deprecated interface based on `common-lisp.sh` has now been removed. - The `systemd-confinement` module extension is now compatible with `DynamicUser=true` and thus `ProtectSystem=strict` too. -- `grafana-loki` package was updated to 3.0.0 which includes [breaking changes](https://github.com/grafana/loki/releases/tag/v3.0.0). -- `programs.fish.package` now allows you to override the package used in the `fish` module. +## Nixpkgs Library {#sec-release-24.05-nixpkgs-lib} + +### Additions and Improvements {#sec-release-24.05-lib-additions-improvements} + +New functions: +- [`lib.asserts.assertEachOneOf`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.asserts.assertEachOneOf): Check that each value is one of the allowed ones. +- [`lib.attrsets.longestValidPathPrefix`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.attrsets.longestValidPathPrefix): The longest prefix of an attribute path that refers to an existing attribute in a nesting of attribute sets. +- [`lib.attrsets.mapCartesianProduct`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.attrsets.mapCartesianProduct): Apply a function to the cartesian product of attribute set value combinations. +- [`lib.trivial.xor`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.trivial.xor): Boolean "exclusive or" +- [`lib.lists.ifilter0`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.lists.ifilter0): Filter a list for elements that satisfy a predicate function. The predicate function is called with both the index and value for each element. +- [`lib.lists.sortOn`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.lists.sortOn): Sort a list based on the default comparison of a derived property. +- [`lib.path.hasStorePathPrefix`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.path.hasStorePathPrefix): Whether a [path](https://nixos.org/manual/nix/stable/language/values.html#type-path) has a [store path](https://nixos.org/manual/nix/stable/store/store-path.html#store-path) as a prefix. +- [`lib.filesystem.packagesFromDirectoryRecursive`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.filesystem.packagesFromDirectoryRecursive): Transform a directory tree containing package files suitable for `callPackage` into a matching nested attribute set of derivations. +- [`lib.fileset.toList`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.fileset.toList): The list of file paths contained in a given file set. +- [`lib.fileset.maybeMissing`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.fileset.maybeMissing): Create a file set from a path that may or may not exist. +- [`lib.derivations.optionalDrvAttr`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.derivations.optionalDrvAttr): Conditionally set a derivation attribute. +- [`lib.strings.makeIncludePath`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.strings.makeIncludePath): Construct an include search path (such as `C_INCLUDE_PATH`) containing the header files for a set of packages or paths. + +Improvements: +- [`lib.fixedPoints.extends`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.fixedPoints.extends): Better documentation +- [`lib.customisation.makeScope`](https://nixos.org/manual/nixpkgs/unstable/#function-library-lib.customisation.makeScope): Better documentation +- [`lib.derivations.lazyDerivation`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.derivations.lazyDerivation): Now supports multiple outputs with an `outputs` argument +- [`lib.gvariant`](https://nixos.org/manual/nixpkgs/unstable#sec-functions-library-gvariant): Better error message for integers and attribute set values +- [`lib.filesets.gitTracked`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.fileset.gitTracked): Now works within store paths + +Misc: +- The [`lib/` directory](https://github.com/NixOS/nixpkgs/tree/release-24.05/lib) is a self-contained flake now, including a working [`lib.trivial.version`](https://nixos.org/manual/nixpkgs/unstable/#function-library-lib.trivial.version) (but note that fetching a subtree by itself is not supported in Nix yet) +- [Various minor performance improvements](https://github.com/NixOS/nixpkgs/issues?q=author%3Aadisbladis+label%3A%226.topic%3A+lib%22+created%3A%3C2024-05-31+) + +Module System: +- New types: + - [`types.attrTag`](https://nixos.org/manual/nixos/unstable/#sec-option-types-sums): A tagged union type + - `types.nonEmptyListOf`: A non-empty list +- Improved types: + - `types.uniq`/`unique` now check the wrapped type + +### Deprecations {#sec-release-24.05-lib-deprecations} + +- [`lib.options.mdDoc`](https://nixos.org/manual/nixpkgs/unstable#function-library-lib.options.mdDoc) is obsolete and now emits a warning. The core ecosystem has completely migrated to markdown, so marking markdown as markdown is redundant. +- `lib.attrsets.zipWithNames` is now a deprecated alias of [`lib.attrsets.zipAttrsWithNames`](https://nixos.org/manual/nixpkgs/unstable/#function-library-lib.attrsets.zipAttrsWithNames) +- `lib.attrsets.cartesianProductOfSets` has been renamed to [`lib.attrsets.cartesianProduct`](https://nixos.org/manual/nixpkgs/unstable/#function-library-lib.attrsets.cartesianProduct) + +### Internal {#sec-release-24.05-lib-internal} +- `lib` now has [Readme for contributing](https://github.com/NixOS/nixpkgs/tree/master/lib#readme). +- Some function's documentation is now written using the [accepted doc comment syntax](https://github.com/NixOS/rfcs/pull/145). diff --git a/nixos/doc/manual/release-notes/rl-2411.section.md b/nixos/doc/manual/release-notes/rl-2411.section.md new file mode 100644 index 0000000000000..889d399749323 --- /dev/null +++ b/nixos/doc/manual/release-notes/rl-2411.section.md @@ -0,0 +1,90 @@ +# Release 24.11 (“Vicuña”, 2024.11/??) {#sec-release-24.11} + + + +## Highlights {#sec-release-24.11-highlights} + +- [AMDVLK](https://github.com/GPUOpen-Drivers/AMDVLK), AMD's open source Vulkan driver, is now available to be configured as `hardware.amdgpu.amdvlk` option. + This also allows configuring runtime settings of AMDVLK and enabling experimental features. + +## New Services {#sec-release-24.11-new-services} + +- [Open-WebUI](https://github.com/open-webui/open-webui), a user-friendly WebUI + for LLMs. Available as [services.open-webui](#opt-services.open-webui.enable) + service. + +- [Quickwit](https://quickwit.io), sub-second search & analytics engine on cloud storage. Available as [services.quickwit](options.html#opt-services.quickwit). + +- [Renovate](https://github.com/renovatebot/renovate), a dependency updating tool for various git forges and language ecosystems. Available as [services.renovate](#opt-services.renovate.enable). + +## Backward Incompatibilities {#sec-release-24.11-incompatibilities} + +- `androidenv.androidPkgs_9_0` has been removed, and replaced with `androidenv.androidPkgs` for a more complete Android SDK including support for Android 9 and later. + +- `nginx` package no longer includes `gd` and `geoip` dependencies. For enabling it, override `nginx` package with the optionals `withImageFilter` and `withGeoIP`. + +- `openssh` and `openssh_hpn` are now compiled without Kerberos 5 / GSSAPI support in an effort to reduce the attack surface of the components for the majority of users. Users needing this support can + use the new `opensshWithKerberos` and `openssh_hpnWithKerberos` flavors (e.g. `programs.ssh.package = pkgs.openssh_gssapi`). + +- `nvimpager` was updated to version 0.13.0, which changes the order of user and + nvimpager settings: user commands in `-c` and `--cmd` now override the + respective default settings because they are executed later. + +- `services.forgejo.mailerPasswordFile` has been deprecated by the drop-in replacement `services.forgejo.secrets.mailer.PASSWD`, + which is part of the new free-form `services.forgejo.secrets` option. + `services.forgejo.secrets` is a small wrapper over systemd's `LoadCredential=`. It has the same structure (sections/keys) as + `services.forgejo.settings` but takes file paths that will be read before service startup instead of some plaintext value. + +- `services.ddclient.use` has been deprecated: `ddclient` now supports separate IPv4 and IPv6 configuration. Use `services.ddclient.usev4` and `services.ddclient.usev6` instead. + +- `vaultwarden` lost the capability to bind to privileged ports. If you rely on + this behavior, override the systemd unit to allow `CAP_NET_BIND_SERVICE` in + your local configuration. + +- The Invoiceplane module now only accepts the structured `settings` option. + `extraConfig` is now removed. + +- Legacy package `stalwart-mail_0_6` was dropped, please note the + [manual upgrade process](https://github.com/stalwartlabs/mail-server/blob/main/UPGRADING.md) + before changing the package to `pkgs.stalwart-mail` in + [`services.stalwart-mail.package`](#opt-services.stalwart-mail.package). + +- `haskell.lib.compose.justStaticExecutables` now disallows references to GHC in the + output by default, to alert users to closure size issues caused by + [#164630](https://github.com/NixOS/nixpkgs/issues/164630). See ["Packaging + Helpers" in the Haskell section of the Nixpkgs + manual](https://nixos.org/manual/nixpkgs/unstable/#haskell-packaging-helpers) + for information on working around `output '...' is not allowed to refer to + the following paths` errors caused by this change. + +- The `stalwart-mail` module now uses RocksDB as the default storage backend + for `stateVersion` ≥ 24.11. (It was previously using SQLite for structured + data and the filesystem for blobs). + +- `zx` was updated to v8, which introduces several breaking changes. + See the [v8 changelog](https://github.com/google/zx/releases/tag/8.0.0) for more information. + +- The `portunus` package and service do not support weak password hashes anymore. + If you installed Portunus on NixOS 23.11 or earlier, upgrade to NixOS 24.05 first to get support for strong password hashing. + Then, follow the instructions on the [upstream release notes](https://github.com/majewsky/portunus/releases/tag/v2.0.0) to upgrade all existing user accounts to strong password hashes. + If you need to upgrade to 24.11 without having completed the migration, consider the security implications of weak password hashes on your user accounts, and add the following to your configuration: + ```nix + services.portunus.package = pkgs.portunus.override { libxcrypt = pkgs.libxcrypt-legacy; }; + services.portunus.ldap.package = pkgs.openldap.override { libxcrypt = pkgs.libxcrypt-legacy; }; + ``` + +- The `tracy` package no longer works on X11, since it's moved to Wayland + support, which is the intended default behavior by Tracy maintainers. + X11 users have to switch to the new package `tracy-x11`. + +## Other Notable Changes {#sec-release-24.11-notable-changes} + + + +- `hareHook` has been added as the language framework for Hare. From now on, it, + not the `hare` package, should be added to `nativeBuildInputs` when building + Hare programs. + +- To facilitate dependency injection, the `imgui` package now builds a static archive using vcpkg' CMake rules. + The derivation now installs "impl" headers selectively instead of by a wildcard. + Use `imgui.src` if you just want to access the unpacked sources. diff --git a/nixos/lib/systemd-lib.nix b/nixos/lib/systemd-lib.nix index 0641da8e77517..dac5cc7b700c8 100644 --- a/nixos/lib/systemd-lib.nix +++ b/nixos/lib/systemd-lib.nix @@ -182,6 +182,30 @@ in rec { in if errors == [] then true else trace (concatStringsSep "\n" errors) false; + checkUnitConfigWithLegacyKey = legacyKey: group: checks: attrs: + let + dump = lib.generators.toPretty { } + (lib.generators.withRecursion { depthLimit = 2; throwOnDepthLimit = false; } attrs); + attrs' = + if legacyKey == null + then attrs + else if ! attrs?${legacyKey} + then attrs + else if removeAttrs attrs [ legacyKey ] == {} + then attrs.${legacyKey} + else throw '' + The declaration + + ${dump} + + must not mix unit options with the legacy key '${legacyKey}'. + + This can be fixed by moving all settings from within ${legacyKey} + one level up. + ''; + in + checkUnitConfig group checks attrs'; + toOption = x: if x == true then "true" else if x == false then "false" diff --git a/nixos/lib/systemd-network-units.nix b/nixos/lib/systemd-network-units.nix index ae581495772a8..c35309a6d2628 100644 --- a/nixos/lib/systemd-network-units.nix +++ b/nixos/lib/systemd-network-units.nix @@ -63,13 +63,13 @@ in { ${attrsToSection def.l2tpConfig} '' + flip concatMapStrings def.l2tpSessions (x: '' [L2TPSession] - ${attrsToSection x.l2tpSessionConfig} + ${attrsToSection x} '') + optionalString (def.wireguardConfig != { }) '' [WireGuard] ${attrsToSection def.wireguardConfig} '' + flip concatMapStrings def.wireguardPeers (x: '' [WireGuardPeer] - ${attrsToSection x.wireguardPeerConfig} + ${attrsToSection x} '') + optionalString (def.bondConfig != { }) '' [Bond] ${attrsToSection def.bondConfig} @@ -122,13 +122,13 @@ in { ${concatStringsSep "\n" (map (s: "Xfrm=${s}") def.xfrm)} '' + "\n" + flip concatMapStrings def.addresses (x: '' [Address] - ${attrsToSection x.addressConfig} + ${attrsToSection x} '') + flip concatMapStrings def.routingPolicyRules (x: '' [RoutingPolicyRule] - ${attrsToSection x.routingPolicyRuleConfig} + ${attrsToSection x} '') + flip concatMapStrings def.routes (x: '' [Route] - ${attrsToSection x.routeConfig} + ${attrsToSection x} '') + optionalString (def.dhcpV4Config != { }) '' [DHCPv4] ${attrsToSection def.dhcpV4Config} @@ -147,24 +147,27 @@ in { '' + optionalString (def.ipv6SendRAConfig != { }) '' [IPv6SendRA] ${attrsToSection def.ipv6SendRAConfig} - '' + flip concatMapStrings def.ipv6Prefixes (x: '' + '' + flip concatMapStrings def.ipv6PREF64Prefixes (x: '' + [IPv6PREF64Prefix] + ${attrsToSection x} + '') + flip concatMapStrings def.ipv6Prefixes (x: '' [IPv6Prefix] - ${attrsToSection x.ipv6PrefixConfig} + ${attrsToSection x} '') + flip concatMapStrings def.ipv6RoutePrefixes (x: '' [IPv6RoutePrefix] - ${attrsToSection x.ipv6RoutePrefixConfig} + ${attrsToSection x} '') + flip concatMapStrings def.dhcpServerStaticLeases (x: '' [DHCPServerStaticLease] - ${attrsToSection x.dhcpServerStaticLeaseConfig} + ${attrsToSection x} '') + optionalString (def.bridgeConfig != { }) '' [Bridge] ${attrsToSection def.bridgeConfig} '' + flip concatMapStrings def.bridgeFDBs (x: '' [BridgeFDB] - ${attrsToSection x.bridgeFDBConfig} + ${attrsToSection x} '') + flip concatMapStrings def.bridgeMDBs (x: '' [BridgeMDB] - ${attrsToSection x.bridgeMDBConfig} + ${attrsToSection x} '') + optionalString (def.lldpConfig != { }) '' [LLDP] ${attrsToSection def.lldpConfig} @@ -251,7 +254,7 @@ in { ${attrsToSection def.quickFairQueueingConfigClass} '' + flip concatMapStrings def.bridgeVLANs (x: '' [BridgeVLAN] - ${attrsToSection x.bridgeVLANConfig} + ${attrsToSection x} '') + def.extraConfig; } diff --git a/nixos/lib/test-driver/default.nix b/nixos/lib/test-driver/default.nix index 1acdaacc4e658..26652db6016e6 100644 --- a/nixos/lib/test-driver/default.nix +++ b/nixos/lib/test-driver/default.nix @@ -13,17 +13,27 @@ , extraPythonPackages ? (_ : []) , nixosTests }: - +let + fs = lib.fileset; +in python3Packages.buildPythonApplication { pname = "nixos-test-driver"; version = "1.1"; - src = ./.; + src = fs.toSource { + root = ./.; + fileset = fs.unions [ + ./pyproject.toml + ./test_driver + ./extract-docstrings.py + ]; + }; pyproject = true; propagatedBuildInputs = [ coreutils netpbm python3Packages.colorama + python3Packages.junit-xml python3Packages.ptpython qemu_pkg socat @@ -46,7 +56,7 @@ python3Packages.buildPythonApplication { echo -e "\x1b[32m## run mypy\x1b[0m" mypy test_driver extract-docstrings.py echo -e "\x1b[32m## run ruff\x1b[0m" - ruff . + ruff check . echo -e "\x1b[32m## run black\x1b[0m" black --check --diff . ''; diff --git a/nixos/lib/test-driver/pyproject.toml b/nixos/lib/test-driver/pyproject.toml index 17b7130a4bad7..714139bc1b25c 100644 --- a/nixos/lib/test-driver/pyproject.toml +++ b/nixos/lib/test-driver/pyproject.toml @@ -19,8 +19,8 @@ test_driver = ["py.typed"] [tool.ruff] line-length = 88 -select = ["E", "F", "I", "U", "N"] -ignore = ["E501"] +lint.select = ["E", "F", "I", "U", "N"] +lint.ignore = ["E501"] # xxx: we can import https://pypi.org/project/types-colorama/ here [[tool.mypy.overrides]] @@ -31,6 +31,10 @@ ignore_missing_imports = true module = "ptpython.*" ignore_missing_imports = true +[[tool.mypy.overrides]] +module = "junit_xml.*" +ignore_missing_imports = true + [tool.black] line-length = 88 target-version = ['py39'] diff --git a/nixos/lib/test-driver/test_driver/__init__.py b/nixos/lib/test-driver/test_driver/__init__.py index 9daae1e941a65..42b6d29b76714 100755 --- a/nixos/lib/test-driver/test_driver/__init__.py +++ b/nixos/lib/test-driver/test_driver/__init__.py @@ -6,7 +6,12 @@ import ptpython.repl from test_driver.driver import Driver -from test_driver.logger import rootlog +from test_driver.logger import ( + CompositeLogger, + JunitXMLLogger, + TerminalLogger, + XMLLogger, +) class EnvDefault(argparse.Action): @@ -92,6 +97,11 @@ def main() -> None: default=Path.cwd(), type=writeable_dir, ) + arg_parser.add_argument( + "--junit-xml", + help="Enable JunitXML report generation to the given path", + type=Path, + ) arg_parser.add_argument( "testscript", action=EnvDefault, @@ -102,14 +112,24 @@ def main() -> None: args = arg_parser.parse_args() + output_directory = args.output_directory.resolve() + logger = CompositeLogger([TerminalLogger()]) + + if "LOGFILE" in os.environ.keys(): + logger.add_logger(XMLLogger(os.environ["LOGFILE"])) + + if args.junit_xml: + logger.add_logger(JunitXMLLogger(output_directory / args.junit_xml)) + if not args.keep_vm_state: - rootlog.info("Machine state will be reset. To keep it, pass --keep-vm-state") + logger.info("Machine state will be reset. To keep it, pass --keep-vm-state") with Driver( args.start_scripts, args.vlans, args.testscript.read_text(), - args.output_directory.resolve(), + output_directory, + logger, args.keep_vm_state, args.global_timeout, ) as driver: @@ -125,7 +145,7 @@ def main() -> None: tic = time.time() driver.run_tests() toc = time.time() - rootlog.info(f"test script finished in {(toc-tic):.2f}s") + logger.info(f"test script finished in {(toc-tic):.2f}s") def generate_driver_symbols() -> None: @@ -134,7 +154,7 @@ def generate_driver_symbols() -> None: in user's test scripts. That list is then used by pyflakes to lint those scripts. """ - d = Driver([], [], "", Path()) + d = Driver([], [], "", Path(), CompositeLogger([])) test_symbols = d.test_symbols() with open("driver-symbols", "w") as fp: fp.write(",".join(test_symbols.keys())) diff --git a/nixos/lib/test-driver/test_driver/driver.py b/nixos/lib/test-driver/test_driver/driver.py index f792c04591996..01b64b92e9770 100644 --- a/nixos/lib/test-driver/test_driver/driver.py +++ b/nixos/lib/test-driver/test_driver/driver.py @@ -9,7 +9,7 @@ from colorama import Fore, Style -from test_driver.logger import rootlog +from test_driver.logger import AbstractLogger from test_driver.machine import Machine, NixStartScript, retry from test_driver.polling_condition import PollingCondition from test_driver.vlan import VLan @@ -49,6 +49,7 @@ class Driver: polling_conditions: List[PollingCondition] global_timeout: int race_timer: threading.Timer + logger: AbstractLogger def __init__( self, @@ -56,6 +57,7 @@ def __init__( vlans: List[int], tests: str, out_dir: Path, + logger: AbstractLogger, keep_vm_state: bool = False, global_timeout: int = 24 * 60 * 60 * 7, ): @@ -63,12 +65,13 @@ def __init__( self.out_dir = out_dir self.global_timeout = global_timeout self.race_timer = threading.Timer(global_timeout, self.terminate_test) + self.logger = logger tmp_dir = get_tmp_dir() - with rootlog.nested("start all VLans"): + with self.logger.nested("start all VLans"): vlans = list(set(vlans)) - self.vlans = [VLan(nr, tmp_dir) for nr in vlans] + self.vlans = [VLan(nr, tmp_dir, self.logger) for nr in vlans] def cmd(scripts: List[str]) -> Iterator[NixStartScript]: for s in scripts: @@ -84,6 +87,7 @@ def cmd(scripts: List[str]) -> Iterator[NixStartScript]: tmp_dir=tmp_dir, callbacks=[self.check_polling_conditions], out_dir=self.out_dir, + logger=self.logger, ) for cmd in cmd(start_scripts) ] @@ -92,19 +96,18 @@ def __enter__(self) -> "Driver": return self def __exit__(self, *_: Any) -> None: - with rootlog.nested("cleanup"): + with self.logger.nested("cleanup"): self.race_timer.cancel() for machine in self.machines: machine.release() def subtest(self, name: str) -> Iterator[None]: """Group logs under a given test name""" - with rootlog.nested("subtest: " + name): + with self.logger.subtest(name): try: yield - return True except Exception as e: - rootlog.error(f'Test "{name}" failed with error: "{e}"') + self.logger.error(f'Test "{name}" failed with error: "{e}"') raise e def test_symbols(self) -> Dict[str, Any]: @@ -118,7 +121,7 @@ def subtest(name: str) -> Iterator[None]: machines=self.machines, vlans=self.vlans, driver=self, - log=rootlog, + log=self.logger, os=os, create_machine=self.create_machine, subtest=subtest, @@ -150,13 +153,13 @@ def subtest(name: str) -> Iterator[None]: def test_script(self) -> None: """Run the test script""" - with rootlog.nested("run the VM test script"): + with self.logger.nested("run the VM test script"): symbols = self.test_symbols() # call eagerly exec(self.tests, symbols, None) def run_tests(self) -> None: """Run the test script (for non-interactive test runs)""" - rootlog.info( + self.logger.info( f"Test will time out and terminate in {self.global_timeout} seconds" ) self.race_timer.start() @@ -168,13 +171,13 @@ def run_tests(self) -> None: def start_all(self) -> None: """Start all machines""" - with rootlog.nested("start all VMs"): + with self.logger.nested("start all VMs"): for machine in self.machines: machine.start() def join_all(self) -> None: """Wait for all machines to shut down""" - with rootlog.nested("wait for all VMs to finish"): + with self.logger.nested("wait for all VMs to finish"): for machine in self.machines: machine.wait_for_shutdown() self.race_timer.cancel() @@ -182,7 +185,7 @@ def join_all(self) -> None: def terminate_test(self) -> None: # This will be usually running in another thread than # the thread actually executing the test script. - with rootlog.nested("timeout reached; test terminating..."): + with self.logger.nested("timeout reached; test terminating..."): for machine in self.machines: machine.release() # As we cannot `sys.exit` from another thread @@ -227,7 +230,7 @@ def create_machine( f"Unsupported arguments passed to create_machine: {args}" ) - rootlog.warning( + self.logger.warning( Fore.YELLOW + Style.BRIGHT + "WARNING: Using create_machine with a single dictionary argument is deprecated and will be removed in NixOS 24.11" @@ -246,13 +249,14 @@ def create_machine( start_command=cmd, name=name, keep_vm_state=keep_vm_state, + logger=self.logger, ) def serial_stdout_on(self) -> None: - rootlog._print_serial_logs = True + self.logger.print_serial_logs(True) def serial_stdout_off(self) -> None: - rootlog._print_serial_logs = False + self.logger.print_serial_logs(False) def check_polling_conditions(self) -> None: for condition in self.polling_conditions: @@ -271,6 +275,7 @@ class Poll: def __init__(self, fun: Callable): self.condition = PollingCondition( fun, + driver.logger, seconds_interval, description, ) @@ -285,15 +290,17 @@ def __exit__(self, a, b, c) -> None: # type: ignore def wait(self, timeout: int = 900) -> None: def condition(last: bool) -> bool: if last: - rootlog.info(f"Last chance for {self.condition.description}") + driver.logger.info( + f"Last chance for {self.condition.description}" + ) ret = self.condition.check(force=True) if not ret and not last: - rootlog.info( + driver.logger.info( f"({self.condition.description} failure not fatal yet)" ) return ret - with rootlog.nested(f"waiting for {self.condition.description}"): + with driver.logger.nested(f"waiting for {self.condition.description}"): retry(condition, timeout=timeout) if fun_ is None: diff --git a/nixos/lib/test-driver/test_driver/logger.py b/nixos/lib/test-driver/test_driver/logger.py index 0b0623bddfa1e..484829254b812 100644 --- a/nixos/lib/test-driver/test_driver/logger.py +++ b/nixos/lib/test-driver/test_driver/logger.py @@ -1,33 +1,238 @@ +import atexit import codecs import os import sys import time import unicodedata -from contextlib import contextmanager +from abc import ABC, abstractmethod +from contextlib import ExitStack, contextmanager +from pathlib import Path from queue import Empty, Queue -from typing import Any, Dict, Iterator +from typing import Any, Dict, Iterator, List from xml.sax.saxutils import XMLGenerator from xml.sax.xmlreader import AttributesImpl from colorama import Fore, Style +from junit_xml import TestCase, TestSuite -class Logger: - def __init__(self) -> None: - self.logfile = os.environ.get("LOGFILE", "/dev/null") - self.logfile_handle = codecs.open(self.logfile, "wb") - self.xml = XMLGenerator(self.logfile_handle, encoding="utf-8") - self.queue: "Queue[Dict[str, str]]" = Queue() +class AbstractLogger(ABC): + @abstractmethod + def log(self, message: str, attributes: Dict[str, str] = {}) -> None: + pass - self.xml.startDocument() - self.xml.startElement("logfile", attrs=AttributesImpl({})) + @abstractmethod + @contextmanager + def subtest(self, name: str, attributes: Dict[str, str] = {}) -> Iterator[None]: + pass + + @abstractmethod + @contextmanager + def nested(self, message: str, attributes: Dict[str, str] = {}) -> Iterator[None]: + pass + + @abstractmethod + def info(self, *args, **kwargs) -> None: # type: ignore + pass + + @abstractmethod + def warning(self, *args, **kwargs) -> None: # type: ignore + pass + + @abstractmethod + def error(self, *args, **kwargs) -> None: # type: ignore + pass + + @abstractmethod + def log_serial(self, message: str, machine: str) -> None: + pass + + @abstractmethod + def print_serial_logs(self, enable: bool) -> None: + pass + + +class JunitXMLLogger(AbstractLogger): + class TestCaseState: + def __init__(self) -> None: + self.stdout = "" + self.stderr = "" + self.failure = False + + def __init__(self, outfile: Path) -> None: + self.tests: dict[str, JunitXMLLogger.TestCaseState] = { + "main": self.TestCaseState() + } + self.currentSubtest = "main" + self.outfile: Path = outfile + self._print_serial_logs = True + atexit.register(self.close) + + def log(self, message: str, attributes: Dict[str, str] = {}) -> None: + self.tests[self.currentSubtest].stdout += message + os.linesep + + @contextmanager + def subtest(self, name: str, attributes: Dict[str, str] = {}) -> Iterator[None]: + old_test = self.currentSubtest + self.tests.setdefault(name, self.TestCaseState()) + self.currentSubtest = name + + yield + + self.currentSubtest = old_test + + @contextmanager + def nested(self, message: str, attributes: Dict[str, str] = {}) -> Iterator[None]: + self.log(message) + yield + + def info(self, *args, **kwargs) -> None: # type: ignore + self.tests[self.currentSubtest].stdout += args[0] + os.linesep + + def warning(self, *args, **kwargs) -> None: # type: ignore + self.tests[self.currentSubtest].stdout += args[0] + os.linesep + + def error(self, *args, **kwargs) -> None: # type: ignore + self.tests[self.currentSubtest].stderr += args[0] + os.linesep + self.tests[self.currentSubtest].failure = True + + def log_serial(self, message: str, machine: str) -> None: + if not self._print_serial_logs: + return + + self.log(f"{machine} # {message}") + + def print_serial_logs(self, enable: bool) -> None: + self._print_serial_logs = enable + + def close(self) -> None: + with open(self.outfile, "w") as f: + test_cases = [] + for name, test_case_state in self.tests.items(): + tc = TestCase( + name, + stdout=test_case_state.stdout, + stderr=test_case_state.stderr, + ) + if test_case_state.failure: + tc.add_failure_info("test case failed") + + test_cases.append(tc) + ts = TestSuite("NixOS integration test", test_cases) + f.write(TestSuite.to_xml_string([ts])) + + +class CompositeLogger(AbstractLogger): + def __init__(self, logger_list: List[AbstractLogger]) -> None: + self.logger_list = logger_list + + def add_logger(self, logger: AbstractLogger) -> None: + self.logger_list.append(logger) + + def log(self, message: str, attributes: Dict[str, str] = {}) -> None: + for logger in self.logger_list: + logger.log(message, attributes) + + @contextmanager + def subtest(self, name: str, attributes: Dict[str, str] = {}) -> Iterator[None]: + with ExitStack() as stack: + for logger in self.logger_list: + stack.enter_context(logger.subtest(name, attributes)) + yield + + @contextmanager + def nested(self, message: str, attributes: Dict[str, str] = {}) -> Iterator[None]: + with ExitStack() as stack: + for logger in self.logger_list: + stack.enter_context(logger.nested(message, attributes)) + yield + + def info(self, *args, **kwargs) -> None: # type: ignore + for logger in self.logger_list: + logger.info(*args, **kwargs) + + def warning(self, *args, **kwargs) -> None: # type: ignore + for logger in self.logger_list: + logger.warning(*args, **kwargs) + + def error(self, *args, **kwargs) -> None: # type: ignore + for logger in self.logger_list: + logger.error(*args, **kwargs) + sys.exit(1) + def print_serial_logs(self, enable: bool) -> None: + for logger in self.logger_list: + logger.print_serial_logs(enable) + + def log_serial(self, message: str, machine: str) -> None: + for logger in self.logger_list: + logger.log_serial(message, machine) + + +class TerminalLogger(AbstractLogger): + def __init__(self) -> None: self._print_serial_logs = True + def maybe_prefix(self, message: str, attributes: Dict[str, str]) -> str: + if "machine" in attributes: + return f"{attributes['machine']}: {message}" + return message + @staticmethod def _eprint(*args: object, **kwargs: Any) -> None: print(*args, file=sys.stderr, **kwargs) + def log(self, message: str, attributes: Dict[str, str] = {}) -> None: + self._eprint(self.maybe_prefix(message, attributes)) + + @contextmanager + def subtest(self, name: str, attributes: Dict[str, str] = {}) -> Iterator[None]: + with self.nested("subtest: " + name, attributes): + yield + + @contextmanager + def nested(self, message: str, attributes: Dict[str, str] = {}) -> Iterator[None]: + self._eprint( + self.maybe_prefix( + Style.BRIGHT + Fore.GREEN + message + Style.RESET_ALL, attributes + ) + ) + + tic = time.time() + yield + toc = time.time() + self.log(f"(finished: {message}, in {toc - tic:.2f} seconds)") + + def info(self, *args, **kwargs) -> None: # type: ignore + self.log(*args, **kwargs) + + def warning(self, *args, **kwargs) -> None: # type: ignore + self.log(*args, **kwargs) + + def error(self, *args, **kwargs) -> None: # type: ignore + self.log(*args, **kwargs) + + def print_serial_logs(self, enable: bool) -> None: + self._print_serial_logs = enable + + def log_serial(self, message: str, machine: str) -> None: + if not self._print_serial_logs: + return + + self._eprint(Style.DIM + f"{machine} # {message}" + Style.RESET_ALL) + + +class XMLLogger(AbstractLogger): + def __init__(self, outfile: str) -> None: + self.logfile_handle = codecs.open(outfile, "wb") + self.xml = XMLGenerator(self.logfile_handle, encoding="utf-8") + self.queue: Queue[dict[str, str]] = Queue() + + self._print_serial_logs = True + + self.xml.startDocument() + self.xml.startElement("logfile", attrs=AttributesImpl({})) + def close(self) -> None: self.xml.endElement("logfile") self.xml.endDocument() @@ -54,17 +259,19 @@ def warning(self, *args, **kwargs) -> None: # type: ignore def error(self, *args, **kwargs) -> None: # type: ignore self.log(*args, **kwargs) - sys.exit(1) def log(self, message: str, attributes: Dict[str, str] = {}) -> None: - self._eprint(self.maybe_prefix(message, attributes)) self.drain_log_queue() self.log_line(message, attributes) + def print_serial_logs(self, enable: bool) -> None: + self._print_serial_logs = enable + def log_serial(self, message: str, machine: str) -> None: + if not self._print_serial_logs: + return + self.enqueue({"msg": message, "machine": machine, "type": "serial"}) - if self._print_serial_logs: - self._eprint(Style.DIM + f"{machine} # {message}" + Style.RESET_ALL) def enqueue(self, item: Dict[str, str]) -> None: self.queue.put(item) @@ -80,13 +287,12 @@ def drain_log_queue(self) -> None: pass @contextmanager - def nested(self, message: str, attributes: Dict[str, str] = {}) -> Iterator[None]: - self._eprint( - self.maybe_prefix( - Style.BRIGHT + Fore.GREEN + message + Style.RESET_ALL, attributes - ) - ) + def subtest(self, name: str, attributes: Dict[str, str] = {}) -> Iterator[None]: + with self.nested("subtest: " + name, attributes): + yield + @contextmanager + def nested(self, message: str, attributes: Dict[str, str] = {}) -> Iterator[None]: self.xml.startElement("nest", attrs=AttributesImpl({})) self.xml.startElement("head", attrs=AttributesImpl(attributes)) self.xml.characters(message) @@ -100,6 +306,3 @@ def nested(self, message: str, attributes: Dict[str, str] = {}) -> Iterator[None self.log(f"(finished: {message}, in {toc - tic:.2f} seconds)") self.xml.endElement("nest") - - -rootlog = Logger() diff --git a/nixos/lib/test-driver/test_driver/machine.py b/nixos/lib/test-driver/test_driver/machine.py index 652cc600fad59..3a1d5bc1be764 100644 --- a/nixos/lib/test-driver/test_driver/machine.py +++ b/nixos/lib/test-driver/test_driver/machine.py @@ -17,7 +17,7 @@ from queue import Queue from typing import Any, Callable, Dict, Iterable, List, Optional, Tuple -from test_driver.logger import rootlog +from test_driver.logger import AbstractLogger from .qmp import QMPSession @@ -270,6 +270,7 @@ def __init__( out_dir: Path, tmp_dir: Path, start_command: StartCommand, + logger: AbstractLogger, name: str = "machine", keep_vm_state: bool = False, callbacks: Optional[List[Callable]] = None, @@ -280,6 +281,7 @@ def __init__( self.name = name self.start_command = start_command self.callbacks = callbacks if callbacks is not None else [] + self.logger = logger # set up directories self.shared_dir = self.tmp_dir / "shared-xchg" @@ -307,15 +309,15 @@ def is_up(self) -> bool: return self.booted and self.connected def log(self, msg: str) -> None: - rootlog.log(msg, {"machine": self.name}) + self.logger.log(msg, {"machine": self.name}) def log_serial(self, msg: str) -> None: - rootlog.log_serial(msg, self.name) + self.logger.log_serial(msg, self.name) def nested(self, msg: str, attrs: Dict[str, str] = {}) -> _GeneratorContextManager: my_attrs = {"machine": self.name} my_attrs.update(attrs) - return rootlog.nested(msg, my_attrs) + return self.logger.nested(msg, my_attrs) def wait_for_monitor_prompt(self) -> str: assert self.monitor is not None @@ -1113,8 +1115,8 @@ def process_serial_output() -> None: def cleanup_statedir(self) -> None: shutil.rmtree(self.state_dir) - rootlog.log(f"deleting VM state directory {self.state_dir}") - rootlog.log("if you want to keep the VM state, pass --keep-vm-state") + self.logger.log(f"deleting VM state directory {self.state_dir}") + self.logger.log("if you want to keep the VM state, pass --keep-vm-state") def shutdown(self) -> None: """ @@ -1221,7 +1223,7 @@ def unblock(self) -> None: def release(self) -> None: if self.pid is None: return - rootlog.info(f"kill machine (pid {self.pid})") + self.logger.info(f"kill machine (pid {self.pid})") assert self.process assert self.shell assert self.monitor diff --git a/nixos/lib/test-driver/test_driver/polling_condition.py b/nixos/lib/test-driver/test_driver/polling_condition.py index 12cbad69e34e9..1cccaf2c71e74 100644 --- a/nixos/lib/test-driver/test_driver/polling_condition.py +++ b/nixos/lib/test-driver/test_driver/polling_condition.py @@ -2,7 +2,7 @@ from math import isfinite from typing import Callable, Optional -from .logger import rootlog +from test_driver.logger import AbstractLogger class PollingConditionError(Exception): @@ -13,6 +13,7 @@ class PollingCondition: condition: Callable[[], bool] seconds_interval: float description: Optional[str] + logger: AbstractLogger last_called: float entry_count: int @@ -20,11 +21,13 @@ class PollingCondition: def __init__( self, condition: Callable[[], Optional[bool]], + logger: AbstractLogger, seconds_interval: float = 2.0, description: Optional[str] = None, ): self.condition = condition # type: ignore self.seconds_interval = seconds_interval + self.logger = logger if description is None: if condition.__doc__: @@ -41,7 +44,7 @@ def check(self, force: bool = False) -> bool: if (self.entered or not self.overdue) and not force: return True - with self, rootlog.nested(self.nested_message): + with self, self.logger.nested(self.nested_message): time_since_last = time.monotonic() - self.last_called last_message = ( f"Time since last: {time_since_last:.2f}s" @@ -49,13 +52,13 @@ def check(self, force: bool = False) -> bool: else "(not called yet)" ) - rootlog.info(last_message) + self.logger.info(last_message) try: res = self.condition() # type: ignore except Exception: res = False res = res is None or res - rootlog.info(self.status_message(res)) + self.logger.info(self.status_message(res)) return res def maybe_raise(self) -> None: diff --git a/nixos/lib/test-driver/test_driver/vlan.py b/nixos/lib/test-driver/test_driver/vlan.py index ec9679108e58d..9340fc92ed4c4 100644 --- a/nixos/lib/test-driver/test_driver/vlan.py +++ b/nixos/lib/test-driver/test_driver/vlan.py @@ -4,7 +4,7 @@ import subprocess from pathlib import Path -from test_driver.logger import rootlog +from test_driver.logger import AbstractLogger class VLan: @@ -19,17 +19,20 @@ class VLan: pid: int fd: io.TextIOBase + logger: AbstractLogger + def __repr__(self) -> str: return f"" - def __init__(self, nr: int, tmp_dir: Path): + def __init__(self, nr: int, tmp_dir: Path, logger: AbstractLogger): self.nr = nr self.socket_dir = tmp_dir / f"vde{self.nr}.ctl" + self.logger = logger # TODO: don't side-effect environment here os.environ[f"QEMU_VDE_SOCKET_{self.nr}"] = str(self.socket_dir) - rootlog.info("start vlan") + self.logger.info("start vlan") pty_master, pty_slave = pty.openpty() # The --hub is required for the scenario determined by @@ -52,11 +55,11 @@ def __init__(self, nr: int, tmp_dir: Path): assert self.process.stdout is not None self.process.stdout.readline() if not (self.socket_dir / "ctl").exists(): - rootlog.error("cannot start vde_switch") + self.logger.error("cannot start vde_switch") - rootlog.info(f"running vlan (pid {self.pid}; ctl {self.socket_dir})") + self.logger.info(f"running vlan (pid {self.pid}; ctl {self.socket_dir})") def __del__(self) -> None: - rootlog.info(f"kill vlan (pid {self.pid})") + self.logger.info(f"kill vlan (pid {self.pid})") self.fd.close() self.process.terminate() diff --git a/nixos/lib/test-script-prepend.py b/nixos/lib/test-script-prepend.py index 976992ea00158..9d2efdf973031 100644 --- a/nixos/lib/test-script-prepend.py +++ b/nixos/lib/test-script-prepend.py @@ -4,7 +4,7 @@ from test_driver.driver import Driver from test_driver.vlan import VLan from test_driver.machine import Machine -from test_driver.logger import Logger +from test_driver.logger import AbstractLogger from typing import Callable, Iterator, ContextManager, Optional, List, Dict, Any, Union from typing_extensions import Protocol from pathlib import Path @@ -44,7 +44,7 @@ def __call__( machines: List[Machine] vlans: List[VLan] driver: Driver -log: Logger +log: AbstractLogger create_machine: CreateMachineProtocol run_tests: Callable[[], None] join_all: Callable[[], None] diff --git a/nixos/maintainers/scripts/ec2/README.md b/nixos/maintainers/scripts/ec2/README.md index 1328109d464a3..eb2c9088d5a2c 100644 --- a/nixos/maintainers/scripts/ec2/README.md +++ b/nixos/maintainers/scripts/ec2/README.md @@ -1,7 +1,36 @@ # Amazon images -* The `create-amis.sh` script will be replaced by https://github.com/NixOS/amis which will regularly upload AMIs per NixOS channel bump. +AMIs are regularly uploaded from Hydra. This automation lives in +https://github.com/NixOS/amis -* @arianvp is planning to drop zfs support -* @arianvp is planning to rewrite the image builder to use the repart-based image builder. +## How to upload an AMI for testing + +If you want to upload an AMI from changes in a local nixpkgs checkout. + +```bash +nix-build nixos/release.nix -A amazonImage + +export AWS_REGION=us-west-2 +export AWS_PROFILE=my-profile +nix run nixpkgs#upload-ami -- --image-info ./result/nix-support/image-info.json +``` + +## How to build your own NixOS config into an AMI + +I suggest looking at https://github.com/nix-community/nixos-generators for a user-friendly interface. + +```bash +nixos-generate -c ./my-config.nix -f amazon + +export AWS_REGION=us-west-2 +export AWS_PROFILE=my-profile +nix run github:NixOS/amis#upload-ami -- --image-info ./result/nix-support/image-info.json +``` + +## Roadmap + +* @arianvp is planning to drop zfs support unless someone else picks it up +* @arianvp is planning to rewrite the image builder to use the repart-based image builder. +* @arianvp is planning to perhaps rewrite `upload-ami` to use coldnsap +* @arianvp is planning to move `upload-ami` tooling into nixpkgs once it has stabilized. And only keep the Github Action in separate repo diff --git a/nixos/maintainers/scripts/ec2/amazon-image.nix b/nixos/maintainers/scripts/ec2/amazon-image.nix index 357b86367d984..8b6a9bc52b128 100644 --- a/nixos/maintainers/scripts/ec2/amazon-image.nix +++ b/nixos/maintainers/scripts/ec2/amazon-image.nix @@ -71,9 +71,8 @@ in { ''; zfsBuilder = import ../../../lib/make-multi-disk-zfs-image.nix { - inherit lib config configFile; + inherit lib config configFile pkgs; inherit (cfg) contents format name; - pkgs = import ../../../.. { inherit (pkgs) system; }; # ensure we use the regular qemu-kvm package includeChannel = true; @@ -120,10 +119,9 @@ in { }; extBuilder = import ../../../lib/make-disk-image.nix { - inherit lib config configFile; + inherit lib config configFile pkgs; inherit (cfg) contents format name; - pkgs = import ../../../.. { inherit (pkgs) system; }; # ensure we use the regular qemu-kvm package fsType = "ext4"; partitionTableType = if config.ec2.efi then "efi" else "legacy+gpt"; diff --git a/nixos/maintainers/scripts/ec2/create-amis.sh b/nixos/maintainers/scripts/ec2/create-amis.sh deleted file mode 100755 index d182c5c2a4794..0000000000000 --- a/nixos/maintainers/scripts/ec2/create-amis.sh +++ /dev/null @@ -1,368 +0,0 @@ -#!/usr/bin/env nix-shell -#!nix-shell -p awscli -p jq -p qemu -i bash -# shellcheck shell=bash -# -# Future Deprecation? -# This entire thing should probably be replaced with a generic terraform config - -# Uploads and registers NixOS images built from the -# amazonImage attribute. Images are uploaded and -# registered via a home region, and then copied to other regions. - -# The home region requires an s3 bucket, and an IAM role named "vmimport" -# (by default) with access to the S3 bucket. The name can be -# configured with the "service_role_name" variable. Configuration of the -# vmimport role is documented in -# https://docs.aws.amazon.com/vm-import/latest/userguide/vmimport-image-import.html - -# set -x -set -euo pipefail - -var () { true; } - -# configuration -var ${state_dir:=$HOME/amis/ec2-images} -var ${home_region:=eu-west-1} -var ${bucket:=nixos-amis} -var ${service_role_name:=vmimport} - -# Output of the command: -# $ nix-shell -I nixpkgs=. -p awscli --run 'aws ec2 describe-regions --region us-east-1 --all-regions --query "Regions[].{Name:RegionName}" --output text | sort | sed -e s/^/\ \ /' -var ${regions:= - af-south-1 - ap-east-1 - ap-northeast-1 - ap-northeast-2 - ap-northeast-3 - ap-south-1 - ap-south-2 - ap-southeast-1 - ap-southeast-2 - ap-southeast-3 - ap-southeast-4 - ca-central-1 - eu-central-1 - eu-central-2 - eu-north-1 - eu-south-1 - eu-south-2 - eu-west-1 - eu-west-2 - eu-west-3 - il-central-1 - me-central-1 - me-south-1 - sa-east-1 - us-east-1 - us-east-2 - us-west-1 - us-west-2 -} - -regions=($regions) - -log() { - echo "$@" >&2 -} - -if [ "$#" -ne 1 ]; then - log "Usage: ./upload-amazon-image.sh IMAGE_OUTPUT" - exit 1 -fi - -# result of the amazon-image from nixos/release.nix -store_path=$1 - -if [ ! -e "$store_path" ]; then - log "Store path: $store_path does not exist, fetching..." - nix-store --realise "$store_path" -fi - -if [ ! -d "$store_path" ]; then - log "store_path: $store_path is not a directory. aborting" - exit 1 -fi - -read_image_info() { - if [ ! -e "$store_path/nix-support/image-info.json" ]; then - log "Image missing metadata" - exit 1 - fi - jq -r "$1" "$store_path/nix-support/image-info.json" -} - -# We handle a single image per invocation, store all attributes in -# globals for convenience. -zfs_disks=$(read_image_info .disks) -is_zfs_image= -if jq -e .boot <<< "$zfs_disks"; then - is_zfs_image=1 - zfs_boot=".disks.boot" -fi -image_label="$(read_image_info .label)${is_zfs_image:+-ZFS}" -image_system=$(read_image_info .system) -image_files=( $(read_image_info ".disks.root.file") ) - -image_logical_bytes=$(read_image_info "${zfs_boot:-.disks.root}.logical_bytes") - -if [[ -n "$is_zfs_image" ]]; then - image_files+=( $(read_image_info .disks.boot.file) ) -fi - -# Derived attributes - -image_logical_gigabytes=$(((image_logical_bytes-1)/1024/1024/1024+1)) # Round to the next GB - -case "$image_system" in - aarch64-linux) - amazon_arch=arm64 - ;; - x86_64-linux) - amazon_arch=x86_64 - ;; - *) - log "Unknown system: $image_system" - exit 1 -esac - -image_name="NixOS-${image_label}-${image_system}" -image_description="NixOS ${image_label} ${image_system}" - -log "Image Details:" -log " Name: $image_name" -log " Description: $image_description" -log " Size (gigabytes): $image_logical_gigabytes" -log " System: $image_system" -log " Amazon Arch: $amazon_arch" - -read_state() { - local state_key=$1 - local type=$2 - - cat "$state_dir/$state_key.$type" 2>/dev/null || true -} - -write_state() { - local state_key=$1 - local type=$2 - local val=$3 - - mkdir -p "$state_dir" - echo "$val" > "$state_dir/$state_key.$type" -} - -wait_for_import() { - local region=$1 - local task_id=$2 - local state snapshot_id - log "Waiting for import task $task_id to be completed" - while true; do - read -r state message snapshot_id < <( - aws ec2 describe-import-snapshot-tasks --region "$region" --import-task-ids "$task_id" | \ - jq -r '.ImportSnapshotTasks[].SnapshotTaskDetail | "\(.Status) \(.StatusMessage) \(.SnapshotId)"' - ) - log " ... state=$state message=$message snapshot_id=$snapshot_id" - case "$state" in - active) - sleep 10 - ;; - completed) - echo "$snapshot_id" - return - ;; - *) - log "Unexpected snapshot import state: '${state}'" - log "Full response: " - aws ec2 describe-import-snapshot-tasks --region "$region" --import-task-ids "$task_id" >&2 - exit 1 - ;; - esac - done -} - -wait_for_image() { - local region=$1 - local ami_id=$2 - local state - log "Waiting for image $ami_id to be available" - - while true; do - read -r state < <( - aws ec2 describe-images --image-ids "$ami_id" --region "$region" | \ - jq -r ".Images[].State" - ) - log " ... state=$state" - case "$state" in - pending) - sleep 10 - ;; - available) - return - ;; - *) - log "Unexpected AMI state: '${state}'" - exit 1 - ;; - esac - done -} - - -make_image_public() { - local region=$1 - local ami_id=$2 - - wait_for_image "$region" "$ami_id" - - log "Making image $ami_id public" - - aws ec2 modify-image-attribute \ - --image-id "$ami_id" --region "$region" --launch-permission 'Add={Group=all}' >&2 -} - -upload_image() { - local region=$1 - - for image_file in "${image_files[@]}"; do - local aws_path=${image_file#/} - - if [[ -n "$is_zfs_image" ]]; then - local suffix=${image_file%.*} - suffix=${suffix##*.} - fi - - local state_key="$region.$image_label${suffix:+.${suffix}}.$image_system" - local task_id - task_id=$(read_state "$state_key" task_id) - local snapshot_id - snapshot_id=$(read_state "$state_key" snapshot_id) - local ami_id - ami_id=$(read_state "$state_key" ami_id) - - if [ -z "$task_id" ]; then - log "Checking for image on S3" - if ! aws s3 ls --region "$region" "s3://${bucket}/${aws_path}" >&2; then - log "Image missing from aws, uploading" - aws s3 cp --region "$region" "$image_file" "s3://${bucket}/${aws_path}" >&2 - fi - - log "Importing image from S3 path s3://$bucket/$aws_path" - - task_id=$(aws ec2 import-snapshot --role-name "$service_role_name" --disk-container "{ - \"Description\": \"nixos-image-${image_label}-${image_system}\", - \"Format\": \"vhd\", - \"UserBucket\": { - \"S3Bucket\": \"$bucket\", - \"S3Key\": \"$aws_path\" - } - }" --region "$region" | jq -r '.ImportTaskId') - - write_state "$state_key" task_id "$task_id" - fi - - if [ -z "$snapshot_id" ]; then - snapshot_id=$(wait_for_import "$region" "$task_id") - write_state "$state_key" snapshot_id "$snapshot_id" - fi - done - - if [ -z "$ami_id" ]; then - log "Registering snapshot $snapshot_id as AMI" - - local block_device_mappings=( - "DeviceName=/dev/xvda,Ebs={SnapshotId=$snapshot_id,VolumeSize=$image_logical_gigabytes,DeleteOnTermination=true,VolumeType=gp3}" - ) - - if [[ -n "$is_zfs_image" ]]; then - local root_snapshot_id=$(read_state "$region.$image_label.root.$image_system" snapshot_id) - - local root_image_logical_bytes=$(read_image_info ".disks.root.logical_bytes") - local root_image_logical_gigabytes=$(((root_image_logical_bytes-1)/1024/1024/1024+1)) # Round to the next GB - - block_device_mappings+=( - "DeviceName=/dev/xvdb,Ebs={SnapshotId=$root_snapshot_id,VolumeSize=$root_image_logical_gigabytes,DeleteOnTermination=true,VolumeType=gp3}" - ) - fi - - - local extra_flags=( - --root-device-name /dev/xvda - --sriov-net-support simple - --ena-support - --virtualization-type hvm - ) - - block_device_mappings+=("DeviceName=/dev/sdb,VirtualName=ephemeral0") - block_device_mappings+=("DeviceName=/dev/sdc,VirtualName=ephemeral1") - block_device_mappings+=("DeviceName=/dev/sdd,VirtualName=ephemeral2") - block_device_mappings+=("DeviceName=/dev/sde,VirtualName=ephemeral3") - - ami_id=$( - aws ec2 register-image \ - --name "$image_name" \ - --description "$image_description" \ - --region "$region" \ - --architecture $amazon_arch \ - --block-device-mappings "${block_device_mappings[@]}" \ - --boot-mode $(read_image_info .boot_mode) \ - "${extra_flags[@]}" \ - | jq -r '.ImageId' - ) - - write_state "$state_key" ami_id "$ami_id" - fi - - [[ -v PRIVATE ]] || make_image_public "$region" "$ami_id" - - echo "$ami_id" -} - -copy_to_region() { - local region=$1 - local from_region=$2 - local from_ami_id=$3 - - state_key="$region.$image_label.$image_system" - ami_id=$(read_state "$state_key" ami_id) - - if [ -z "$ami_id" ]; then - log "Copying $from_ami_id to $region" - ami_id=$( - aws ec2 copy-image \ - --region "$region" \ - --source-region "$from_region" \ - --source-image-id "$from_ami_id" \ - --name "$image_name" \ - --description "$image_description" \ - | jq -r '.ImageId' - ) - - write_state "$state_key" ami_id "$ami_id" - fi - - [[ -v PRIVATE ]] || make_image_public "$region" "$ami_id" - - echo "$ami_id" -} - -upload_all() { - home_image_id=$(upload_image "$home_region") - jq -n \ - --arg key "$home_region.$image_system" \ - --arg value "$home_image_id" \ - '$ARGS.named' - - for region in "${regions[@]}"; do - if [ "$region" = "$home_region" ]; then - continue - fi - copied_image_id=$(copy_to_region "$region" "$home_region" "$home_image_id") - - jq -n \ - --arg key "$region.$image_system" \ - --arg value "$copied_image_id" \ - '$ARGS.named' - done -} - -upload_all | jq --slurp from_entries diff --git a/nixos/maintainers/scripts/lxd/lxd-container-image.nix b/nixos/maintainers/scripts/lxd/lxd-container-image.nix index 930ab34af3856..8c0e75e84f753 100644 --- a/nixos/maintainers/scripts/lxd/lxd-container-image.nix +++ b/nixos/maintainers/scripts/lxd/lxd-container-image.nix @@ -20,7 +20,7 @@ }; in '' if [ ! -e /etc/nixos/configuration.nix ]; then - install -m 644 -D ${config} /etc/nixos/configuration.nix + install -m 0644 -D ${config} /etc/nixos/configuration.nix fi ''; diff --git a/nixos/maintainers/scripts/lxd/lxd-virtual-machine-image.nix b/nixos/maintainers/scripts/lxd/lxd-virtual-machine-image.nix index bbbdd1f3fa173..8a1c9b0d634cd 100644 --- a/nixos/maintainers/scripts/lxd/lxd-virtual-machine-image.nix +++ b/nixos/maintainers/scripts/lxd/lxd-virtual-machine-image.nix @@ -20,8 +20,7 @@ }; in '' if [ ! -e /etc/nixos/configuration.nix ]; then - mkdir -p /etc/nixos - cp ${config} /etc/nixos/configuration.nix + install -m 0644 -D ${config} /etc/nixos/configuration.nix fi ''; diff --git a/nixos/modules/config/no-x-libs.nix b/nixos/modules/config/no-x-libs.nix index 1d7976cef36a2..87b6fea92ba4a 100644 --- a/nixos/modules/config/no-x-libs.nix +++ b/nixos/modules/config/no-x-libs.nix @@ -46,18 +46,20 @@ with lib; graphviz = super.graphviz-nox; gst_all_1 = super.gst_all_1 // { gst-plugins-bad = super.gst_all_1.gst-plugins-bad.override { guiSupport = false; }; - gst-plugins-base = super.gst_all_1.gst-plugins-base.override { enableWayland = false; enableX11 = false; }; + gst-plugins-base = super.gst_all_1.gst-plugins-base.override { enableGl = false; enableWayland = false; enableX11 = false; }; gst-plugins-good = super.gst_all_1.gst-plugins-good.override { enableWayland = false; enableX11 = false; gtkSupport = false; qt5Support = false; qt6Support = false; }; + gst-plugins-rs = super.gst_all_1.gst-plugins-rs.override { withGtkPlugins = false; }; }; imagemagick = super.imagemagick.override { libX11Support = false; libXtSupport = false; }; imagemagickBig = super.imagemagickBig.override { libX11Support = false; libXtSupport = false; }; intel-vaapi-driver = super.intel-vaapi-driver.override { enableGui = false; }; libdevil = super.libdevil-nox; libextractor = super.libextractor.override { gtkSupport = false; }; + libplacebo = super.libplacebo.override { vulkanSupport = false; }; libva = super.libva-minimal; limesuite = super.limesuite.override { withGui = false; }; mc = super.mc.override { x11Support = false; }; - mpv-unwrapped = super.mpv-unwrapped.override { sdl2Support = false; x11Support = false; waylandSupport = false; }; + mpv-unwrapped = super.mpv-unwrapped.override { drmSupport = false; screenSaverSupport = false; sdl2Support = false; vulkanSupport = false; waylandSupport = false; x11Support = false; }; msmtp = super.msmtp.override { withKeyring = false; }; mupdf = super.mupdf.override { enableGL = false; enableX11 = false; }; neofetch = super.neofetch.override { x11Support = false; }; @@ -70,6 +72,7 @@ with lib; networkmanager-vpnc = super.networkmanager-vpnc.override { withGnome = false; }; pango = super.pango.override { x11Support = false; }; pinentry-curses = super.pinentry-curses.override { withLibsecret = false; }; + pinentry-tty = super.pinentry-tty.override { withLibsecret = false; }; pipewire = super.pipewire.override { vulkanSupport = false; x11Support = false; }; pythonPackagesExtensions = super.pythonPackagesExtensions ++ [ (python-final: python-prev: { diff --git a/nixos/modules/config/nsswitch.nix b/nixos/modules/config/nsswitch.nix index c7ba9b8eec6a2..fe0402ee9e666 100644 --- a/nixos/modules/config/nsswitch.nix +++ b/nixos/modules/config/nsswitch.nix @@ -12,7 +12,7 @@ with lib; system.nssModules = mkOption { type = types.listOf types.path; internal = true; - default = []; + default = [ ]; description = '' Search path for NSS (Name Service Switch) modules. This allows several DNS resolution methods to be specified via @@ -35,7 +35,7 @@ with lib; This option only takes effect if nscd is enabled. ''; - default = []; + default = [ ]; }; group = mkOption { @@ -47,7 +47,7 @@ with lib; This option only takes effect if nscd is enabled. ''; - default = []; + default = [ ]; }; shadow = mkOption { @@ -59,7 +59,19 @@ with lib; This option only takes effect if nscd is enabled. ''; - default = []; + default = [ ]; + }; + + sudoers = mkOption { + type = types.listOf types.str; + description = '' + List of sudoers entries to configure in {file}`/etc/nsswitch.conf`. + + Note that "files" is always prepended. + + This option only takes effect if nscd is enabled. + ''; + default = [ ]; }; hosts = mkOption { @@ -71,7 +83,7 @@ with lib; This option only takes effect if nscd is enabled. ''; - default = []; + default = [ ]; }; services = mkOption { @@ -83,7 +95,7 @@ with lib; This option only takes effect if nscd is enabled. ''; - default = []; + default = [ ]; }; }; }; @@ -112,6 +124,7 @@ with lib; passwd: ${concatStringsSep " " config.system.nssDatabases.passwd} group: ${concatStringsSep " " config.system.nssDatabases.group} shadow: ${concatStringsSep " " config.system.nssDatabases.shadow} + sudoers: ${concatStringsSep " " config.system.nssDatabases.sudoers} hosts: ${concatStringsSep " " config.system.nssDatabases.hosts} networks: files @@ -126,6 +139,7 @@ with lib; passwd = mkBefore [ "files" ]; group = mkBefore [ "files" ]; shadow = mkBefore [ "files" ]; + sudoers = mkBefore [ "files" ]; hosts = mkMerge [ (mkOrder 998 [ "files" ]) (mkOrder 1499 [ "dns" ]) diff --git a/nixos/modules/config/xdg/portal.nix b/nixos/modules/config/xdg/portal.nix index 2c4d07c4953cb..2368ca04a49ea 100644 --- a/nixos/modules/config/xdg/portal.nix +++ b/nixos/modules/config/xdg/portal.nix @@ -96,7 +96,7 @@ in Sets which portal backend should be used to provide the implementation for the requested interface. For details check {manpage}`portals.conf(5)`. - Configs will be linked to `/etx/xdg/xdg-desktop-portal/` with the name `$desktop-portals.conf` + Configs will be linked to `/etc/xdg/xdg-desktop-portal/` with the name `$desktop-portals.conf` for `xdg.portal.config.$desktop` and `portals.conf` for `xdg.portal.config.common` as an exception. ''; diff --git a/nixos/modules/hardware/opengl.nix b/nixos/modules/hardware/opengl.nix index 25324fd8b0af9..3ca9deec8961d 100644 --- a/nixos/modules/hardware/opengl.nix +++ b/nixos/modules/hardware/opengl.nix @@ -1,7 +1,5 @@ { config, lib, pkgs, ... }: -with lib; - let cfg = config.hardware.opengl; @@ -25,14 +23,14 @@ in { imports = [ - (mkRenamedOptionModule [ "services" "xserver" "vaapiDrivers" ] [ "hardware" "opengl" "extraPackages" ]) - (mkRemovedOptionModule [ "hardware" "opengl" "s3tcSupport" ] "S3TC support is now always enabled in Mesa.") + (lib.mkRenamedOptionModule [ "services" "xserver" "vaapiDrivers" ] [ "hardware" "opengl" "extraPackages" ]) + (lib.mkRemovedOptionModule [ "hardware" "opengl" "s3tcSupport" ] "S3TC support is now always enabled in Mesa.") ]; options = { hardware.opengl = { - enable = mkOption { + enable = lib.mkOption { description = '' Whether to enable OpenGL drivers. This is needed to enable OpenGL support in X11 systems, as well as for Wayland compositors @@ -42,12 +40,12 @@ in compositor of choice. See services.xserver.enable and programs.sway.enable. ''; - type = types.bool; + type = lib.types.bool; default = false; }; - driSupport = mkOption { - type = types.bool; + driSupport = lib.mkOption { + type = lib.types.bool; default = true; description = '' Whether to enable accelerated OpenGL rendering through the @@ -55,8 +53,8 @@ in ''; }; - driSupport32Bit = mkOption { - type = types.bool; + driSupport32Bit = lib.mkOption { + type = lib.types.bool; default = false; description = '' On 64-bit systems, whether to support Direct Rendering for @@ -66,16 +64,16 @@ in ''; }; - package = mkOption { - type = types.package; + package = lib.mkOption { + type = lib.types.package; internal = true; description = '' The package that provides the OpenGL implementation. ''; }; - package32 = mkOption { - type = types.package; + package32 = lib.mkOption { + type = lib.types.package; internal = true; description = '' The package that provides the 32-bit OpenGL implementation on @@ -84,10 +82,10 @@ in ''; }; - extraPackages = mkOption { - type = types.listOf types.package; + extraPackages = lib.mkOption { + type = lib.types.listOf lib.types.package; default = []; - example = literalExpression "with pkgs; [ intel-media-driver intel-ocl intel-vaapi-driver ]"; + example = lib.literalExpression "with pkgs; [ intel-media-driver intel-ocl intel-vaapi-driver ]"; description = '' Additional packages to add to OpenGL drivers. This can be used to add OpenCL drivers, VA-API/VDPAU drivers etc. @@ -98,10 +96,10 @@ in ''; }; - extraPackages32 = mkOption { - type = types.listOf types.package; + extraPackages32 =lib. mkOption { + type = lib.types.listOf lib.types.package; default = []; - example = literalExpression "with pkgs.pkgsi686Linux; [ intel-media-driver intel-vaapi-driver ]"; + example = lib.literalExpression "with pkgs.pkgsi686Linux; [ intel-media-driver intel-vaapi-driver ]"; description = '' Additional packages to add to 32-bit OpenGL drivers on 64-bit systems. Used when {option}`driSupport32Bit` is set. This can be used to add OpenCL drivers, VA-API/VDPAU drivers etc. @@ -112,8 +110,8 @@ in ''; }; - setLdLibraryPath = mkOption { - type = types.bool; + setLdLibraryPath = lib.mkOption { + type = lib.types.bool; internal = true; default = false; description = '' @@ -128,7 +126,7 @@ in }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [ { assertion = cfg.driSupport32Bit -> pkgs.stdenv.isx86_64; message = "Option driSupport32Bit only makes sense on a 64-bit system."; @@ -138,24 +136,23 @@ in } ]; - systemd.tmpfiles.rules = [ - "L+ /run/opengl-driver - - - - ${package}" - ( + systemd.tmpfiles.settings.opengl = { + "/run/opengl-driver"."L+".argument = toString package; + "/run/opengl-driver-32" = if pkgs.stdenv.isi686 then - "L+ /run/opengl-driver-32 - - - - opengl-driver" + { "L+".argument = "opengl-driver"; } else if cfg.driSupport32Bit then - "L+ /run/opengl-driver-32 - - - - ${package32}" + { "L+".argument = toString package32; } else - "r /run/opengl-driver-32" - ) - ]; + { "r" = {}; }; + }; - environment.sessionVariables.LD_LIBRARY_PATH = mkIf cfg.setLdLibraryPath - ([ "/run/opengl-driver/lib" ] ++ optional cfg.driSupport32Bit "/run/opengl-driver-32/lib"); + environment.sessionVariables.LD_LIBRARY_PATH = lib.mkIf cfg.setLdLibraryPath + ([ "/run/opengl-driver/lib" ] ++ lib.optional cfg.driSupport32Bit "/run/opengl-driver-32/lib"); - hardware.opengl.package = mkDefault pkgs.mesa.drivers; - hardware.opengl.package32 = mkDefault pkgs.pkgsi686Linux.mesa.drivers; + hardware.opengl.package = lib.mkDefault pkgs.mesa.drivers; + hardware.opengl.package32 = lib.mkDefault pkgs.pkgsi686Linux.mesa.drivers; - boot.extraModulePackages = optional (elem "virtualbox" videoDrivers) kernelPackages.virtualboxGuestAdditions; + boot.extraModulePackages = lib.optional (lib.elem "virtualbox" videoDrivers) kernelPackages.virtualboxGuestAdditions; }; } diff --git a/nixos/modules/hardware/printers.nix b/nixos/modules/hardware/printers.nix index de2f84d4831b8..ace900d88586d 100644 --- a/nixos/modules/hardware/printers.nix +++ b/nixos/modules/hardware/printers.nix @@ -13,7 +13,7 @@ let } // optionalAttrs (p.description != null) { D = p.description; } // optionalAttrs (p.ppdOptions != {}) { - o = mapAttrsToList (name: value: "'${name}'='${value}'") p.ppdOptions; + o = mapAttrsToList (name: value: "${name}=${value}") p.ppdOptions; }); in '' ${pkgs.cups}/bin/lpadmin ${args} -E diff --git a/nixos/modules/hardware/video/nvidia.nix b/nixos/modules/hardware/video/nvidia.nix index 37d8e53a2e049..ae5c2aa7a034a 100644 --- a/nixos/modules/hardware/video/nvidia.nix +++ b/nixos/modules/hardware/video/nvidia.nix @@ -3,12 +3,10 @@ lib, pkgs, ... -}: let +}: +let nvidiaEnabled = (lib.elem "nvidia" config.services.xserver.videoDrivers); - nvidia_x11 = - if nvidiaEnabled || cfg.datacenter.enable - then cfg.package - else null; + nvidia_x11 = if nvidiaEnabled || cfg.datacenter.enable then cfg.package else null; cfg = config.hardware.nvidia; @@ -19,8 +17,9 @@ primeEnabled = syncCfg.enable || reverseSyncCfg.enable || offloadCfg.enable; busIDType = lib.types.strMatching "([[:print:]]+[\:\@][0-9]{1,3}\:[0-9]{1,2}\:[0-9])?"; ibtSupport = cfg.open || (nvidia_x11.ibtSupport or false); - settingsFormat = pkgs.formats.keyValue {}; -in { + settingsFormat = pkgs.formats.keyValue { }; +in +{ options = { hardware.nvidia = { datacenter.enable = lib.mkEnableOption '' @@ -29,50 +28,50 @@ in { datacenter.settings = lib.mkOption { type = settingsFormat.type; default = { - LOG_LEVEL=4; - LOG_FILE_NAME="/var/log/fabricmanager.log"; - LOG_APPEND_TO_LOG=1; - LOG_FILE_MAX_SIZE=1024; - LOG_USE_SYSLOG=0; - DAEMONIZE=1; - BIND_INTERFACE_IP="127.0.0.1"; - STARTING_TCP_PORT=16000; - FABRIC_MODE=0; - FABRIC_MODE_RESTART=0; - STATE_FILE_NAME="/var/tmp/fabricmanager.state"; - FM_CMD_BIND_INTERFACE="127.0.0.1"; - FM_CMD_PORT_NUMBER=6666; - FM_STAY_RESIDENT_ON_FAILURES=0; - ACCESS_LINK_FAILURE_MODE=0; - TRUNK_LINK_FAILURE_MODE=0; - NVSWITCH_FAILURE_MODE=0; - ABORT_CUDA_JOBS_ON_FM_EXIT=1; - TOPOLOGY_FILE_PATH="${nvidia_x11.fabricmanager}/share/nvidia-fabricmanager/nvidia/nvswitch"; - DATABASE_PATH="${nvidia_x11.fabricmanager}/share/nvidia-fabricmanager/nvidia/nvswitch"; + LOG_LEVEL = 4; + LOG_FILE_NAME = "/var/log/fabricmanager.log"; + LOG_APPEND_TO_LOG = 1; + LOG_FILE_MAX_SIZE = 1024; + LOG_USE_SYSLOG = 0; + DAEMONIZE = 1; + BIND_INTERFACE_IP = "127.0.0.1"; + STARTING_TCP_PORT = 16000; + FABRIC_MODE = 0; + FABRIC_MODE_RESTART = 0; + STATE_FILE_NAME = "/var/tmp/fabricmanager.state"; + FM_CMD_BIND_INTERFACE = "127.0.0.1"; + FM_CMD_PORT_NUMBER = 6666; + FM_STAY_RESIDENT_ON_FAILURES = 0; + ACCESS_LINK_FAILURE_MODE = 0; + TRUNK_LINK_FAILURE_MODE = 0; + NVSWITCH_FAILURE_MODE = 0; + ABORT_CUDA_JOBS_ON_FM_EXIT = 1; + TOPOLOGY_FILE_PATH = "${nvidia_x11.fabricmanager}/share/nvidia-fabricmanager/nvidia/nvswitch"; + DATABASE_PATH = "${nvidia_x11.fabricmanager}/share/nvidia-fabricmanager/nvidia/nvswitch"; }; defaultText = lib.literalExpression '' - { - LOG_LEVEL=4; - LOG_FILE_NAME="/var/log/fabricmanager.log"; - LOG_APPEND_TO_LOG=1; - LOG_FILE_MAX_SIZE=1024; - LOG_USE_SYSLOG=0; - DAEMONIZE=1; - BIND_INTERFACE_IP="127.0.0.1"; - STARTING_TCP_PORT=16000; - FABRIC_MODE=0; - FABRIC_MODE_RESTART=0; - STATE_FILE_NAME="/var/tmp/fabricmanager.state"; - FM_CMD_BIND_INTERFACE="127.0.0.1"; - FM_CMD_PORT_NUMBER=6666; - FM_STAY_RESIDENT_ON_FAILURES=0; - ACCESS_LINK_FAILURE_MODE=0; - TRUNK_LINK_FAILURE_MODE=0; - NVSWITCH_FAILURE_MODE=0; - ABORT_CUDA_JOBS_ON_FM_EXIT=1; - TOPOLOGY_FILE_PATH="''${nvidia_x11.fabricmanager}/share/nvidia-fabricmanager/nvidia/nvswitch"; - DATABASE_PATH="''${nvidia_x11.fabricmanager}/share/nvidia-fabricmanager/nvidia/nvswitch"; - } + { + LOG_LEVEL=4; + LOG_FILE_NAME="/var/log/fabricmanager.log"; + LOG_APPEND_TO_LOG=1; + LOG_FILE_MAX_SIZE=1024; + LOG_USE_SYSLOG=0; + DAEMONIZE=1; + BIND_INTERFACE_IP="127.0.0.1"; + STARTING_TCP_PORT=16000; + FABRIC_MODE=0; + FABRIC_MODE_RESTART=0; + STATE_FILE_NAME="/var/tmp/fabricmanager.state"; + FM_CMD_BIND_INTERFACE="127.0.0.1"; + FM_CMD_PORT_NUMBER=6666; + FM_STAY_RESIDENT_ON_FAILURES=0; + ACCESS_LINK_FAILURE_MODE=0; + TRUNK_LINK_FAILURE_MODE=0; + NVSWITCH_FAILURE_MODE=0; + ABORT_CUDA_JOBS_ON_FM_EXIT=1; + TOPOLOGY_FILE_PATH="''${nvidia_x11.fabricmanager}/share/nvidia-fabricmanager/nvidia/nvswitch"; + DATABASE_PATH="''${nvidia_x11.fabricmanager}/share/nvidia-fabricmanager/nvidia/nvswitch"; + } ''; description = '' Additional configuration options for fabricmanager. @@ -207,11 +206,26 @@ in { option is supported is used ''; + prime.reverseSync.setupCommands.enable = + (lib.mkEnableOption '' + configure the display manager to be able to use the outputs + attached to the NVIDIA GPU. + Disable in order to configure the NVIDIA GPU outputs manually using xrandr. + Note that this configuration will only be successful when a display manager + for which the {option}`services.xserver.displayManager.setupCommands` + option is supported is used + '') + // { + default = true; + }; + nvidiaSettings = (lib.mkEnableOption '' nvidia-settings, NVIDIA's GUI configuration tool '') - // {default = true;}; + // { + default = true; + }; nvidiaPersistenced = lib.mkEnableOption '' nvidia-persistenced a update for NVIDIA GPU headless mode, i.e. @@ -226,7 +240,8 @@ in { ''; package = lib.mkOption { - default = config.boot.kernelPackages.nvidiaPackages."${if cfg.datacenter.enable then "dc" else "stable"}"; + default = + config.boot.kernelPackages.nvidiaPackages."${if cfg.datacenter.enable then "dc" else "stable"}"; defaultText = lib.literalExpression '' config.boot.kernelPackages.nvidiaPackages."\$\{if cfg.datacenter.enable then "dc" else "stable"}" ''; @@ -242,403 +257,404 @@ in { }; }; - config = let - igpuDriver = - if pCfg.intelBusId != "" - then "modesetting" - else "amdgpu"; - igpuBusId = - if pCfg.intelBusId != "" - then pCfg.intelBusId - else pCfg.amdgpuBusId; - in - lib.mkIf (nvidia_x11 != null) (lib.mkMerge [ - # Common - ({ - assertions = [ - { - assertion = !(nvidiaEnabled && cfg.datacenter.enable); - message = "You cannot configure both X11 and Data Center drivers at the same time."; - } - ]; - boot = { - blacklistedKernelModules = ["nouveau" "nvidiafb"]; - - # Don't add `nvidia-uvm` to `kernelModules`, because we want - # `nvidia-uvm` be loaded only after `udev` rules for `nvidia` kernel - # module are applied. - # - # Instead, we use `softdep` to lazily load `nvidia-uvm` kernel module - # after `nvidia` kernel module is loaded and `udev` rules are applied. - extraModprobeConfig = '' - softdep nvidia post: nvidia-uvm - ''; - }; - systemd.tmpfiles.rules = - lib.optional config.virtualisation.docker.enableNvidia - "L+ /run/nvidia-docker/bin - - - - ${nvidia_x11.bin}/origBin"; - services.udev.extraRules = - '' - # Create /dev/nvidia-uvm when the nvidia-uvm module is loaded. - KERNEL=="nvidia", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidiactl c 195 255'" - KERNEL=="nvidia", RUN+="${pkgs.runtimeShell} -c 'for i in $$(cat /proc/driver/nvidia/gpus/*/information | grep Minor | cut -d \ -f 4); do mknod -m 666 /dev/nvidia$${i} c 195 $${i}; done'" - KERNEL=="nvidia_modeset", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidia-modeset c 195 254'" - KERNEL=="nvidia_uvm", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidia-uvm c $$(grep nvidia-uvm /proc/devices | cut -d \ -f 1) 0'" - KERNEL=="nvidia_uvm", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidia-uvm-tools c $$(grep nvidia-uvm /proc/devices | cut -d \ -f 1) 1'" - ''; - hardware.opengl = { - extraPackages = [ - nvidia_x11.out + config = + let + igpuDriver = if pCfg.intelBusId != "" then "modesetting" else "amdgpu"; + igpuBusId = if pCfg.intelBusId != "" then pCfg.intelBusId else pCfg.amdgpuBusId; + in + lib.mkIf (nvidia_x11 != null) ( + lib.mkMerge [ + # Common + ({ + assertions = [ + { + assertion = !(nvidiaEnabled && cfg.datacenter.enable); + message = "You cannot configure both X11 and Data Center drivers at the same time."; + } ]; - extraPackages32 = [ - nvidia_x11.lib32 + boot = { + blacklistedKernelModules = [ + "nouveau" + "nvidiafb" + ]; + + # Don't add `nvidia-uvm` to `kernelModules`, because we want + # `nvidia-uvm` be loaded only after `udev` rules for `nvidia` kernel + # module are applied. + # + # Instead, we use `softdep` to lazily load `nvidia-uvm` kernel module + # after `nvidia` kernel module is loaded and `udev` rules are applied. + extraModprobeConfig = '' + softdep nvidia post: nvidia-uvm + ''; + }; + systemd.tmpfiles.rules = lib.mkIf config.virtualisation.docker.enableNvidia [ "L+ /run/nvidia-docker/bin - - - - ${nvidia_x11.bin}/origBin" ]; + services.udev.extraRules = '' + # Create /dev/nvidia-uvm when the nvidia-uvm module is loaded. + KERNEL=="nvidia", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidiactl c 195 255'" + KERNEL=="nvidia", RUN+="${pkgs.runtimeShell} -c 'for i in $$(cat /proc/driver/nvidia/gpus/*/information | grep Minor | cut -d \ -f 4); do mknod -m 666 /dev/nvidia$${i} c 195 $${i}; done'" + KERNEL=="nvidia_modeset", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidia-modeset c 195 254'" + KERNEL=="nvidia_uvm", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidia-uvm c $$(grep nvidia-uvm /proc/devices | cut -d \ -f 1) 0'" + KERNEL=="nvidia_uvm", RUN+="${pkgs.runtimeShell} -c 'mknod -m 666 /dev/nvidia-uvm-tools c $$(grep nvidia-uvm /proc/devices | cut -d \ -f 1) 1'" + ''; + hardware.opengl = { + extraPackages = [ nvidia_x11.out ]; + extraPackages32 = [ nvidia_x11.lib32 ]; + }; + environment.systemPackages = [ nvidia_x11.bin ]; + }) + + # X11 + (lib.mkIf nvidiaEnabled { + assertions = [ + { + assertion = primeEnabled -> pCfg.intelBusId == "" || pCfg.amdgpuBusId == ""; + message = "You cannot configure both an Intel iGPU and an AMD APU. Pick the one corresponding to your processor."; + } + + { + assertion = offloadCfg.enableOffloadCmd -> offloadCfg.enable || reverseSyncCfg.enable; + message = "Offload command requires offloading or reverse prime sync to be enabled."; + } + + { + assertion = + primeEnabled -> pCfg.nvidiaBusId != "" && (pCfg.intelBusId != "" || pCfg.amdgpuBusId != ""); + message = "When NVIDIA PRIME is enabled, the GPU bus IDs must be configured."; + } + + { + assertion = offloadCfg.enable -> lib.versionAtLeast nvidia_x11.version "435.21"; + message = "NVIDIA PRIME render offload is currently only supported on versions >= 435.21."; + } + + { + assertion = + (reverseSyncCfg.enable && pCfg.amdgpuBusId != "") -> lib.versionAtLeast nvidia_x11.version "470.0"; + message = "NVIDIA PRIME render offload for AMD APUs is currently only supported on versions >= 470 beta."; + } + + { + assertion = !(syncCfg.enable && offloadCfg.enable); + message = "PRIME Sync and Offload cannot be both enabled"; + } + + { + assertion = !(syncCfg.enable && reverseSyncCfg.enable); + message = "PRIME Sync and PRIME Reverse Sync cannot be both enabled"; + } + + { + assertion = !(syncCfg.enable && cfg.powerManagement.finegrained); + message = "Sync precludes powering down the NVIDIA GPU."; + } + + { + assertion = cfg.powerManagement.finegrained -> offloadCfg.enable; + message = "Fine-grained power management requires offload to be enabled."; + } + + { + assertion = cfg.powerManagement.enable -> lib.versionAtLeast nvidia_x11.version "430.09"; + message = "Required files for driver based power management only exist on versions >= 430.09."; + } + + { + assertion = cfg.open -> (cfg.package ? open && cfg.package ? firmware); + message = "This version of NVIDIA driver does not provide a corresponding opensource kernel driver"; + } + + { + assertion = cfg.dynamicBoost.enable -> lib.versionAtLeast nvidia_x11.version "510.39.01"; + message = "NVIDIA's Dynamic Boost feature only exists on versions >= 510.39.01"; + } ]; - }; - environment.systemPackages = [ - nvidia_x11.bin - ]; - }) - # X11 - (lib.mkIf nvidiaEnabled { - assertions = [ - { - assertion = primeEnabled -> pCfg.intelBusId == "" || pCfg.amdgpuBusId == ""; - message = "You cannot configure both an Intel iGPU and an AMD APU. Pick the one corresponding to your processor."; - } - - { - assertion = offloadCfg.enableOffloadCmd -> offloadCfg.enable || reverseSyncCfg.enable; - message = "Offload command requires offloading or reverse prime sync to be enabled."; - } - - { - assertion = primeEnabled -> pCfg.nvidiaBusId != "" && (pCfg.intelBusId != "" || pCfg.amdgpuBusId != ""); - message = "When NVIDIA PRIME is enabled, the GPU bus IDs must be configured."; - } - - { - assertion = offloadCfg.enable -> lib.versionAtLeast nvidia_x11.version "435.21"; - message = "NVIDIA PRIME render offload is currently only supported on versions >= 435.21."; - } - - { - assertion = (reverseSyncCfg.enable && pCfg.amdgpuBusId != "") -> lib.versionAtLeast nvidia_x11.version "470.0"; - message = "NVIDIA PRIME render offload for AMD APUs is currently only supported on versions >= 470 beta."; - } - - { - assertion = !(syncCfg.enable && offloadCfg.enable); - message = "PRIME Sync and Offload cannot be both enabled"; - } - - { - assertion = !(syncCfg.enable && reverseSyncCfg.enable); - message = "PRIME Sync and PRIME Reverse Sync cannot be both enabled"; - } - - { - assertion = !(syncCfg.enable && cfg.powerManagement.finegrained); - message = "Sync precludes powering down the NVIDIA GPU."; - } - - { - assertion = cfg.powerManagement.finegrained -> offloadCfg.enable; - message = "Fine-grained power management requires offload to be enabled."; - } - - { - assertion = cfg.powerManagement.enable -> lib.versionAtLeast nvidia_x11.version "430.09"; - message = "Required files for driver based power management only exist on versions >= 430.09."; - } - - { - assertion = cfg.open -> (cfg.package ? open && cfg.package ? firmware); - message = "This version of NVIDIA driver does not provide a corresponding opensource kernel driver"; - } - - { - assertion = cfg.dynamicBoost.enable -> lib.versionAtLeast nvidia_x11.version "510.39.01"; - message = "NVIDIA's Dynamic Boost feature only exists on versions >= 510.39.01"; - }]; - - # If Optimus/PRIME is enabled, we: - # - Specify the configured NVIDIA GPU bus ID in the Device section for the - # "nvidia" driver. - # - Add the AllowEmptyInitialConfiguration option to the Screen section for the - # "nvidia" driver, in order to allow the X server to start without any outputs. - # - Add a separate Device section for the Intel GPU, using the "modesetting" - # driver and with the configured BusID. - # - OR add a separate Device section for the AMD APU, using the "amdgpu" - # driver and with the configures BusID. - # - Reference that Device section from the ServerLayout section as an inactive - # device. - # - Configure the display manager to run specific `xrandr` commands which will - # configure/enable displays connected to the Intel iGPU / AMD APU. - - # reverse sync implies offloading - hardware.nvidia.prime.offload.enable = lib.mkDefault reverseSyncCfg.enable; - - services.xserver.drivers = - lib.optional primeEnabled { - name = igpuDriver; - display = offloadCfg.enable; - modules = lib.optional (igpuDriver == "amdgpu") pkgs.xorg.xf86videoamdgpu; - deviceSection = - '' - BusID "${igpuBusId}" - '' - + lib.optionalString (syncCfg.enable && igpuDriver != "amdgpu") '' - Option "AccelMethod" "none" - ''; - } - ++ lib.singleton { - name = "nvidia"; - modules = [nvidia_x11.bin]; - display = !offloadCfg.enable; - deviceSection = - '' - Option "SidebandSocketPath" "/run/nvidia-xdriver/" - '' + - lib.optionalString primeEnabled - '' - BusID "${pCfg.nvidiaBusId}" - '' - + lib.optionalString pCfg.allowExternalGpu '' - Option "AllowExternalGpus" - ''; - screenSection = - '' - Option "RandRRotation" "on" - '' - + lib.optionalString syncCfg.enable '' - Option "AllowEmptyInitialConfiguration" + + # If Optimus/PRIME is enabled, we: + # - Specify the configured NVIDIA GPU bus ID in the Device section for the + # "nvidia" driver. + # - Add the AllowEmptyInitialConfiguration option to the Screen section for the + # "nvidia" driver, in order to allow the X server to start without any outputs. + # - Add a separate Device section for the Intel GPU, using the "modesetting" + # driver and with the configured BusID. + # - OR add a separate Device section for the AMD APU, using the "amdgpu" + # driver and with the configures BusID. + # - Reference that Device section from the ServerLayout section as an inactive + # device. + # - Configure the display manager to run specific `xrandr` commands which will + # configure/enable displays connected to the Intel iGPU / AMD APU. + + # reverse sync implies offloading + hardware.nvidia.prime.offload.enable = lib.mkDefault reverseSyncCfg.enable; + + services.xserver.drivers = + lib.optional primeEnabled { + name = igpuDriver; + display = offloadCfg.enable; + modules = lib.optional (igpuDriver == "amdgpu") pkgs.xorg.xf86videoamdgpu; + deviceSection = + '' + BusID "${igpuBusId}" + '' + + lib.optionalString (syncCfg.enable && igpuDriver != "amdgpu") '' + Option "AccelMethod" "none" + ''; + } + ++ lib.singleton { + name = "nvidia"; + modules = [ nvidia_x11.bin ]; + display = !offloadCfg.enable; + deviceSection = + '' + Option "SidebandSocketPath" "/run/nvidia-xdriver/" + '' + + lib.optionalString primeEnabled '' + BusID "${pCfg.nvidiaBusId}" + '' + + lib.optionalString pCfg.allowExternalGpu '' + Option "AllowExternalGpus" + ''; + screenSection = + '' + Option "RandRRotation" "on" + '' + + lib.optionalString syncCfg.enable '' + Option "AllowEmptyInitialConfiguration" + '' + + lib.optionalString cfg.forceFullCompositionPipeline '' + Option "metamodes" "nvidia-auto-select +0+0 {ForceFullCompositionPipeline=On}" + Option "AllowIndirectGLXProtocol" "off" + Option "TripleBuffer" "on" + ''; + }; + + services.xserver.serverLayoutSection = + lib.optionalString syncCfg.enable '' + Inactive "Device-${igpuDriver}[0]" + '' + + lib.optionalString reverseSyncCfg.enable '' + Inactive "Device-nvidia[0]" + '' + + lib.optionalString offloadCfg.enable '' + Option "AllowNVIDIAGPUScreens" + ''; + + services.xserver.displayManager.setupCommands = + let + gpuProviderName = + if igpuDriver == "amdgpu" then + # find the name of the provider if amdgpu + "`${lib.getExe pkgs.xorg.xrandr} --listproviders | ${lib.getExe pkgs.gnugrep} -i AMD | ${lib.getExe pkgs.gnused} -n 's/^.*name://p'`" + else + igpuDriver; + providerCmdParams = + if syncCfg.enable then "\"${gpuProviderName}\" NVIDIA-0" else "NVIDIA-G0 \"${gpuProviderName}\""; + in + lib.optionalString + (syncCfg.enable || (reverseSyncCfg.enable && reverseSyncCfg.setupCommands.enable)) '' - + lib.optionalString cfg.forceFullCompositionPipeline '' - Option "metamodes" "nvidia-auto-select +0+0 {ForceFullCompositionPipeline=On}" - Option "AllowIndirectGLXProtocol" "off" - Option "TripleBuffer" "on" + # Added by nvidia configuration module for Optimus/PRIME. + ${lib.getExe pkgs.xorg.xrandr} --setprovideroutputsource ${providerCmdParams} + ${lib.getExe pkgs.xorg.xrandr} --auto ''; - }; - services.xserver.serverLayoutSection = - lib.optionalString syncCfg.enable '' - Inactive "Device-${igpuDriver}[0]" - '' - + lib.optionalString reverseSyncCfg.enable '' - Inactive "Device-nvidia[0]" - '' - + lib.optionalString offloadCfg.enable '' - Option "AllowNVIDIAGPUScreens" - ''; + environment.etc = { + "nvidia/nvidia-application-profiles-rc" = lib.mkIf nvidia_x11.useProfiles { + source = "${nvidia_x11.bin}/share/nvidia/nvidia-application-profiles-rc"; + }; - services.xserver.displayManager.setupCommands = let - gpuProviderName = - if igpuDriver == "amdgpu" - then - # find the name of the provider if amdgpu - "`${lib.getExe pkgs.xorg.xrandr} --listproviders | ${lib.getExe pkgs.gnugrep} -i AMD | ${lib.getExe pkgs.gnused} -n 's/^.*name://p'`" - else igpuDriver; - providerCmdParams = - if syncCfg.enable - then "\"${gpuProviderName}\" NVIDIA-0" - else "NVIDIA-G0 \"${gpuProviderName}\""; - in - lib.optionalString (syncCfg.enable || reverseSyncCfg.enable) '' - # Added by nvidia configuration module for Optimus/PRIME. - ${lib.getExe pkgs.xorg.xrandr} --setprovideroutputsource ${providerCmdParams} - ${lib.getExe pkgs.xorg.xrandr} --auto - ''; + # 'nvidia_x11' installs it's files to /run/opengl-driver/... + "egl/egl_external_platform.d".source = "/run/opengl-driver/share/egl/egl_external_platform.d/"; + }; - environment.etc = { - "nvidia/nvidia-application-profiles-rc" = lib.mkIf nvidia_x11.useProfiles {source = "${nvidia_x11.bin}/share/nvidia/nvidia-application-profiles-rc";}; + hardware.opengl = { + extraPackages = [ pkgs.nvidia-vaapi-driver ]; + extraPackages32 = [ pkgs.pkgsi686Linux.nvidia-vaapi-driver ]; + }; - # 'nvidia_x11' installs it's files to /run/opengl-driver/... - "egl/egl_external_platform.d".source = "/run/opengl-driver/share/egl/egl_external_platform.d/"; - }; + environment.systemPackages = + lib.optional cfg.nvidiaSettings nvidia_x11.settings + ++ lib.optional cfg.nvidiaPersistenced nvidia_x11.persistenced + ++ lib.optional offloadCfg.enableOffloadCmd ( + pkgs.writeShellScriptBin "nvidia-offload" '' + export __NV_PRIME_RENDER_OFFLOAD=1 + export __NV_PRIME_RENDER_OFFLOAD_PROVIDER=NVIDIA-G0 + export __GLX_VENDOR_LIBRARY_NAME=nvidia + export __VK_LAYER_NV_optimus=NVIDIA_only + exec "$@" + '' + ); - hardware.opengl = { - extraPackages = [ - pkgs.nvidia-vaapi-driver - ]; - extraPackages32 = [ - pkgs.pkgsi686Linux.nvidia-vaapi-driver - ]; - }; - environment.systemPackages = - lib.optional cfg.nvidiaSettings nvidia_x11.settings - ++ lib.optional cfg.nvidiaPersistenced nvidia_x11.persistenced - ++ lib.optional offloadCfg.enableOffloadCmd - (pkgs.writeShellScriptBin "nvidia-offload" '' - export __NV_PRIME_RENDER_OFFLOAD=1 - export __NV_PRIME_RENDER_OFFLOAD_PROVIDER=NVIDIA-G0 - export __GLX_VENDOR_LIBRARY_NAME=nvidia - export __VK_LAYER_NV_optimus=NVIDIA_only - exec "$@" - ''); - - systemd.packages = lib.optional cfg.powerManagement.enable nvidia_x11.out; - - systemd.services = let - nvidiaService = state: { - description = "NVIDIA system ${state} actions"; - path = [pkgs.kbd]; - serviceConfig = { - Type = "oneshot"; - ExecStart = "${nvidia_x11.out}/bin/nvidia-sleep.sh '${state}'"; - }; - before = ["systemd-${state}.service"]; - requiredBy = ["systemd-${state}.service"]; - }; - in - lib.mkMerge [ - (lib.mkIf cfg.powerManagement.enable { - nvidia-suspend = nvidiaService "suspend"; - nvidia-hibernate = nvidiaService "hibernate"; - nvidia-resume = - (nvidiaService "resume") - // { - before = []; - after = ["systemd-suspend.service" "systemd-hibernate.service"]; - requiredBy = ["systemd-suspend.service" "systemd-hibernate.service"]; - }; - }) - (lib.mkIf cfg.nvidiaPersistenced { - "nvidia-persistenced" = { - description = "NVIDIA Persistence Daemon"; - wantedBy = ["multi-user.target"]; + systemd.packages = lib.optional cfg.powerManagement.enable nvidia_x11.out; + + systemd.services = + let + nvidiaService = state: { + description = "NVIDIA system ${state} actions"; + path = [ pkgs.kbd ]; serviceConfig = { - Type = "forking"; - Restart = "always"; - PIDFile = "/var/run/nvidia-persistenced/nvidia-persistenced.pid"; - ExecStart = "${lib.getExe nvidia_x11.persistenced} --verbose"; - ExecStopPost = "${pkgs.coreutils}/bin/rm -rf /var/run/nvidia-persistenced"; + Type = "oneshot"; + ExecStart = "${nvidia_x11.out}/bin/nvidia-sleep.sh '${state}'"; }; + before = [ "systemd-${state}.service" ]; + requiredBy = [ "systemd-${state}.service" ]; }; - }) - (lib.mkIf cfg.dynamicBoost.enable { - "nvidia-powerd" = { - description = "nvidia-powerd service"; - path = [ - pkgs.util-linux # nvidia-powerd wants lscpu - ]; - wantedBy = ["multi-user.target"]; - serviceConfig = { - Type = "dbus"; - BusName = "nvidia.powerd.server"; - ExecStart = "${nvidia_x11.bin}/bin/nvidia-powerd"; + in + lib.mkMerge [ + (lib.mkIf cfg.powerManagement.enable { + nvidia-suspend = nvidiaService "suspend"; + nvidia-hibernate = nvidiaService "hibernate"; + nvidia-resume = (nvidiaService "resume") // { + before = [ ]; + after = [ + "systemd-suspend.service" + "systemd-hibernate.service" + ]; + requiredBy = [ + "systemd-suspend.service" + "systemd-hibernate.service" + ]; }; - }; - }) - ]; - services.acpid.enable = true; - - services.dbus.packages = lib.optional cfg.dynamicBoost.enable nvidia_x11.bin; - - hardware.firmware = lib.optional cfg.open nvidia_x11.firmware; - - systemd.tmpfiles.rules = [ - # Remove the following log message: - # (WW) NVIDIA: Failed to bind sideband socket to - # (WW) NVIDIA: '/var/run/nvidia-xdriver-b4f69129' Permission denied - # - # https://bbs.archlinux.org/viewtopic.php?pid=1909115#p1909115 - "d /run/nvidia-xdriver 0770 root users" - ] ++ lib.optional (nvidia_x11.persistenced != null && config.virtualisation.docker.enableNvidia) - "L+ /run/nvidia-docker/extras/bin/nvidia-persistenced - - - - ${nvidia_x11.persistenced}/origBin/nvidia-persistenced"; - - boot = { - extraModulePackages = - if cfg.open - then [nvidia_x11.open] - else [nvidia_x11.bin]; - # nvidia-uvm is required by CUDA applications. - kernelModules = - lib.optionals config.services.xserver.enable ["nvidia" "nvidia_modeset" "nvidia_drm"]; - - # If requested enable modesetting via kernel parameter. - kernelParams = - lib.optional (offloadCfg.enable || cfg.modesetting.enable) "nvidia-drm.modeset=1" - ++ lib.optional cfg.powerManagement.enable "nvidia.NVreg_PreserveVideoMemoryAllocations=1" - ++ lib.optional cfg.open "nvidia.NVreg_OpenRmEnableUnsupportedGpus=1" - ++ lib.optional (config.boot.kernelPackages.kernel.kernelAtLeast "6.2" && !ibtSupport) "ibt=off"; - - # enable finegrained power management - extraModprobeConfig = lib.optionalString cfg.powerManagement.finegrained '' - options nvidia "NVreg_DynamicPowerManagement=0x02" - ''; - }; - services.udev.extraRules = - lib.optionalString cfg.powerManagement.finegrained ( - lib.optionalString (lib.versionOlder config.boot.kernelPackages.kernel.version "5.5") '' - # Remove NVIDIA USB xHCI Host Controller devices, if present - ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c0330", ATTR{remove}="1" - - # Remove NVIDIA USB Type-C UCSI devices, if present - ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c8000", ATTR{remove}="1" - - # Remove NVIDIA Audio devices, if present - ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x040300", ATTR{remove}="1" - '' - + '' - # Enable runtime PM for NVIDIA VGA/3D controller devices on driver bind - ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="auto" - ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="auto" - - # Disable runtime PM for NVIDIA VGA/3D controller devices on driver unbind - ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="on" - ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="on" - '' - ); - }) - # Data Center - (lib.mkIf (cfg.datacenter.enable) { - boot.extraModulePackages = [ - nvidia_x11.bin - ]; - - systemd = { - tmpfiles.rules = - lib.optional (nvidia_x11.persistenced != null && config.virtualisation.docker.enableNvidia) - "L+ /run/nvidia-docker/extras/bin/nvidia-persistenced - - - - ${nvidia_x11.persistenced}/origBin/nvidia-persistenced"; - - services = lib.mkMerge [ - ({ - nvidia-fabricmanager = { - enable = true; - description = "Start NVIDIA NVLink Management"; - wantedBy = [ "multi-user.target" ]; - unitConfig.After = [ "network-online.target" ]; - unitConfig.Requires = [ "network-online.target" ]; - serviceConfig = { - Type = "forking"; - TimeoutStartSec = 240; - ExecStart = let - nv-fab-conf = settingsFormat.generate "fabricmanager.conf" cfg.datacenter.settings; - in + }) + (lib.mkIf cfg.nvidiaPersistenced { + "nvidia-persistenced" = { + description = "NVIDIA Persistence Daemon"; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "forking"; + Restart = "always"; + PIDFile = "/var/run/nvidia-persistenced/nvidia-persistenced.pid"; + ExecStart = "${lib.getExe nvidia_x11.persistenced} --verbose"; + ExecStopPost = "${pkgs.coreutils}/bin/rm -rf /var/run/nvidia-persistenced"; + }; + }; + }) + (lib.mkIf cfg.dynamicBoost.enable { + "nvidia-powerd" = { + description = "nvidia-powerd service"; + path = [ + pkgs.util-linux # nvidia-powerd wants lscpu + ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "dbus"; + BusName = "nvidia.powerd.server"; + ExecStart = "${nvidia_x11.bin}/bin/nvidia-powerd"; + }; + }; + }) + ]; + + services.acpid.enable = true; + + services.dbus.packages = lib.optional cfg.dynamicBoost.enable nvidia_x11.bin; + + hardware.firmware = lib.optional (cfg.open || lib.versionAtLeast nvidia_x11.version "555") nvidia_x11.firmware; + + systemd.tmpfiles.rules = + [ + # Remove the following log message: + # (WW) NVIDIA: Failed to bind sideband socket to + # (WW) NVIDIA: '/var/run/nvidia-xdriver-b4f69129' Permission denied + # + # https://bbs.archlinux.org/viewtopic.php?pid=1909115#p1909115 + "d /run/nvidia-xdriver 0770 root users" + ] + ++ lib.optional (nvidia_x11.persistenced != null && config.virtualisation.docker.enableNvidia) + "L+ /run/nvidia-docker/extras/bin/nvidia-persistenced - - - - ${nvidia_x11.persistenced}/origBin/nvidia-persistenced"; + + boot = { + extraModulePackages = if cfg.open then [ nvidia_x11.open ] else [ nvidia_x11.bin ]; + # nvidia-uvm is required by CUDA applications. + kernelModules = lib.optionals config.services.xserver.enable [ + "nvidia" + "nvidia_modeset" + "nvidia_drm" + ]; + + # If requested enable modesetting via kernel parameter. + kernelParams = + lib.optional (offloadCfg.enable || cfg.modesetting.enable) "nvidia-drm.modeset=1" + ++ lib.optional cfg.powerManagement.enable "nvidia.NVreg_PreserveVideoMemoryAllocations=1" + ++ lib.optional cfg.open "nvidia.NVreg_OpenRmEnableUnsupportedGpus=1" + ++ lib.optional (config.boot.kernelPackages.kernel.kernelAtLeast "6.2" && !ibtSupport) "ibt=off"; + + # enable finegrained power management + extraModprobeConfig = lib.optionalString cfg.powerManagement.finegrained '' + options nvidia "NVreg_DynamicPowerManagement=0x02" + ''; + }; + services.udev.extraRules = lib.optionalString cfg.powerManagement.finegrained ( + lib.optionalString (lib.versionOlder config.boot.kernelPackages.kernel.version "5.5") '' + # Remove NVIDIA USB xHCI Host Controller devices, if present + ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c0330", ATTR{remove}="1" + + # Remove NVIDIA USB Type-C UCSI devices, if present + ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c8000", ATTR{remove}="1" + + # Remove NVIDIA Audio devices, if present + ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x040300", ATTR{remove}="1" + '' + + '' + # Enable runtime PM for NVIDIA VGA/3D controller devices on driver bind + ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="auto" + ACTION=="bind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="auto" + + # Disable runtime PM for NVIDIA VGA/3D controller devices on driver unbind + ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030000", TEST=="power/control", ATTR{power/control}="on" + ACTION=="unbind", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x030200", TEST=="power/control", ATTR{power/control}="on" + '' + ); + }) + # Data Center + (lib.mkIf (cfg.datacenter.enable) { + boot.extraModulePackages = [ nvidia_x11.bin ]; + + systemd = { + tmpfiles.rules = + lib.optional (nvidia_x11.persistenced != null && config.virtualisation.docker.enableNvidia) + "L+ /run/nvidia-docker/extras/bin/nvidia-persistenced - - - - ${nvidia_x11.persistenced}/origBin/nvidia-persistenced"; + + services = lib.mkMerge [ + ({ + nvidia-fabricmanager = { + enable = true; + description = "Start NVIDIA NVLink Management"; + wantedBy = [ "multi-user.target" ]; + unitConfig.After = [ "network-online.target" ]; + unitConfig.Requires = [ "network-online.target" ]; + serviceConfig = { + Type = "forking"; + TimeoutStartSec = 240; + ExecStart = + let + nv-fab-conf = settingsFormat.generate "fabricmanager.conf" cfg.datacenter.settings; + in "${lib.getExe nvidia_x11.fabricmanager} -c ${nv-fab-conf}"; - LimitCORE="infinity"; + LimitCORE = "infinity"; + }; }; - }; - }) - (lib.mkIf cfg.nvidiaPersistenced { - "nvidia-persistenced" = { - description = "NVIDIA Persistence Daemon"; - wantedBy = ["multi-user.target"]; - serviceConfig = { - Type = "forking"; - Restart = "always"; - PIDFile = "/var/run/nvidia-persistenced/nvidia-persistenced.pid"; - ExecStart = "${lib.getExe nvidia_x11.persistenced} --verbose"; - ExecStopPost = "${pkgs.coreutils}/bin/rm -rf /var/run/nvidia-persistenced"; + }) + (lib.mkIf cfg.nvidiaPersistenced { + "nvidia-persistenced" = { + description = "NVIDIA Persistence Daemon"; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "forking"; + Restart = "always"; + PIDFile = "/var/run/nvidia-persistenced/nvidia-persistenced.pid"; + ExecStart = "${lib.getExe nvidia_x11.persistenced} --verbose"; + ExecStopPost = "${pkgs.coreutils}/bin/rm -rf /var/run/nvidia-persistenced"; + }; }; - }; - }) - ]; - }; + }) + ]; + }; - environment.systemPackages = - lib.optional cfg.datacenter.enable nvidia_x11.fabricmanager - ++ lib.optional cfg.nvidiaPersistenced nvidia_x11.persistenced; - }) - ]); + environment.systemPackages = + lib.optional cfg.datacenter.enable nvidia_x11.fabricmanager + ++ lib.optional cfg.nvidiaPersistenced nvidia_x11.persistenced; + }) + ] + ); } diff --git a/nixos/modules/hardware/xone.nix b/nixos/modules/hardware/xone.nix index 89690d8c6fb10..bb3b42399d8e1 100644 --- a/nixos/modules/hardware/xone.nix +++ b/nixos/modules/hardware/xone.nix @@ -6,7 +6,7 @@ let in { options.hardware.xone = { - enable = mkEnableOption "the xone driver for Xbox One and Xbobx Series X|S accessories"; + enable = mkEnableOption "the xone driver for Xbox One and Xbox Series X|S accessories"; }; config = mkIf cfg.enable { diff --git a/nixos/modules/image/repart-image.nix b/nixos/modules/image/repart-image.nix index 59d5fc26efe9b..e404067299004 100644 --- a/nixos/modules/image/repart-image.nix +++ b/nixos/modules/image/repart-image.nix @@ -10,7 +10,6 @@ , mypy , systemd , fakeroot -, util-linux # filesystem tools , dosfstools @@ -105,7 +104,6 @@ in nativeBuildInputs = [ systemd fakeroot - util-linux ] ++ lib.optionals (compression.enable) [ compressionPkg ] ++ fileSystemTools; @@ -148,7 +146,7 @@ in runHook preBuild echo "Building image with systemd-repart..." - unshare --map-root-user fakeroot systemd-repart \ + fakeroot systemd-repart \ ''${systemdRepartFlags[@]} \ ${imageFileBasename}.raw \ | tee repart-output.json diff --git a/nixos/modules/installer/cd-dvd/installation-cd-graphical-calamares-plasma5.nix b/nixos/modules/installer/cd-dvd/installation-cd-graphical-calamares-plasma5.nix index 61e94ffed8894..d1a42fc7a713b 100644 --- a/nixos/modules/installer/cd-dvd/installation-cd-graphical-calamares-plasma5.nix +++ b/nixos/modules/installer/cd-dvd/installation-cd-graphical-calamares-plasma5.nix @@ -23,7 +23,7 @@ environment.systemPackages = with pkgs; [ # Graphical text editor - kate + plasma5Packages.kate ]; system.activationScripts.installerDesktop = let @@ -40,7 +40,7 @@ ln -sfT ${manualDesktopFile} ${desktopDir + "nixos-manual.desktop"} ln -sfT ${pkgs.gparted}/share/applications/gparted.desktop ${desktopDir + "gparted.desktop"} - ln -sfT ${pkgs.konsole}/share/applications/org.kde.konsole.desktop ${desktopDir + "org.kde.konsole.desktop"} + ln -sfT ${pkgs.plasma5Packages.konsole}/share/applications/org.kde.konsole.desktop ${desktopDir + "org.kde.konsole.desktop"} ln -sfT ${pkgs.calamares-nixos}/share/applications/io.calamares.calamares.desktop ${desktopDir + "io.calamares.calamares.desktop"} ''; diff --git a/nixos/modules/installer/cd-dvd/installation-cd-graphical-plasma5.nix b/nixos/modules/installer/cd-dvd/installation-cd-graphical-plasma5.nix index ce111bcebd5c9..770df5bb997b9 100644 --- a/nixos/modules/installer/cd-dvd/installation-cd-graphical-plasma5.nix +++ b/nixos/modules/installer/cd-dvd/installation-cd-graphical-plasma5.nix @@ -23,7 +23,7 @@ environment.systemPackages = with pkgs; [ # Graphical text editor - kate + plasma5Packages.kate ]; system.activationScripts.installerDesktop = let @@ -40,7 +40,7 @@ ln -sfT ${manualDesktopFile} ${desktopDir + "nixos-manual.desktop"} ln -sfT ${pkgs.gparted}/share/applications/gparted.desktop ${desktopDir + "gparted.desktop"} - ln -sfT ${pkgs.konsole}/share/applications/org.kde.konsole.desktop ${desktopDir + "org.kde.konsole.desktop"} + ln -sfT ${pkgs.plasma5Packages.konsole}/share/applications/org.kde.konsole.desktop ${desktopDir + "org.kde.konsole.desktop"} ''; } diff --git a/nixos/modules/installer/netboot/netboot.nix b/nixos/modules/installer/netboot/netboot.nix index c88a53393d13f..93f806b75eb11 100644 --- a/nixos/modules/installer/netboot/netboot.nix +++ b/nixos/modules/installer/netboot/netboot.nix @@ -37,10 +37,6 @@ with lib; # here and it causes a cyclic dependency. boot.loader.grub.enable = false; - # !!! Hack - attributes expected by other modules. - environment.systemPackages = [ pkgs.grub2_efi ] - ++ (lib.optionals (pkgs.stdenv.hostPlatform.system != "aarch64-linux") [pkgs.grub2 pkgs.syslinux]); - fileSystems."/" = mkImageMediaOverride { fsType = "tmpfs"; options = [ "mode=0755" ]; diff --git a/nixos/modules/misc/locate.nix b/nixos/modules/misc/locate.nix index 84c711c2b4efa..0e9adefff5e1e 100644 --- a/nixos/modules/misc/locate.nix +++ b/nixos/modules/misc/locate.nix @@ -1,24 +1,22 @@ { config, lib, pkgs, ... }: -with lib; - let cfg = config.services.locate; - isMLocate = hasPrefix "mlocate" cfg.package.name; - isPLocate = hasPrefix "plocate" cfg.package.name; + isMLocate = lib.hasPrefix "mlocate" cfg.package.name; + isPLocate = lib.hasPrefix "plocate" cfg.package.name; isMorPLocate = isMLocate || isPLocate; - isFindutils = hasPrefix "findutils" cfg.package.name; + isFindutils = lib.hasPrefix "findutils" cfg.package.name; in { imports = [ - (mkRenamedOptionModule [ "services" "locate" "period" ] [ "services" "locate" "interval" ]) - (mkRenamedOptionModule [ "services" "locate" "locate" ] [ "services" "locate" "package" ]) - (mkRemovedOptionModule [ "services" "locate" "includeStore" ] "Use services.locate.prunePaths") + (lib.mkRenamedOptionModule [ "services" "locate" "period" ] [ "services" "locate" "interval" ]) + (lib.mkRenamedOptionModule [ "services" "locate" "locate" ] [ "services" "locate" "package" ]) + (lib.mkRemovedOptionModule [ "services" "locate" "includeStore" ] "Use services.locate.prunePaths") ]; - options.services.locate = with types; { - enable = mkOption { - type = bool; + options.services.locate = { + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' If enabled, NixOS will periodically update the database of @@ -26,12 +24,12 @@ in ''; }; - package = mkPackageOption pkgs [ "findutils" "locate" ] { + package = lib.mkPackageOption pkgs [ "findutils" "locate" ] { example = "mlocate"; }; - interval = mkOption { - type = str; + interval = lib.mkOption { + type = lib.types.str; default = "02:15"; example = "hourly"; description = '' @@ -46,24 +44,24 @@ in ''; }; - extraFlags = mkOption { - type = listOf str; + extraFlags = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ ]; description = '' Extra flags to pass to {command}`updatedb`. ''; }; - output = mkOption { - type = path; + output = lib.mkOption { + type = lib.types.path; default = "/var/cache/locatedb"; description = '' The database file to build. ''; }; - localuser = mkOption { - type = nullOr str; + localuser = lib.mkOption { + type = lib.types.nullOr lib.types.str; default = "nobody"; description = '' The user to search non-network directories as, using @@ -71,8 +69,8 @@ in ''; }; - pruneFS = mkOption { - type = listOf str; + pruneFS = lib.mkOption { + type = lib.types.listOf lib.types.str; default = [ "afs" "anon_inodefs" @@ -158,8 +156,8 @@ in ''; }; - prunePaths = mkOption { - type = listOf path; + prunePaths = lib.mkOption { + type = lib.types.listOf lib.types.path; default = [ "/tmp" "/var/tmp" @@ -175,10 +173,10 @@ in ''; }; - pruneNames = mkOption { - type = listOf str; + pruneNames = lib.mkOption { + type = lib.types.listOf lib.types.str; default = lib.optionals (!isFindutils) [ ".bzr" ".cache" ".git" ".hg" ".svn" ]; - defaultText = literalMD '' + defaultText = lib.literalMD '' `[ ".bzr" ".cache" ".git" ".hg" ".svn" ]`, if supported by the locate implementation (i.e. mlocate or plocate). ''; @@ -187,8 +185,8 @@ in ''; }; - pruneBindMounts = mkOption { - type = bool; + pruneBindMounts = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether not to index bind mounts @@ -197,10 +195,10 @@ in }; - config = mkIf cfg.enable { - users.groups = mkMerge [ - (mkIf isMLocate { mlocate = { }; }) - (mkIf isPLocate { plocate = { }; }) + config = lib.mkIf cfg.enable { + users.groups = lib.mkMerge [ + (lib.mkIf isMLocate { mlocate = { }; }) + (lib.mkIf isPLocate { plocate = { }; }) ]; security.wrappers = @@ -211,46 +209,46 @@ in setgid = true; setuid = false; }; - mlocate = mkIf isMLocate { + mlocate = lib.mkIf isMLocate { group = "mlocate"; source = "${cfg.package}/bin/locate"; }; - plocate = mkIf isPLocate { + plocate = lib.mkIf isPLocate { group = "plocate"; source = "${cfg.package}/bin/plocate"; }; in - mkIf isMorPLocate { - locate = mkMerge [ common mlocate plocate ]; - plocate = mkIf isPLocate (mkMerge [ common plocate ]); + lib.mkIf isMorPLocate { + locate = lib.mkMerge [ common mlocate plocate ]; + plocate = lib.mkIf isPLocate (lib.mkMerge [ common plocate ]); }; - environment.systemPackages = [ cfg.package ]; + environment = { + # write /etc/updatedb.conf for manual calls to `updatedb` + etc."updatedb.conf".text = '' + PRUNEFS="${lib.concatStringsSep " " cfg.pruneFS}" + PRUNENAMES="${lib.concatStringsSep " " cfg.pruneNames}" + PRUNEPATHS="${lib.concatStringsSep " " cfg.prunePaths}" + PRUNE_BIND_MOUNTS="${if cfg.pruneBindMounts then "yes" else "no"}" + ''; - environment.variables.LOCATE_PATH = cfg.output; + systemPackages = [ cfg.package ]; - environment.etc = { - # write /etc/updatedb.conf for manual calls to `updatedb` - "updatedb.conf" = { - text = '' - PRUNEFS="${lib.concatStringsSep " " cfg.pruneFS}" - PRUNENAMES="${lib.concatStringsSep " " cfg.pruneNames}" - PRUNEPATHS="${lib.concatStringsSep " " cfg.prunePaths}" - PRUNE_BIND_MOUNTS="${if cfg.pruneBindMounts then "yes" else "no"}" - ''; + variables = lib.mkIf isFindutils { + LOCATE_PATH = cfg.output; }; }; - warnings = optional (isMorPLocate && cfg.localuser != null) + warnings = lib.optional (isMorPLocate && cfg.localuser != null) "mlocate and plocate do not support the services.locate.localuser option. updatedb will run as root. Silence this warning by setting services.locate.localuser = null." - ++ optional (isFindutils && cfg.pruneNames != [ ]) + ++ lib.optional (isFindutils && cfg.pruneNames != [ ]) "findutils locate does not support pruning by directory component" - ++ optional (isFindutils && cfg.pruneBindMounts) + ++ lib.optional (isFindutils && cfg.pruneBindMounts) "findutils locate does not support skipping bind mounts"; systemd.services.update-locatedb = { description = "Update Locate Database"; - path = mkIf (!isMorPLocate) [ pkgs.su ]; + path = lib.mkIf (!isMorPLocate) [ pkgs.su ]; # mlocate's updatedb takes flags via a configuration file or # on the command line, but not by environment variable. @@ -258,42 +256,44 @@ in if isMorPLocate then let toFlags = x: - optional (cfg.${x} != [ ]) - "--${lib.toLower x} '${concatStringsSep " " cfg.${x}}'"; - args = concatLists (map toFlags [ "pruneFS" "pruneNames" "prunePaths" ]); + lib.optional (cfg.${x} != [ ]) + "--${lib.toLower x} '${lib.concatStringsSep " " cfg.${x}}'"; + args = lib.concatLists (map toFlags [ "pruneFS" "pruneNames" "prunePaths" ]); in '' exec ${cfg.package}/bin/updatedb \ - --output ${toString cfg.output} ${concatStringsSep " " args} \ + --output ${toString cfg.output} ${lib.concatStringsSep " " args} \ --prune-bind-mounts ${if cfg.pruneBindMounts then "yes" else "no"} \ - ${concatStringsSep " " cfg.extraFlags} + ${lib.concatStringsSep " " cfg.extraFlags} '' else '' exec ${cfg.package}/bin/updatedb \ - ${optionalString (cfg.localuser != null && !isMorPLocate) "--localuser=${cfg.localuser}"} \ - --output=${toString cfg.output} ${concatStringsSep " " cfg.extraFlags} + ${lib.optionalString (cfg.localuser != null && !isMorPLocate) "--localuser=${cfg.localuser}"} \ + --output=${toString cfg.output} ${lib.concatStringsSep " " cfg.extraFlags} ''; - environment = optionalAttrs (!isMorPLocate) { - PRUNEFS = concatStringsSep " " cfg.pruneFS; - PRUNEPATHS = concatStringsSep " " cfg.prunePaths; - PRUNENAMES = concatStringsSep " " cfg.pruneNames; + environment = lib.optionalAttrs (!isMorPLocate) { + PRUNEFS = lib.concatStringsSep " " cfg.pruneFS; + PRUNEPATHS = lib.concatStringsSep " " cfg.prunePaths; + PRUNENAMES = lib.concatStringsSep " " cfg.pruneNames; PRUNE_BIND_MOUNTS = if cfg.pruneBindMounts then "yes" else "no"; }; - serviceConfig.Nice = 19; - serviceConfig.IOSchedulingClass = "idle"; - serviceConfig.PrivateTmp = "yes"; - serviceConfig.PrivateNetwork = "yes"; - serviceConfig.NoNewPrivileges = "yes"; - serviceConfig.ReadOnlyPaths = "/"; - # Use dirOf cfg.output because mlocate creates temporary files next to - # the actual database. We could specify and create them as well, - # but that would make this quite brittle when they change something. - # NOTE: If /var/cache does not exist, this leads to the misleading error message: - # update-locatedb.service: Failed at step NAMESPACE spawning …/update-locatedb-start: No such file or directory - serviceConfig.ReadWritePaths = dirOf cfg.output; + serviceConfig = { + Nice = 19; + IOSchedulingClass = "idle"; + PrivateTmp = "yes"; + PrivateNetwork = "yes"; + NoNewPrivileges = "yes"; + ReadOnlyPaths = "/"; + # Use dirOf cfg.output because mlocate creates temporary files next to + # the actual database. We could specify and create them as well, + # but that would make this quite brittle when they change something. + # NOTE: If /var/cache does not exist, this leads to the misleading error message: + # update-locatedb.service: Failed at step NAMESPACE spawning …/update-locatedb-start: No such file or directory + ReadWritePaths = dirOf cfg.output; + }; }; - systemd.timers.update-locatedb = mkIf (cfg.interval != "never") { + systemd.timers.update-locatedb = lib.mkIf (cfg.interval != "never") { description = "Update timer for locate database"; partOf = [ "update-locatedb.service" ]; wantedBy = [ "timers.target" ]; diff --git a/nixos/modules/misc/version.nix b/nixos/modules/misc/version.nix index d582e0c162de3..db917f73a0645 100644 --- a/nixos/modules/misc/version.nix +++ b/nixos/modules/misc/version.nix @@ -121,7 +121,7 @@ in image = { id = lib.mkOption { - type = types.nullOr (types.strMatching "^[a-z0-9._-]+$"); + type = types.nullOr types.str; default = null; description = '' Image identifier. @@ -135,7 +135,7 @@ in }; version = lib.mkOption { - type = types.nullOr (types.strMatching "^[a-z0-9._-]+$"); + type = types.nullOr types.str; default = null; description = '' Image version. diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index b14b83a8119ac..b20e98a9f229b 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -158,6 +158,7 @@ ./programs/bash/ls-colors.nix ./programs/bash/undistract-me.nix ./programs/bcc.nix + ./programs/benchexec.nix ./programs/browserpass.nix ./programs/calls.nix ./programs/captive-browser.nix @@ -167,6 +168,7 @@ ./programs/chromium.nix ./programs/clash-verge.nix ./programs/cnping.nix + ./programs/cpu-energy-meter.nix ./programs/command-not-found/command-not-found.nix ./programs/coolercontrol.nix ./programs/criu.nix @@ -194,6 +196,7 @@ ./programs/fzf.nix ./programs/gamemode.nix ./programs/gamescope.nix + ./programs/gdk-pixbuf.nix ./programs/geary.nix ./programs/git.nix ./programs/gnome-disks.nix @@ -216,6 +219,7 @@ ./programs/kbdlight.nix ./programs/kclock.nix ./programs/kdeconnect.nix + ./programs/ladybird.nix ./programs/lazygit.nix ./programs/kubeswitch.nix ./programs/less.nix @@ -247,9 +251,9 @@ ./programs/oblogout.nix ./programs/oddjobd.nix ./programs/openvpn3.nix - ./programs/pantheon-tweaks.nix ./programs/partition-manager.nix ./programs/plotinus.nix + ./programs/pqos-wrapper.nix ./programs/projecteur.nix ./programs/proxychains.nix ./programs/qdmr.nix @@ -279,6 +283,7 @@ ./programs/systemtap.nix ./programs/thefuck.nix ./programs/thunar.nix + ./programs/thunderbird.nix ./programs/tmux.nix ./programs/traceroute.nix ./programs/trippy.nix @@ -290,6 +295,7 @@ ./programs/virt-manager.nix ./programs/wavemon.nix ./programs/wayland/cardboard.nix + ./programs/wayland/hyprlock.nix ./programs/wayland/hyprland.nix ./programs/wayland/labwc.nix ./programs/wayland/river.nix @@ -415,6 +421,7 @@ ./services/cluster/kubernetes/scheduler.nix ./services/cluster/pacemaker/default.nix ./services/cluster/patroni/default.nix + ./services/cluster/rke2/default.nix ./services/cluster/spark/default.nix ./services/computing/boinc/client.nix ./services/computing/foldingathome/client.nix @@ -542,6 +549,7 @@ ./services/games/xonotic.nix ./services/hardware/acpid.nix ./services/hardware/actkbd.nix + ./services/hardware/amdvlk.nix ./services/hardware/argonone.nix ./services/hardware/asusd.nix ./services/hardware/auto-cpufreq.nix @@ -765,12 +773,14 @@ ./services/misc/octoprint.nix ./services/misc/ollama.nix ./services/misc/ombi.nix + ./services/misc/open-webui.nix ./services/misc/osrm.nix ./services/misc/owncast.nix ./services/misc/packagekit.nix ./services/misc/paperless.nix ./services/misc/parsoid.nix ./services/misc/persistent-evdev.nix + ./services/misc/pghero.nix ./services/misc/pinnwand.nix ./services/misc/plex.nix ./services/misc/plikd.nix @@ -785,6 +795,7 @@ ./services/misc/radarr.nix ./services/misc/readarr.nix ./services/misc/redmine.nix + ./services/misc/renovate.nix ./services/misc/ripple-data-api.nix ./services/misc/rippled.nix ./services/misc/rmfakecloud.nix @@ -827,6 +838,7 @@ ./services/misc/zoneminder.nix ./services/misc/zookeeper.nix ./services/monitoring/alerta.nix + ./services/monitoring/alloy.nix ./services/monitoring/apcupsd.nix ./services/monitoring/arbtt.nix ./services/monitoring/below.nix @@ -1106,6 +1118,7 @@ ./services/networking/ocserv.nix ./services/networking/ofono.nix ./services/networking/oidentd.nix + ./services/networking/oink.nix ./services/networking/onedrive.nix ./services/networking/openconnect.nix ./services/networking/openvpn.nix @@ -1240,6 +1253,7 @@ ./services/search/meilisearch.nix ./services/search/opensearch.nix ./services/search/qdrant.nix + ./services/search/quickwit.nix ./services/search/sonic-server.nix ./services/search/typesense.nix ./services/security/aesmd.nix @@ -1322,9 +1336,11 @@ ./services/video/unifi-video.nix ./services/video/v4l2-relayd.nix ./services/wayland/cage.nix + ./services/wayland/hypridle.nix ./services/web-apps/akkoma.nix ./services/web-apps/alps.nix ./services/web-apps/anuko-time-tracker.nix + ./services/web-apps/artalk.nix ./services/web-apps/atlassian/confluence.nix ./services/web-apps/atlassian/crowd.nix ./services/web-apps/atlassian/jira.nix @@ -1338,6 +1354,7 @@ ./services/web-apps/chatgpt-retrieval-plugin.nix ./services/web-apps/cloudlog.nix ./services/web-apps/code-server.nix + ./services/web-apps/commafeed.nix ./services/web-apps/convos.nix ./services/web-apps/crabfit.nix ./services/web-apps/davis.nix @@ -1348,7 +1365,9 @@ ./services/web-apps/dolibarr.nix ./services/web-apps/engelsystem.nix ./services/web-apps/ethercalc.nix + ./services/web-apps/filesender.nix ./services/web-apps/firefly-iii.nix + ./services/web-apps/flarum.nix ./services/web-apps/fluidd.nix ./services/web-apps/freshrss.nix ./services/web-apps/galene.nix @@ -1392,6 +1411,7 @@ ./services/web-apps/netbox.nix ./services/web-apps/nextcloud.nix ./services/web-apps/nextcloud-notify_push.nix + ./services/web-apps/nextjs-ollama-llm-ui.nix ./services/web-apps/nexus.nix ./services/web-apps/nifi.nix ./services/web-apps/node-red.nix @@ -1420,6 +1440,7 @@ ./services/web-apps/selfoss.nix ./services/web-apps/shiori.nix ./services/web-apps/silverbullet.nix + ./services/web-apps/simplesamlphp.nix ./services/web-apps/slskd.nix ./services/web-apps/snipe-it.nix ./services/web-apps/sogo.nix @@ -1437,6 +1458,7 @@ ./services/web-apps/zitadel.nix ./services/web-servers/agate.nix ./services/web-servers/apache-httpd/default.nix + ./services/web-servers/bluemap.nix ./services/web-servers/caddy/default.nix ./services/web-servers/darkhttpd.nix ./services/web-servers/fcgiwrap.nix @@ -1480,7 +1502,6 @@ ./services/x11/display-managers/xpra.nix ./services/x11/extra-layouts.nix ./services/x11/fractalart.nix - ./services/x11/gdk-pixbuf.nix ./services/x11/hardware/cmt.nix ./services/x11/hardware/digimend.nix ./services/x11/hardware/synaptics.nix diff --git a/nixos/modules/programs/bash/bash-completion.nix b/nixos/modules/programs/bash/bash-completion.nix index c973d36fdfbf0..f143361bc9331 100644 --- a/nixos/modules/programs/bash/bash-completion.nix +++ b/nixos/modules/programs/bash/bash-completion.nix @@ -1,16 +1,22 @@ { config, lib, pkgs, ... }: let - enable = config.programs.bash.enableCompletion; + cfg = config.programs.bash; in { - options = { - programs.bash.enableCompletion = lib.mkEnableOption "Bash completion for all interactive bash shells" // { + options.programs.bash.completion = { + enable = lib.mkEnableOption "Bash completion for all interactive bash shells" // { default = true; }; + + package = lib.mkPackageOption pkgs "bash-completion" { }; }; - config = lib.mkIf enable { + imports = [ + (lib.mkRenamedOptionModule [ "programs" "bash" "enableCompletion" ] [ "programs" "bash" "completion" "enable" ]) + ]; + + config = lib.mkIf cfg.completion.enable { programs.bash.promptPluginInit = '' # Check whether we're running a version of Bash that has support for # programmable completion. If we do, enable all modules installed in @@ -19,7 +25,7 @@ in # $XDG_DATA_DIRS/bash-completion/completions/ # on demand, so they do not need to be sourced here. if shopt -q progcomp &>/dev/null; then - . "${pkgs.bash-completion}/etc/profile.d/bash_completion.sh" + . "${cfg.completion.package}/etc/profile.d/bash_completion.sh" nullglobStatus=$(shopt -p nullglob) shopt -s nullglob for p in $NIX_PROFILES; do diff --git a/nixos/modules/programs/bash/bash.nix b/nixos/modules/programs/bash/bash.nix index 0f8c40da801b6..4c06f0aad9f81 100644 --- a/nixos/modules/programs/bash/bash.nix +++ b/nixos/modules/programs/bash/bash.nix @@ -198,7 +198,7 @@ in users.defaultUserShell = lib.mkDefault pkgs.bashInteractive; - environment.pathsToLink = lib.optionals cfg.enableCompletion [ + environment.pathsToLink = lib.optionals cfg.completion.enable [ "/etc/bash_completion.d" "/share/bash-completion" ]; diff --git a/nixos/modules/programs/benchexec.nix b/nixos/modules/programs/benchexec.nix new file mode 100644 index 0000000000000..652670c117ea3 --- /dev/null +++ b/nixos/modules/programs/benchexec.nix @@ -0,0 +1,98 @@ +{ lib +, pkgs +, config +, options +, ... +}: +let + cfg = config.programs.benchexec; + opt = options.programs.benchexec; + + filterUsers = x: + if builtins.isString x then config.users.users ? ${x} else + if builtins.isInt x then x else + throw "filterUsers expects string (username) or int (UID)"; + + uid = x: + if builtins.isString x then config.users.users.${x}.uid else + if builtins.isInt x then x else + throw "uid expects string (username) or int (UID)"; +in +{ + options.programs.benchexec = { + enable = lib.mkEnableOption "BenchExec"; + package = lib.options.mkPackageOption pkgs "benchexec" { }; + + users = lib.options.mkOption { + type = with lib.types; listOf (either str int); + description = '' + Users that intend to use BenchExec. + Provide usernames of users that are configured via {option}`${options.users.users}` as string, + and UIDs of "mutable users" as integers. + Control group delegation will be configured via systemd. + For more information, see . + ''; + default = [ ]; + example = lib.literalExpression '' + [ + "alice" # username of a user configured via ${options.users.users} + 1007 # UID of a mutable user + ] + ''; + }; + }; + + config = lib.mkIf cfg.enable { + assertions = (map + (user: { + assertion = config.users.users ? ${user}; + message = '' + The user '${user}' intends to use BenchExec (via `${opt.users}`), but is not configured via `${options.users.users}`. + ''; + }) + (builtins.filter builtins.isString cfg.users) + ) ++ (map + (id: { + assertion = config.users.mutableUsers; + message = '' + The user with UID '${id}' intends to use BenchExec (via `${opt.users}`), but mutable users are disabled via `${options.users.mutableUsers}`. + ''; + }) + (builtins.filter builtins.isInt cfg.users) + ) ++ [ + { + assertion = config.systemd.enableUnifiedCgroupHierarchy == true; + message = '' + The BenchExec module `${opt.enable}` only supports control groups 2 (`${options.systemd.enableUnifiedCgroupHierarchy} = true`). + ''; + } + ]; + + environment.systemPackages = [ cfg.package ]; + + # See . + systemd.services = builtins.listToAttrs (map + (user: { + name = "user@${builtins.toString (uid user)}"; + value = { + serviceConfig.Delegate = "yes"; + overrideStrategy = "asDropin"; + }; + }) + (builtins.filter filterUsers cfg.users)); + + # See . + virtualisation.lxc.lxcfs.enable = lib.mkDefault true; + + # See . + programs = { + cpu-energy-meter.enable = lib.mkDefault true; + pqos-wrapper.enable = lib.mkDefault true; + }; + + # See . + security.unprivilegedUsernsClone = true; + }; + + meta.maintainers = with lib.maintainers; [ lorenzleutgeb ]; +} diff --git a/nixos/modules/programs/coolercontrol.nix b/nixos/modules/programs/coolercontrol.nix index 8c9a39d2eba99..1c64d46ae2b90 100644 --- a/nixos/modules/programs/coolercontrol.nix +++ b/nixos/modules/programs/coolercontrol.nix @@ -48,9 +48,11 @@ in # Nvidia support (lib.mkIf cfg.nvidiaSupport { - systemd.services.coolercontrold.path = with config.boot.kernelPackages; [ - nvidia_x11 # nvidia-smi - nvidia_x11.settings # nvidia-settings + systemd.services.coolercontrold.path = let + nvidiaPkg = config.hardware.nvidia.package; + in [ + nvidiaPkg # nvidia-smi + nvidiaPkg.settings # nvidia-settings ]; }) ]); diff --git a/nixos/modules/programs/cpu-energy-meter.nix b/nixos/modules/programs/cpu-energy-meter.nix new file mode 100644 index 0000000000000..653ec067492d7 --- /dev/null +++ b/nixos/modules/programs/cpu-energy-meter.nix @@ -0,0 +1,27 @@ +{ config +, lib +, pkgs +, ... +}: { + options.programs.cpu-energy-meter = { + enable = lib.mkEnableOption "CPU Energy Meter"; + package = lib.mkPackageOption pkgs "cpu-energy-meter" { }; + }; + + config = + let + cfg = config.programs.cpu-energy-meter; + in + lib.mkIf cfg.enable { + hardware.cpu.x86.msr.enable = true; + + security.wrappers.${cfg.package.meta.mainProgram} = { + owner = "nobody"; + group = config.hardware.cpu.x86.msr.group; + source = lib.getExe cfg.package; + capabilities = "cap_sys_rawio=ep"; + }; + }; + + meta.maintainers = with lib.maintainers; [ lorenzleutgeb ]; +} diff --git a/nixos/modules/programs/fzf.nix b/nixos/modules/programs/fzf.nix index 66ad7d418de68..b9258ab1e5052 100644 --- a/nixos/modules/programs/fzf.nix +++ b/nixos/modules/programs/fzf.nix @@ -15,7 +15,7 @@ in environment.systemPackages = lib.mkIf (cfg.keybindings || cfg.fuzzyCompletion) [ pkgs.fzf ]; programs = { - # load after programs.bash.enableCompletion + # load after programs.bash.completion.enable bash.promptPluginInit = lib.mkAfter (lib.optionalString cfg.fuzzyCompletion '' source ${pkgs.fzf}/share/fzf/completion.bash '' + lib.optionalString cfg.keybindings '' diff --git a/nixos/modules/programs/gdk-pixbuf.nix b/nixos/modules/programs/gdk-pixbuf.nix new file mode 100644 index 0000000000000..f96259ccd2c78 --- /dev/null +++ b/nixos/modules/programs/gdk-pixbuf.nix @@ -0,0 +1,32 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.programs.gdk-pixbuf; + + loadersCache = pkgs.gnome._gdkPixbufCacheBuilder_DO_NOT_USE { + extraLoaders = lib.unique cfg.modulePackages; + }; +in + +{ + imports = [ + (lib.mkRenamedOptionModule [ "services" "xserver" "gdk-pixbuf" ] [ "programs" "gdk-pixbuf" ]) + ]; + + options = { + programs.gdk-pixbuf.modulePackages = lib.mkOption { + type = lib.types.listOf lib.types.package; + default = [ ]; + description = "Packages providing GDK-Pixbuf modules, for cache generation."; + }; + }; + + # If there is any package configured in modulePackages, we generate the + # loaders.cache based on that and set the environment variable + # GDK_PIXBUF_MODULE_FILE to point to it. + config = lib.mkIf (cfg.modulePackages != []) { + environment.sessionVariables = { + GDK_PIXBUF_MODULE_FILE = loadersCache; + }; + }; +} diff --git a/nixos/modules/programs/gnupg.nix b/nixos/modules/programs/gnupg.nix index c755d110170c6..eb983d9ce78a9 100644 --- a/nixos/modules/programs/gnupg.nix +++ b/nixos/modules/programs/gnupg.nix @@ -8,22 +8,6 @@ let agentSettingsFormat = pkgs.formats.keyValue { mkKeyValue = lib.generators.mkKeyValueDefault { } " "; }; - - xserverCfg = config.services.xserver; - - defaultPinentryFlavor = - if xserverCfg.desktopManager.lxqt.enable - || xserverCfg.desktopManager.plasma5.enable - || xserverCfg.desktopManager.plasma6.enable - || xserverCfg.desktopManager.deepin.enable then - "qt" - else if xserverCfg.desktopManager.xfce.enable then - "gtk2" - else if xserverCfg.enable || config.programs.sway.enable then - "gnome3" - else - "curses"; - in { imports = [ diff --git a/nixos/modules/programs/kdeconnect.nix b/nixos/modules/programs/kdeconnect.nix index dbdff1e447c5c..76bba40103084 100644 --- a/nixos/modules/programs/kdeconnect.nix +++ b/nixos/modules/programs/kdeconnect.nix @@ -21,7 +21,6 @@ lib.mkIf cfg.enable { environment.systemPackages = [ cfg.package - pkgs.sshfs ]; networking.firewall = rec { allowedTCPPortRanges = [ { from = 1714; to = 1764; } ]; diff --git a/nixos/modules/programs/ladybird.nix b/nixos/modules/programs/ladybird.nix new file mode 100644 index 0000000000000..43bfe445ef58e --- /dev/null +++ b/nixos/modules/programs/ladybird.nix @@ -0,0 +1,14 @@ +{ config, pkgs, lib, ... }: + +let + cfg = config.programs.ladybird; +in { + options = { + programs.ladybird.enable = lib.mkEnableOption "the Ladybird web browser"; + }; + + config = lib.mkIf cfg.enable { + environment.systemPackages = [ pkgs.ladybird ]; + fonts.fontDir.enable = true; + }; +} diff --git a/nixos/modules/programs/less.nix b/nixos/modules/programs/less.nix index c904fc2089aa3..50ea1586f6880 100644 --- a/nixos/modules/programs/less.nix +++ b/nixos/modules/programs/less.nix @@ -35,6 +35,8 @@ in # therefore also enables this module enable = lib.mkEnableOption "less, a file pager"; + package = lib.mkPackageOption pkgs "less" { }; + configFile = lib.mkOption { type = lib.types.nullOr lib.types.path; default = null; @@ -110,7 +112,7 @@ in config = lib.mkIf cfg.enable { - environment.systemPackages = [ pkgs.less ]; + environment.systemPackages = [ cfg.package ]; environment.variables = { LESSKEYIN_SYSTEM = builtins.toString lessKey; diff --git a/nixos/modules/programs/pantheon-tweaks.nix b/nixos/modules/programs/pantheon-tweaks.nix deleted file mode 100644 index b7258e2eb4bfe..0000000000000 --- a/nixos/modules/programs/pantheon-tweaks.nix +++ /dev/null @@ -1,17 +0,0 @@ -{ config, lib, pkgs, ... }: - -{ - meta = { - maintainers = lib.teams.pantheon.members; - }; - - ###### interface - options = { - programs.pantheon-tweaks.enable = lib.mkEnableOption "Pantheon Tweaks, an unofficial system settings panel for Pantheon"; - }; - - ###### implementation - config = lib.mkIf config.programs.pantheon-tweaks.enable { - services.xserver.desktopManager.pantheon.extraSwitchboardPlugs = [ pkgs.pantheon-tweaks ]; - }; -} diff --git a/nixos/modules/programs/pqos-wrapper.nix b/nixos/modules/programs/pqos-wrapper.nix new file mode 100644 index 0000000000000..82023e67a2ae2 --- /dev/null +++ b/nixos/modules/programs/pqos-wrapper.nix @@ -0,0 +1,27 @@ +{ config +, lib +, pkgs +, ... +}: +let + cfg = config.programs.pqos-wrapper; +in +{ + options.programs.pqos-wrapper = { + enable = lib.mkEnableOption "PQoS Wrapper for BenchExec"; + package = lib.mkPackageOption pkgs "pqos-wrapper" { }; + }; + + config = lib.mkIf cfg.enable { + hardware.cpu.x86.msr.enable = true; + + security.wrappers.${cfg.package.meta.mainProgram} = { + owner = "nobody"; + group = config.hardware.cpu.x86.msr.group; + source = lib.getExe cfg.package; + capabilities = "cap_sys_rawio=eip"; + }; + }; + + meta.maintainers = with lib.maintainers; [ lorenzleutgeb ]; +} diff --git a/nixos/modules/programs/screen.nix b/nixos/modules/programs/screen.nix index 01af5b4c9597a..4f3cd9fcf9a56 100644 --- a/nixos/modules/programs/screen.nix +++ b/nixos/modules/programs/screen.nix @@ -12,7 +12,8 @@ in package = lib.mkPackageOptionMD pkgs "screen" { }; screenrc = lib.mkOption { - type = with lib.types; nullOr lines; + type = lib.types.lines; + default = ""; example = '' defscrollback 10000 startup_message off @@ -22,20 +23,22 @@ in }; }; - config = { - # TODO: Added in 24.05, remove before 24.11 - assertions = [ - { - assertion = cfg.screenrc != null -> cfg.enable; - message = "`programs.screen.screenrc` has been configured, but `programs.screen.enable` is not true"; - } - ]; - } // lib.mkIf cfg.enable { - environment.etc.screenrc = { - enable = cfg.screenrc != null; - text = cfg.screenrc; - }; - environment.systemPackages = [ cfg.package ]; - security.pam.services.screen = {}; - }; + config = lib.mkMerge [ + { + # TODO: Added in 24.05, remove before 24.11 + assertions = [ + { + assertion = cfg.screenrc != "" -> cfg.enable; + message = "`programs.screen.screenrc` has been configured, but `programs.screen.enable` is not true"; + } + ]; + } + (lib.mkIf cfg.enable { + environment.etc.screenrc = { + text = cfg.screenrc; + }; + environment.systemPackages = [ cfg.package ]; + security.pam.services.screen = {}; + }) + ]; } diff --git a/nixos/modules/programs/shadow.nix b/nixos/modules/programs/shadow.nix index f09bfaa5393d7..ef5bad69e934e 100644 --- a/nixos/modules/programs/shadow.nix +++ b/nixos/modules/programs/shadow.nix @@ -4,7 +4,18 @@ let cfg = config.security.loginDefs; in { - options = with lib.types; { + options = { + + security.shadow.enable = lib.mkEnableOption "" // { + default = true; + description = '' + Enable the shadow authentication suite, which provides critical programs such as su, login, passwd. + + Note: This is currently experimental. Only disable this if you're + confident that you can recover your system if it breaks. + ''; + }; + security.loginDefs = { package = lib.mkPackageOption pkgs "shadow" { }; @@ -12,7 +23,7 @@ in description = '' Use chfn SUID to allow non-root users to change their account GECOS information. ''; - type = nullOr str; + type = lib.types.nullOr lib.types.str; default = null; }; @@ -22,7 +33,7 @@ in the site-specific configuration for the shadow password suite. See login.defs(5) man page for available options. ''; - type = submodule { + type = lib.types.submodule { freeformType = (pkgs.formats.keyValue { }).type; /* There are three different sources for user/group id ranges, each of which gets used by different programs: @@ -37,62 +48,62 @@ in DEFAULT_HOME = lib.mkOption { description = "Indicate if login is allowed if we can't cd to the home directory."; default = "yes"; - type = enum [ "yes" "no" ]; + type = lib.types.enum [ "yes" "no" ]; }; ENCRYPT_METHOD = lib.mkOption { description = "This defines the system default encryption algorithm for encrypting passwords."; # The default crypt() method, keep in sync with the PAM default default = "YESCRYPT"; - type = enum [ "YESCRYPT" "SHA512" "SHA256" "MD5" "DES"]; + type = lib.types.enum [ "YESCRYPT" "SHA512" "SHA256" "MD5" "DES"]; }; SYS_UID_MIN = lib.mkOption { description = "Range of user IDs used for the creation of system users by useradd or newusers."; default = 400; - type = int; + type = lib.types.int; }; SYS_UID_MAX = lib.mkOption { description = "Range of user IDs used for the creation of system users by useradd or newusers."; default = 999; - type = int; + type = lib.types.int; }; UID_MIN = lib.mkOption { description = "Range of user IDs used for the creation of regular users by useradd or newusers."; default = 1000; - type = int; + type = lib.types.int; }; UID_MAX = lib.mkOption { description = "Range of user IDs used for the creation of regular users by useradd or newusers."; default = 29999; - type = int; + type = lib.types.int; }; SYS_GID_MIN = lib.mkOption { description = "Range of group IDs used for the creation of system groups by useradd, groupadd, or newusers"; default = 400; - type = int; + type = lib.types.int; }; SYS_GID_MAX = lib.mkOption { description = "Range of group IDs used for the creation of system groups by useradd, groupadd, or newusers"; default = 999; - type = int; + type = lib.types.int; }; GID_MIN = lib.mkOption { description = "Range of group IDs used for the creation of regular groups by useradd, groupadd, or newusers."; default = 1000; - type = int; + type = lib.types.int; }; GID_MAX = lib.mkOption { description = "Range of group IDs used for the creation of regular groups by useradd, groupadd, or newusers."; default = 29999; - type = int; + type = lib.types.int; }; TTYGROUP = lib.mkOption { @@ -100,7 +111,7 @@ in The terminal permissions: the login tty will be owned by the TTYGROUP group, and the permissions will be set to TTYPERM''; default = "tty"; - type = str; + type = lib.types.str; }; TTYPERM = lib.mkOption { @@ -108,14 +119,14 @@ in The terminal permissions: the login tty will be owned by the TTYGROUP group, and the permissions will be set to TTYPERM''; default = "0620"; - type = str; + type = lib.types.str; }; # Ensure privacy for newly created home directories. UMASK = lib.mkOption { description = "The file mode creation mask is initialized to this value."; default = "077"; - type = str; + type = lib.types.str; }; }; }; @@ -132,107 +143,115 @@ in used outside the store (in particular in /etc/passwd). ''; example = lib.literalExpression "pkgs.zsh"; - type = either path shellPackage; + type = lib.types.either lib.types.path lib.types.shellPackage; }; }; ###### implementation - config = { - assertions = [ - { - assertion = cfg.settings.SYS_UID_MIN <= cfg.settings.SYS_UID_MAX; - message = "SYS_UID_MIN must be less than or equal to SYS_UID_MAX"; - } - { - assertion = cfg.settings.UID_MIN <= cfg.settings.UID_MAX; - message = "UID_MIN must be less than or equal to UID_MAX"; - } - { - assertion = cfg.settings.SYS_GID_MIN <= cfg.settings.SYS_GID_MAX; - message = "SYS_GID_MIN must be less than or equal to SYS_GID_MAX"; - } - { - assertion = cfg.settings.GID_MIN <= cfg.settings.GID_MAX; - message = "GID_MIN must be less than or equal to GID_MAX"; - } - ]; - - security.loginDefs.settings.CHFN_RESTRICT = - lib.mkIf (cfg.chfnRestrict != null) cfg.chfnRestrict; - - environment.systemPackages = lib.optional config.users.mutableUsers cfg.package - ++ lib.optional (lib.types.shellPackage.check config.users.defaultUserShell) config.users.defaultUserShell - ++ lib.optional (cfg.chfnRestrict != null) pkgs.util-linux; - - environment.etc = - # Create custom toKeyValue generator - # see https://man7.org/linux/man-pages/man5/login.defs.5.html for config specification - let - toKeyValue = lib.generators.toKeyValue { - mkKeyValue = lib.generators.mkKeyValueDefault { } " "; - }; - in - { - # /etc/login.defs: global configuration for pwdutils. - # You cannot login without it! - "login.defs".source = pkgs.writeText "login.defs" (toKeyValue cfg.settings); - - # /etc/default/useradd: configuration for useradd. - "default/useradd".source = pkgs.writeText "useradd" '' - GROUP=100 - HOME=/home - SHELL=${utils.toShellPath config.users.defaultUserShell} - ''; - }; + config = lib.mkMerge [ + { + assertions = [ + { + assertion = config.security.shadow.enable || config.services.greetd.enable; + message = "You must enable at least one VT login method, either security.shadow.enable or services.greetd.enable"; + } + ]; + } + (lib.mkIf config.security.shadow.enable { + assertions = [ + { + assertion = cfg.settings.SYS_UID_MIN <= cfg.settings.SYS_UID_MAX; + message = "SYS_UID_MIN must be less than or equal to SYS_UID_MAX"; + } + { + assertion = cfg.settings.UID_MIN <= cfg.settings.UID_MAX; + message = "UID_MIN must be less than or equal to UID_MAX"; + } + { + assertion = cfg.settings.SYS_GID_MIN <= cfg.settings.SYS_GID_MAX; + message = "SYS_GID_MIN must be less than or equal to SYS_GID_MAX"; + } + { + assertion = cfg.settings.GID_MIN <= cfg.settings.GID_MAX; + message = "GID_MIN must be less than or equal to GID_MAX"; + } + ]; - security.pam.services = { - chsh = { rootOK = true; }; - chfn = { rootOK = true; }; - su = { - rootOK = true; - forwardXAuth = true; - logFailures = true; - }; - passwd = { }; - # Note: useradd, groupadd etc. aren't setuid root, so it - # doesn't really matter what the PAM config says as long as it - # lets root in. - useradd.rootOK = true; - usermod.rootOK = true; - userdel.rootOK = true; - groupadd.rootOK = true; - groupmod.rootOK = true; - groupmems.rootOK = true; - groupdel.rootOK = true; - login = { - startSession = true; - allowNullPassword = true; - showMotd = true; - updateWtmp = true; - }; - chpasswd = { rootOK = true; }; - }; + security.loginDefs.settings.CHFN_RESTRICT = lib.mkIf (cfg.chfnRestrict != null) cfg.chfnRestrict; + + environment.systemPackages = lib.optional config.users.mutableUsers cfg.package + ++ lib.optional (lib.types.shellPackage.check config.users.defaultUserShell) config.users.defaultUserShell + ++ lib.optional (cfg.chfnRestrict != null) pkgs.util-linux; + + environment.etc = + # Create custom toKeyValue generator + # see https://man7.org/linux/man-pages/man5/login.defs.5.html for config specification + let + toKeyValue = lib.generators.toKeyValue { + mkKeyValue = lib.generators.mkKeyValueDefault { } " "; + }; + in { + # /etc/login.defs: global configuration for pwdutils. + # You cannot login without it! + "login.defs".source = pkgs.writeText "login.defs" (toKeyValue cfg.settings); + + # /etc/default/useradd: configuration for useradd. + "default/useradd".source = pkgs.writeText "useradd" '' + GROUP=100 + HOME=/home + SHELL=${utils.toShellPath config.users.defaultUserShell} + ''; + }; - security.wrappers = - let - mkSetuidRoot = source: { - setuid = true; - owner = "root"; - group = "root"; - inherit source; + security.pam.services = { + chsh.rootOK = true; + chfn.rootOK = true; + su = { + rootOK = true; + forwardXAuth = true; + logFailures = true; }; - in - { - su = mkSetuidRoot "${cfg.package.su}/bin/su"; - sg = mkSetuidRoot "${cfg.package.out}/bin/sg"; - newgrp = mkSetuidRoot "${cfg.package.out}/bin/newgrp"; - newuidmap = mkSetuidRoot "${cfg.package.out}/bin/newuidmap"; - newgidmap = mkSetuidRoot "${cfg.package.out}/bin/newgidmap"; - } - // lib.optionalAttrs config.users.mutableUsers { - chsh = mkSetuidRoot "${cfg.package.out}/bin/chsh"; - passwd = mkSetuidRoot "${cfg.package.out}/bin/passwd"; + passwd = { }; + # Note: useradd, groupadd etc. aren't setuid root, so it + # doesn't really matter what the PAM config says as long as it + # lets root in. + useradd.rootOK = true; + usermod.rootOK = true; + userdel.rootOK = true; + groupadd.rootOK = true; + groupmod.rootOK = true; + groupmems.rootOK = true; + groupdel.rootOK = true; + login = { + startSession = true; + allowNullPassword = true; + showMotd = true; + updateWtmp = true; + }; + chpasswd.rootOK = true; }; - }; + + security.wrappers = + let + mkSetuidRoot = source: { + setuid = true; + owner = "root"; + group = "root"; + inherit source; + }; + in + { + su = mkSetuidRoot "${cfg.package.su}/bin/su"; + sg = mkSetuidRoot "${cfg.package.out}/bin/sg"; + newgrp = mkSetuidRoot "${cfg.package.out}/bin/newgrp"; + newuidmap = mkSetuidRoot "${cfg.package.out}/bin/newuidmap"; + newgidmap = mkSetuidRoot "${cfg.package.out}/bin/newgidmap"; + } + // lib.optionalAttrs config.users.mutableUsers { + chsh = mkSetuidRoot "${cfg.package.out}/bin/chsh"; + passwd = mkSetuidRoot "${cfg.package.out}/bin/passwd"; + }; + }) + ]; } diff --git a/nixos/modules/programs/steam.nix b/nixos/modules/programs/steam.nix index d317398495f54..5138588dbd3e5 100644 --- a/nixos/modules/programs/steam.nix +++ b/nixos/modules/programs/steam.nix @@ -4,6 +4,8 @@ let cfg = config.programs.steam; gamescopeCfg = config.programs.gamescope; + extraCompatPaths = lib.makeSearchPathOutput "steamcompattool" "" cfg.extraCompatPackages; + steam-gamescope = let exports = builtins.attrValues (builtins.mapAttrs (n: v: "export ${n}=${v}") cfg.gamescopeSession.env); in @@ -42,7 +44,7 @@ in { ''; apply = steam: steam.override (prev: { extraEnv = (lib.optionalAttrs (cfg.extraCompatPackages != [ ]) { - STEAM_EXTRA_COMPAT_TOOLS_PATHS = lib.makeSearchPathOutput "steamcompattool" "" cfg.extraCompatPackages; + STEAM_EXTRA_COMPAT_TOOLS_PATHS = extraCompatPaths; }) // (lib.optionalAttrs cfg.extest.enable { LD_PRELOAD = "${pkgs.pkgsi686Linux.extest}/lib/libextest.so"; }) // (prev.extraEnv or {}); @@ -53,6 +55,7 @@ in { then [ package ] ++ extraPackages else [ package32 ] ++ extraPackages32; in prevLibs ++ additionalLibs; + extraPkgs = p: (cfg.extraPackages ++ lib.optionals (prev ? extraPkgs) (prev.extraPkgs p)); } // lib.optionalAttrs (cfg.gamescopeSession.enable && gamescopeCfg.capSysNice) { buildFHSEnv = pkgs.buildFHSEnv.override { @@ -69,6 +72,19 @@ in { ''; }; + extraPackages = lib.mkOption { + type = lib.types.listOf lib.types.package; + default = [ ]; + example = lib.literalExpression '' + with pkgs; [ + gamescope + ] + ''; + description = '' + Additional packages to add to the Steam environment. + ''; + }; + extraCompatPackages = lib.mkOption { type = lib.types.listOf lib.types.package; default = [ ]; @@ -86,6 +102,19 @@ in { ''; }; + fontPackages = lib.mkOption { + type = lib.types.listOf lib.types.package; + # `fonts.packages` is a list of paths now, filter out which are not packages + default = builtins.filter lib.types.package.check config.fonts.packages; + defaultText = lib.literalExpression "builtins.filter lib.types.package.check config.fonts.packages"; + example = lib.literalExpression "with pkgs; [ source-han-sans ]"; + description = '' + Font packages to use in Steam. + + Defaults to system fonts, but could be overridden to use other fonts — useful for users who would like to customize CJK fonts used in Steam. According to the [upstream issue](https://github.com/ValveSoftware/steam-for-linux/issues/10422#issuecomment-1944396010), Steam only follows the per-user fontconfig configuration. + ''; + }; + remotePlay.openFirewall = lib.mkOption { type = lib.types.bool; default = false; @@ -139,6 +168,11 @@ in { Load the extest library into Steam, to translate X11 input events to uinput events (e.g. for using Steam Input on Wayland) ''; + + protontricks = { + enable = lib.mkEnableOption "protontricks, a simple wrapper for running Winetricks commands for Proton-enabled games"; + package = lib.mkPackageOption pkgs "protontricks" { }; + }; }; config = lib.mkIf cfg.enable { @@ -158,6 +192,8 @@ in { }; }; + programs.steam.extraPackages = cfg.fontPackages; + programs.gamescope.enable = lib.mkDefault cfg.gamescopeSession.enable; services.displayManager.sessionPackages = lib.mkIf cfg.gamescopeSession.enable [ gamescopeSessionFile ]; @@ -169,7 +205,8 @@ in { environment.systemPackages = [ cfg.package cfg.package.run - ] ++ lib.optional cfg.gamescopeSession.enable steam-gamescope; + ] ++ lib.optional cfg.gamescopeSession.enable steam-gamescope + ++ lib.optional cfg.protontricks.enable (cfg.protontricks.package.override { inherit extraCompatPaths; }); networking.firewall = lib.mkMerge [ (lib.mkIf (cfg.remotePlay.openFirewall || cfg.localNetworkGameTransfers.openFirewall) { @@ -192,5 +229,5 @@ in { ]; }; - meta.maintainers = lib.teams.steam; + meta.maintainers = lib.teams.steam.members; } diff --git a/nixos/modules/programs/thunderbird.nix b/nixos/modules/programs/thunderbird.nix new file mode 100644 index 0000000000000..b15c1df609439 --- /dev/null +++ b/nixos/modules/programs/thunderbird.nix @@ -0,0 +1,89 @@ +{ + pkgs, + config, + lib, + ... +}: +let + cfg = config.programs.thunderbird; + policyFormat = pkgs.formats.json { }; + policyDoc = "https://github.com/thunderbird/policy-templates"; +in +{ + options.programs.thunderbird = { + enable = lib.mkEnableOption "Thunderbird mail client"; + + package = lib.mkPackageOption pkgs "thunderbird" { }; + + policies = lib.mkOption { + type = policyFormat.type; + default = { }; + description = '' + Group policies to install. + + See [Thunderbird's documentation](${policyDoc}) + for a list of available options. + + This can be used to install extensions declaratively! Check out the + documentation of the `ExtensionSettings` policy for details. + + ''; + }; + + preferences = lib.mkOption { + type = + with lib.types; + attrsOf (oneOf [ + bool + int + str + ]); + default = { }; + description = '' + Preferences to set from `about:config`. + + Some of these might be able to be configured more ergonomically + using policies. + ''; + }; + + preferencesStatus = lib.mkOption { + type = lib.types.enum [ + "default" + "locked" + "user" + "clear" + ]; + default = "locked"; + description = '' + The status of `thunderbird.preferences`. + + `status` can assume the following values: + - `"default"`: Preferences appear as default. + - `"locked"`: Preferences appear as default and can't be changed. + - `"user"`: Preferences appear as changed. + - `"clear"`: Value has no effect. Resets to factory defaults on each startup. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + environment.systemPackages = [ cfg.package ]; + + environment.etc = + let + policiesJSON = policyFormat.generate "thunderbird-policies.json" { inherit (cfg) policies; }; + in + lib.mkIf (cfg.policies != { }) { "thunderbird/policies/policies.json".source = policiesJSON; }; + + programs.thunderbird.policies = { + DisableAppUpdate = true; + Preferences = builtins.mapAttrs (_: value: { + Value = value; + Status = cfg.preferencesStatus; + }) cfg.preferences; + }; + }; + + meta.maintainers = with lib.maintainers; [ nydragon ]; +} diff --git a/nixos/modules/programs/wayland/hyprland.nix b/nixos/modules/programs/wayland/hyprland.nix index c963429f2e2a9..5a21bd153b632 100644 --- a/nixos/modules/programs/wayland/hyprland.nix +++ b/nixos/modules/programs/wayland/hyprland.nix @@ -1,46 +1,41 @@ -{ config -, lib -, pkgs -, ... -}: +{ config, lib, pkgs, ... }: + let cfg = config.programs.hyprland; - finalPortalPackage = cfg.portalPackage.override { - hyprland = cfg.finalPackage; - }; + wayland-lib = import ./lib.nix { inherit lib; }; in { options.programs.hyprland = { - enable = lib.mkEnableOption null // { - description = '' - Whether to enable Hyprland, the dynamic tiling Wayland compositor that doesn't sacrifice on its looks. - - You can manually launch Hyprland by executing {command}`Hyprland` on a TTY. - - A configuration file will be generated in {file}`~/.config/hypr/hyprland.conf`. - See for more information. + enable = lib.mkEnableOption '' + Hyprland, the dynamic tiling Wayland compositor that doesn't sacrifice on its looks. + You can manually launch Hyprland by executing {command}`Hyprland` on a TTY. + A configuration file will be generated in {file}`~/.config/hypr/hyprland.conf`. + See for more information''; + + package = lib.mkPackageOption pkgs "hyprland" { + extraDescription = '' + If the package is not overridable with `enableXWayland`, then the module option + {option}`xwayland` will have no effect. ''; - }; - - package = lib.mkPackageOption pkgs "hyprland" { }; - - finalPackage = lib.mkOption { - type = lib.types.package; - readOnly = true; - default = cfg.package.override { + } // { + apply = p: wayland-lib.genFinalPackage p { enableXWayland = cfg.xwayland.enable; }; - defaultText = lib.literalExpression - "`programs.hyprland.package` with applied configuration"; - description = '' - The Hyprland package after applying configuration. - ''; }; - portalPackage = lib.mkPackageOption pkgs "xdg-desktop-portal-hyprland" { }; + portalPackage = lib.mkPackageOption pkgs "xdg-desktop-portal-hyprland" { + extraDescription = '' + If the package is not overridable with `hyprland`, then the Hyprland package + used by the portal may differ from the one set in the module option {option}`package`. + ''; + } // { + apply = p: wayland-lib.genFinalPackage p { + hyprland = cfg.package; + }; + }; - xwayland.enable = lib.mkEnableOption ("XWayland") // { default = true; }; + xwayland.enable = lib.mkEnableOption "XWayland" // { default = true; }; systemd.setPath.enable = lib.mkEnableOption null // { default = true; @@ -53,33 +48,32 @@ in }; }; - config = lib.mkIf cfg.enable { - environment.systemPackages = [ cfg.finalPackage ]; - - fonts.enableDefaultPackages = lib.mkDefault true; - hardware.opengl.enable = lib.mkDefault true; - - programs = { - dconf.enable = lib.mkDefault true; - xwayland.enable = lib.mkDefault cfg.xwayland.enable; - }; + config = lib.mkIf cfg.enable (lib.mkMerge [ + { + environment.systemPackages = [ cfg.package ]; - security.polkit.enable = true; + # To make a Hyprland session available if a display manager like SDDM is enabled: + services.displayManager.sessionPackages = [ cfg.package ]; - services.displayManager.sessionPackages = [ cfg.finalPackage ]; + xdg.portal = { + enable = true; + extraPortals = [ cfg.portalPackage ]; + configPackages = lib.mkDefault [ cfg.package ]; + }; - xdg.portal = { - enable = lib.mkDefault true; - extraPortals = [ finalPortalPackage ]; - configPackages = lib.mkDefault [ cfg.finalPackage ]; - }; + systemd = lib.mkIf cfg.systemd.setPath.enable { + user.extraConfig = '' + DefaultEnvironment="PATH=$PATH:/run/current-system/sw/bin:/etc/profiles/per-user/%u/bin:/run/wrappers/bin" + ''; + }; + } - systemd = lib.mkIf cfg.systemd.setPath.enable { - user.extraConfig = '' - DefaultEnvironment="PATH=$PATH:/run/current-system/sw/bin:/etc/profiles/per-user/%u/bin:/run/wrappers/bin" - ''; - }; - }; + (import ./wayland-session.nix { + inherit lib pkgs; + enableXWayland = cfg.xwayland.enable; + enableWlrPortal = lib.mkDefault false; # Hyprland has its own portal, wlr is not needed + }) + ]); imports = [ (lib.mkRemovedOptionModule @@ -95,4 +89,6 @@ in "Nvidia patches are no longer needed" ) ]; + + meta.maintainers = with lib.maintainers; [ fufexan ]; } diff --git a/nixos/modules/programs/wayland/hyprlock.nix b/nixos/modules/programs/wayland/hyprlock.nix new file mode 100644 index 0000000000000..6c60765e80cc7 --- /dev/null +++ b/nixos/modules/programs/wayland/hyprlock.nix @@ -0,0 +1,25 @@ +{ lib, pkgs, config, ... }: + +let + cfg = config.programs.hyprlock; +in +{ + options.programs.hyprlock = { + enable = lib.mkEnableOption "hyprlock, Hyprland's GPU-accelerated screen locking utility"; + package = lib.mkPackageOption pkgs "hyprlock" { }; + }; + + config = lib.mkIf cfg.enable { + environment.systemPackages = [ + cfg.package + ]; + + # Hyprlock needs Hypridle systemd service to be running to detect idle time + services.hypridle.enable = true; + + # Hyprlock needs PAM access to authenticate, else it fallbacks to su + security.pam.services.hyprlock = {}; + }; + + meta.maintainers = with lib.maintainers; [ johnrtitor ]; +} diff --git a/nixos/modules/programs/wayland/lib.nix b/nixos/modules/programs/wayland/lib.nix new file mode 100644 index 0000000000000..0f275d3f18c56 --- /dev/null +++ b/nixos/modules/programs/wayland/lib.nix @@ -0,0 +1,12 @@ +{ lib }: + +{ + genFinalPackage = pkg: args: + let + expectedArgs = with lib; + lib.naturalSort (lib.attrNames args); + existingArgs = with lib; + naturalSort (intersectLists expectedArgs (attrNames (functionArgs pkg.override))); + in + if existingArgs != expectedArgs then pkg else pkg.override args; +} diff --git a/nixos/modules/programs/wayland/river.nix b/nixos/modules/programs/wayland/river.nix index 6f8bafb155064..6391f00e2f626 100644 --- a/nixos/modules/programs/wayland/river.nix +++ b/nixos/modules/programs/wayland/river.nix @@ -1,37 +1,40 @@ -{ - config, - pkgs, - lib, - ... -}: +{ config, lib, pkgs, ... }: + let cfg = config.programs.river; -in { + + wayland-lib = import ./lib.nix { inherit lib; }; +in +{ options.programs.river = { enable = lib.mkEnableOption "river, a dynamic tiling Wayland compositor"; package = lib.mkPackageOption pkgs "river" { nullable = true; extraDescription = '' + If the package is not overridable with `xwaylandSupport`, then the module option + {option}`xwayland` will have no effect. + Set to `null` to not add any River package to your path. This should be done if you want to use the Home Manager River module to install River. ''; + } // { + apply = p: if p == null then null else + wayland-lib.genFinalPackage p { + xwaylandSupport = cfg.xwayland.enable; + }; }; + xwayland.enable = lib.mkEnableOption "XWayland" // { default = true; }; + extraPackages = lib.mkOption { type = with lib.types; listOf package; - default = with pkgs; [ - swaylock - foot - dmenu - ]; + default = with pkgs; [ swaylock foot dmenu ]; defaultText = lib.literalExpression '' with pkgs; [ swaylock foot dmenu ]; ''; example = lib.literalExpression '' - with pkgs; [ - termite rofi light - ] + with pkgs; [ termite rofi light ] ''; description = '' Extra packages to be installed system wide. See @@ -41,19 +44,22 @@ in { }; }; - config = - lib.mkIf cfg.enable (lib.mkMerge [ - { - environment.systemPackages = lib.optional (cfg.package != null) cfg.package ++ cfg.extraPackages; + config = lib.mkIf cfg.enable (lib.mkMerge [ + { + environment.systemPackages = lib.optional (cfg.package != null) cfg.package ++ cfg.extraPackages; + + # To make a river session available if a display manager like SDDM is enabled: + services.displayManager.sessionPackages = lib.optional (cfg.package != null) cfg.package; - # To make a river session available if a display manager like SDDM is enabled: - services.displayManager.sessionPackages = lib.optionals (cfg.package != null) [ cfg.package ]; + # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1050913 + xdg.portal.config.river.default = lib.mkDefault [ "wlr" "gtk" ]; + } - # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1050913 - xdg.portal.config.river.default = lib.mkDefault [ "wlr" "gtk" ]; - } - (import ./wayland-session.nix { inherit lib pkgs; }) - ]); + (import ./wayland-session.nix { + inherit lib pkgs; + enableXWayland = cfg.xwayland.enable; + }) + ]); meta.maintainers = with lib.maintainers; [ GaetanLepage ]; } diff --git a/nixos/modules/programs/wayland/sway.nix b/nixos/modules/programs/wayland/sway.nix index cec634b6b0338..e3e32aa7a56ab 100644 --- a/nixos/modules/programs/wayland/sway.nix +++ b/nixos/modules/programs/wayland/sway.nix @@ -1,52 +1,11 @@ -{ config, pkgs, lib, ... }: +{ config, lib, pkgs, ... }: let cfg = config.programs.sway; - wrapperOptions = lib.types.submodule { - options = - let - mkWrapperFeature = default: description: lib.mkOption { - type = lib.types.bool; - inherit default; - example = !default; - description = "Whether to make use of the ${description}"; - }; - in { - base = mkWrapperFeature true '' - base wrapper to execute extra session commands and prepend a - dbus-run-session to the sway command. - ''; - gtk = mkWrapperFeature false '' - wrapGAppsHook wrapper to execute sway with required environment - variables for GTK applications. - ''; - }; - }; - - genFinalPackage = pkg: - let - expectedArgs = lib.naturalSort [ - "extraSessionCommands" - "extraOptions" - "withBaseWrapper" - "withGtkWrapper" - "isNixOS" - ]; - existedArgs = with lib; - naturalSort - (intersectLists expectedArgs (attrNames (functionArgs pkg.override))); - in if existedArgs != expectedArgs then - pkg - else - pkg.override { - extraSessionCommands = cfg.extraSessionCommands; - extraOptions = cfg.extraOptions; - withBaseWrapper = cfg.wrapperFeatures.base; - withGtkWrapper = cfg.wrapperFeatures.gtk; - isNixOS = true; - }; -in { + wayland-lib = import ./lib.nix { inherit lib; }; +in +{ options.programs.sway = { enable = lib.mkEnableOption '' Sway, the i3-compatible tiling Wayland compositor. You can manually launch @@ -55,28 +14,36 @@ in { and "man 5 sway" for more information''; - package = lib.mkOption { - type = with lib.types; nullOr package; - default = pkgs.sway; - apply = p: if p == null then null else genFinalPackage p; - defaultText = lib.literalExpression "pkgs.sway"; - description = '' - Sway package to use. If the package does not contain the override arguments - `extraSessionCommands`, `extraOptions`, `withBaseWrapper`, `withGtkWrapper`, - `isNixOS`, then the module options {option}`wrapperFeatures`, - {option}`wrapperFeatures` and {option}`wrapperFeatures` will have no effect. - Set to `null` to not add any Sway package to your path. This should be done if - you want to use the Home Manager Sway module to install Sway. + package = lib.mkPackageOption pkgs "sway" { + nullable = true; + extraDescription = '' + If the package is not overridable with `extraSessionCommands`, `extraOptions`, + `withBaseWrapper`, `withGtkWrapper`, `enableXWayland` and `isNixOS`, + then the module options {option}`wrapperFeatures`, {option}`extraSessionCommands`, + {option}`extraOptions` and {option}`xwayland` will have no effect. + + Set to `null` to not add any Sway package to your path. + This should be done if you want to use the Home Manager Sway module to install Sway. ''; + } // { + apply = p: if p == null then null else + wayland-lib.genFinalPackage p { + extraSessionCommands = cfg.extraSessionCommands; + extraOptions = cfg.extraOptions; + withBaseWrapper = cfg.wrapperFeatures.base; + withGtkWrapper = cfg.wrapperFeatures.gtk; + enableXWayland = cfg.xwayland.enable; + isNixOS = true; + }; }; - wrapperFeatures = lib.mkOption { - type = wrapperOptions; - default = { }; - example = { gtk = true; }; - description = '' - Attribute set of features to enable in the wrapper. - ''; + wrapperFeatures = { + base = lib.mkEnableOption '' + the base wrapper to execute extra session commands and prepend a + dbus-run-session to the sway command'' // { default = true; }; + gtk = lib.mkEnableOption '' + the wrapGAppsHook wrapper to execute sway with required environment + variables for GTK applications''; }; extraSessionCommands = lib.mkOption { @@ -114,19 +81,16 @@ in { ''; }; + xwayland.enable = lib.mkEnableOption "XWayland" // { default = true; }; + extraPackages = lib.mkOption { type = with lib.types; listOf package; - default = with pkgs; [ - swaylock swayidle foot dmenu wmenu - ]; + default = with pkgs; [ swaylock swayidle foot dmenu wmenu ]; defaultText = lib.literalExpression '' with pkgs; [ swaylock swayidle foot dmenu wmenu ]; ''; example = lib.literalExpression '' - with pkgs; [ - i3status i3status-rust - termite rofi light - ] + with pkgs; [ i3status i3status-rust termite rofi light ] ''; description = '' Extra packages to be installed system wide. See @@ -135,46 +99,50 @@ in { for a list of useful software. ''; }; - }; - config = lib.mkIf cfg.enable - (lib.mkMerge [ - { - assertions = [ - { - assertion = cfg.extraSessionCommands != "" -> cfg.wrapperFeatures.base; - message = '' - The extraSessionCommands for Sway will not be run if - wrapperFeatures.base is disabled. - ''; - } - ]; - - environment = { - systemPackages = lib.optional (cfg.package != null) cfg.package ++ cfg.extraPackages; - # Needed for the default wallpaper: - pathsToLink = lib.optionals (cfg.package != null) [ "/share/backgrounds/sway" ]; - etc = { - "sway/config.d/nixos.conf".source = pkgs.writeText "nixos.conf" '' - # Import the most important environment variables into the D-Bus and systemd - # user environments (e.g. required for screen sharing and Pinentry prompts): - exec dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP - ''; - } // lib.optionalAttrs (cfg.package != null) { - "sway/config".source = lib.mkOptionDefault "${cfg.package}/etc/sway/config"; - }; + config = lib.mkIf cfg.enable (lib.mkMerge [ + { + assertions = [ + { + assertion = cfg.extraSessionCommands != "" -> cfg.wrapperFeatures.base; + message = '' + The extraSessionCommands for Sway will not be run if wrapperFeatures.base is disabled. + ''; + } + ]; + + environment = { + systemPackages = lib.optional (cfg.package != null) cfg.package ++ cfg.extraPackages; + + # Needed for the default wallpaper: + pathsToLink = lib.optional (cfg.package != null) "/share/backgrounds/sway"; + + etc = { + "sway/config.d/nixos.conf".source = pkgs.writeText "nixos.conf" '' + # Import the most important environment variables into the D-Bus and systemd + # user environments (e.g. required for screen sharing and Pinentry prompts): + exec dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY SWAYSOCK XDG_CURRENT_DESKTOP + ''; + } // lib.optionalAttrs (cfg.package != null) { + "sway/config".source = lib.mkOptionDefault "${cfg.package}/etc/sway/config"; }; + }; + + programs.gnupg.agent.pinentryPackage = lib.mkDefault pkgs.pinentry-gnome3; - programs.gnupg.agent.pinentryPackage = lib.mkDefault pkgs.pinentry-gnome3; + # To make a Sway session available if a display manager like SDDM is enabled: + services.displayManager.sessionPackages = lib.optional (cfg.package != null) cfg.package; - # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1050913 - xdg.portal.config.sway.default = lib.mkDefault [ "wlr" "gtk" ]; + # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1050913 + xdg.portal.config.sway.default = lib.mkDefault [ "wlr" "gtk" ]; + } - # To make a Sway session available if a display manager like SDDM is enabled: - services.displayManager.sessionPackages = lib.optionals (cfg.package != null) [ cfg.package ]; } - (import ./wayland-session.nix { inherit lib pkgs; }) - ]); + (import ./wayland-session.nix { + inherit lib pkgs; + enableXWayland = cfg.xwayland.enable; + }) + ]); meta.maintainers = with lib.maintainers; [ primeos colemickens ]; } diff --git a/nixos/modules/programs/wayland/wayland-session.nix b/nixos/modules/programs/wayland/wayland-session.nix index 47ee0788e0f38..877b106684700 100644 --- a/nixos/modules/programs/wayland/wayland-session.nix +++ b/nixos/modules/programs/wayland/wayland-session.nix @@ -1,23 +1,27 @@ -{ lib, pkgs, ... }: { - security = { - polkit.enable = true; - pam.services.swaylock = {}; - }; +{ + lib, + pkgs, + enableXWayland ? true, + enableWlrPortal ? true, +}: - hardware.opengl.enable = lib.mkDefault true; - fonts.enableDefaultPackages = lib.mkDefault true; +{ + security = { + polkit.enable = true; + pam.services.swaylock = {}; + }; - programs = { - dconf.enable = lib.mkDefault true; - xwayland.enable = lib.mkDefault true; - }; + hardware.opengl.enable = lib.mkDefault true; + fonts.enableDefaultPackages = lib.mkDefault true; - xdg.portal = { - enable = lib.mkDefault true; + programs = { + dconf.enable = lib.mkDefault true; + xwayland.enable = lib.mkDefault enableXWayland; + }; - extraPortals = [ - # For screen sharing - pkgs.xdg-desktop-portal-wlr - ]; - }; + xdg.portal.wlr.enable = enableWlrPortal; + + # Window manager only sessions (unlike DEs) don't handle XDG + # autostart files, so force them to run the service + services.xserver.desktopManager.runXdgAutostartIfNone = lib.mkDefault true; } diff --git a/nixos/modules/programs/yazi.nix b/nixos/modules/programs/yazi.nix index 5905f2afb946d..d9f38d8d81185 100644 --- a/nixos/modules/programs/yazi.nix +++ b/nixos/modules/programs/yazi.nix @@ -5,7 +5,7 @@ let settingsFormat = pkgs.formats.toml { }; - names = [ "yazi" "theme" "keymap" ]; + files = [ "yazi" "theme" "keymap" ]; in { options.programs.yazi = { @@ -15,7 +15,7 @@ in settings = lib.mkOption { type = with lib.types; submodule { - options = lib.listToAttrs (map + options = (lib.listToAttrs (map (name: lib.nameValuePair name (lib.mkOption { inherit (settingsFormat) type; default = { }; @@ -25,26 +25,65 @@ in See https://yazi-rs.github.io/docs/configuration/${name}/ for documentation. ''; })) - names); + files)); }; default = { }; description = '' Configuration included in `$YAZI_CONFIG_HOME`. ''; }; + + initLua = lib.mkOption { + type = with lib.types; nullOr path; + default = null; + description = '' + The init.lua for Yazi itself. + ''; + example = lib.literalExpression "./init.lua"; + }; + + plugins = lib.mkOption { + type = with lib.types; attrsOf (oneOf [ path package ]); + default = { }; + description = '' + Lua plugins. + + See https://yazi-rs.github.io/docs/plugins/overview/ for documentation. + ''; + example = lib.literalExpression '' + { + foo = ./foo; + bar = pkgs.bar; + } + ''; + }; + + flavors = lib.mkOption { + type = with lib.types; attrsOf (oneOf [ path package ]); + default = { }; + description = '' + Pre-made themes. + + See https://yazi-rs.github.io/docs/flavors/overview/ for documentation. + ''; + example = lib.literalExpression '' + { + foo = ./foo; + bar = pkgs.bar; + } + ''; + }; + }; config = lib.mkIf cfg.enable { - environment = { - systemPackages = [ cfg.package ]; - variables.YAZI_CONFIG_HOME = "/etc/yazi/"; - etc = lib.attrsets.mergeAttrsList (map - (name: lib.optionalAttrs (cfg.settings.${name} != { }) { - "yazi/${name}.toml".source = settingsFormat.generate "${name}.toml" cfg.settings.${name}; - }) - names); - }; + environment.systemPackages = [ + (cfg.package.override { + inherit (cfg) settings initLua plugins flavors; + }) + ]; }; + meta = { maintainers = with lib.maintainers; [ linsui ]; }; diff --git a/nixos/modules/programs/ydotool.nix b/nixos/modules/programs/ydotool.nix index f639e9283de42..643a5d369f3fc 100644 --- a/nixos/modules/programs/ydotool.nix +++ b/nixos/modules/programs/ydotool.nix @@ -14,23 +14,32 @@ in options.programs.ydotool = { enable = lib.mkEnableOption '' - ydotoold system service and install ydotool. - Add yourself to the 'ydotool' group to be able to use it. + ydotoold system service and {command}`ydotool` for members of + {option}`programs.ydotool.group`. ''; + group = lib.mkOption { + type = lib.types.str; + default = "ydotool"; + description = '' + Group which users must be in to use {command}`ydotool`. + ''; + }; }; - config = lib.mkIf cfg.enable { - users.groups.ydotool = { }; + config = let + runtimeDirectory = "ydotoold"; + in lib.mkIf cfg.enable { + users.groups."${config.programs.ydotool.group}" = { }; systemd.services.ydotoold = { description = "ydotoold - backend for ydotool"; wantedBy = [ "multi-user.target" ]; partOf = [ "multi-user.target" ]; serviceConfig = { - Group = "ydotool"; - RuntimeDirectory = "ydotoold"; + Group = config.programs.ydotool.group; + RuntimeDirectory = runtimeDirectory; RuntimeDirectoryMode = "0750"; - ExecStart = "${lib.getExe' pkgs.ydotool "ydotoold"} --socket-path=/run/ydotoold/socket --socket-perm=0660"; + ExecStart = "${lib.getExe' pkgs.ydotool "ydotoold"} --socket-path=${config.environment.variables.YDOTOOL_SOCKET} --socket-perm=0660"; # hardening @@ -76,7 +85,7 @@ in }; environment.variables = { - YDOTOOL_SOCKET = "/run/ydotoold/socket"; + YDOTOOL_SOCKET = "/run/${runtimeDirectory}/socket"; }; environment.systemPackages = with pkgs; [ ydotool ]; }; diff --git a/nixos/modules/rename.nix b/nixos/modules/rename.nix index 01985995a651d..d4661a19188c8 100644 --- a/nixos/modules/rename.nix +++ b/nixos/modules/rename.nix @@ -40,12 +40,16 @@ in (mkRemovedOptionModule [ "networking" "vpnc" ] "Use environment.etc.\"vpnc/service.conf\" instead.") (mkRemovedOptionModule [ "networking" "wicd" ] "The corresponding package was removed from nixpkgs.") (mkRemovedOptionModule [ "programs" "gnome-documents" ] "The corresponding package was removed from nixpkgs.") + (mkRemovedOptionModule [ "programs" "pantheon-tweaks" ] '' + pantheon-tweaks is no longer a switchboard plugin but an independent app, + adding the package to environment.systemPackages is sufficient. + '') (mkRemovedOptionModule [ "programs" "tilp2" ] "The corresponding package was removed from nixpkgs.") (mkRemovedOptionModule [ "programs" "way-cooler" ] ("way-cooler is abandoned by its author: " + "https://way-cooler.org/blog/2020/01/09/way-cooler-post-mortem.html")) (mkRemovedOptionModule [ "security" "hideProcessInformation" ] '' - The hidepid module was removed, since the underlying machinery - is broken when using cgroups-v2. + The hidepid module was removed, since the underlying machinery + is broken when using cgroups-v2. '') (mkRemovedOptionModule [ "services" "baget" "enable" ] "The baget module was removed due to the upstream package being unmaintained.") (mkRemovedOptionModule [ "services" "beegfs" ] "The BeeGFS module has been removed") diff --git a/nixos/modules/security/acme/default.nix b/nixos/modules/security/acme/default.nix index 5ffafdc37fefb..83581d02840ed 100644 --- a/nixos/modules/security/acme/default.nix +++ b/nixos/modules/security/acme/default.nix @@ -545,7 +545,7 @@ let }; server = mkOption { - type = types.str; + type = types.nullOr types.str; inherit (defaultAndText "server" "https://acme-v02.api.letsencrypt.org/directory") default defaultText; example = "https://acme-staging-v02.api.letsencrypt.org/directory"; description = '' diff --git a/nixos/modules/security/krb5/default.nix b/nixos/modules/security/krb5/default.nix index 78426c07cbc98..6714c41d8a07c 100644 --- a/nixos/modules/security/krb5/default.nix +++ b/nixos/modules/security/krb5/default.nix @@ -77,8 +77,22 @@ in { }; }; - config = mkIf cfg.enable { - environment = { + config = { + assertions = mkIf (cfg.enable || config.services.kerberos_server.enable) [(let + implementation = cfg.package.passthru.implementation or ""; + in { + assertion = lib.elem implementation [ "krb5" "heimdal" ]; + message = '' + `security.krb5.package` must be one of: + + - krb5 + - heimdal + + Currently chosen implementation: ${implementation} + ''; + })]; + + environment = mkIf cfg.enable { systemPackages = [ cfg.package ]; etc."krb5.conf".source = format.generate "krb5.conf" cfg.settings; }; diff --git a/nixos/modules/security/krb5/krb5-conf-format.nix b/nixos/modules/security/krb5/krb5-conf-format.nix index 5a6bbed9fd188..3e5e64ae0cb04 100644 --- a/nixos/modules/security/krb5/krb5-conf-format.nix +++ b/nixos/modules/security/krb5/krb5-conf-format.nix @@ -7,17 +7,61 @@ let inherit (lib) boolToString concatMapStringsSep concatStringsSep filter isAttrs isBool isList mapAttrsToList mkOption singleton splitString; - inherit (lib.types) attrsOf bool coercedTo either int listOf oneOf path - str submodule; + inherit (lib.types) attrsOf bool coercedTo either enum int listOf oneOf + path str submodule; in -{ }: { - type = let - section = attrsOf relation; - relation = either (attrsOf value) value; +{ + enableKdcACLEntries ? false +}: rec { + sectionType = let + relation = oneOf [ + (listOf (attrsOf value)) + (attrsOf value) + value + ]; value = either (listOf atom) atom; atom = oneOf [int str bool]; + in attrsOf relation; + + type = let + aclEntry = submodule { + options = { + principal = mkOption { + type = str; + description = "Which principal the rule applies to"; + }; + access = mkOption { + type = either + (listOf (enum ["add" "cpw" "delete" "get" "list" "modify"])) + (enum ["all"]); + default = "all"; + description = "The changes the principal is allowed to make."; + }; + target = mkOption { + type = str; + default = "*"; + description = "The principals that 'access' applies to."; + }; + }; + }; + + realm = submodule ({ name, ... }: { + freeformType = sectionType; + options = { + acl = mkOption { + type = listOf aclEntry; + default = [ + { principal = "*/admin"; access = "all"; } + { principal = "admin"; access = "all"; } + ]; + description = '' + The privileges granted to a user. + ''; + }; + }; + }); in submodule { - freeformType = attrsOf section; + freeformType = attrsOf sectionType; options = { include = mkOption { default = [ ]; @@ -40,7 +84,17 @@ in ''; type = coercedTo path singleton (listOf path); }; - }; + + } + // + (lib.optionalAttrs enableKdcACLEntries { + realms = mkOption { + type = attrsOf realm; + description = '' + The realm(s) to serve keys for. + ''; + }; + }); }; generate = let @@ -71,6 +125,9 @@ in ${name} = { ${indent (concatStringsSep "\n" (mapAttrsToList formatValue relation))} }'' + else if isList relation + then + concatMapStringsSep "\n" (formatRelation name) relation else formatValue name relation; formatValue = name: value: diff --git a/nixos/modules/services/admin/pgadmin.nix b/nixos/modules/services/admin/pgadmin.nix index ead0c3c6c9a34..b3dd3c78874c2 100644 --- a/nixos/modules/services/admin/pgadmin.nix +++ b/nixos/modules/services/admin/pgadmin.nix @@ -152,7 +152,8 @@ in # Check here for password length to prevent pgadmin from starting # and presenting a hard to find error message # see https://github.com/NixOS/nixpkgs/issues/270624 - PW_LENGTH=$(wc -m < ${escapeShellArg cfg.initialPasswordFile}) + PW_FILE="$CREDENTIALS_DIRECTORY/initial_password" + PW_LENGTH=$(wc -m < "$PW_FILE") if [ $PW_LENGTH -lt ${toString cfg.minimumPasswordLength} ]; then echo "Password must be at least ${toString cfg.minimumPasswordLength} characters long" exit 1 @@ -162,7 +163,7 @@ in echo ${escapeShellArg cfg.initialEmail} # file might not contain newline. echo hack fixes that. - PW=$(cat ${escapeShellArg cfg.initialPasswordFile}) + PW=$(cat "$PW_FILE") # Password: echo "$PW" @@ -181,6 +182,8 @@ in LogsDirectory = "pgadmin"; StateDirectory = "pgadmin"; ExecStart = "${cfg.package}/bin/pgadmin4"; + LoadCredential = [ "initial_password:${cfg.initialPasswordFile}" ] + ++ optional cfg.emailServer.enable "email_password:${cfg.emailServer.passwordFile}"; }; }; @@ -193,7 +196,8 @@ in environment.etc."pgadmin/config_system.py" = { text = lib.optionalString cfg.emailServer.enable '' - with open("${cfg.emailServer.passwordFile}") as f: + import os + with open(os.path.join(os.environ['CREDENTIALS_DIRECTORY'], 'email_password')) as f: pw = f.read() MAIL_PASSWORD = pw '' + formatPy cfg.settings; diff --git a/nixos/modules/services/audio/alsa.nix b/nixos/modules/services/audio/alsa.nix index e53da4b64e7bc..b002cb1274ac3 100644 --- a/nixos/modules/services/audio/alsa.nix +++ b/nixos/modules/services/audio/alsa.nix @@ -106,7 +106,8 @@ in serviceConfig = { Type = "oneshot"; RemainAfterExit = true; - ExecStart = "${pkgs.coreutils}/bin/mkdir -p /var/lib/alsa"; + ExecStartPre = "${pkgs.coreutils}/bin/mkdir -p /var/lib/alsa"; + ExecStart = "${alsa-utils}/sbin/alsactl restore --ignore"; ExecStop = "${alsa-utils}/sbin/alsactl store --ignore"; }; }; diff --git a/nixos/modules/services/audio/mopidy.nix b/nixos/modules/services/audio/mopidy.nix index 1d6c45b64a16c..198ca74359dc1 100644 --- a/nixos/modules/services/audio/mopidy.nix +++ b/nixos/modules/services/audio/mopidy.nix @@ -78,6 +78,7 @@ in { systemd.services.mopidy = { wantedBy = [ "multi-user.target" ]; after = [ "network-online.target" "sound.target" ]; + wants = [ "network-online.target" ]; description = "mopidy music player daemon"; serviceConfig = { ExecStart = "${mopidyEnv}/bin/mopidy --config ${concatStringsSep ":" ([mopidyConf] ++ cfg.extraConfigFiles)}"; diff --git a/nixos/modules/services/audio/navidrome.nix b/nixos/modules/services/audio/navidrome.nix index ca1cd6ca43af0..06d2d174a4df3 100644 --- a/nixos/modules/services/audio/navidrome.nix +++ b/nixos/modules/services/audio/navidrome.nix @@ -6,8 +6,18 @@ }: let - inherit (lib) mkEnableOption mkPackageOption mkOption maintainers; - inherit (lib.types) bool str; + inherit (lib) + mkEnableOption + mkPackageOption + mkOption + maintainers + ; + inherit (lib.types) + bool + port + str + submodule + ; cfg = config.services.navidrome; settingsFormat = pkgs.formats.json { }; in @@ -20,11 +30,24 @@ in package = mkPackageOption pkgs "navidrome" { }; settings = mkOption { - type = settingsFormat.type; - default = { - Address = "127.0.0.1"; - Port = 4533; + type = submodule { + freeformType = settingsFormat.type; + + options = { + Address = mkOption { + default = "127.0.0.1"; + description = "Address to run Navidrome on."; + type = str; + }; + + Port = mkOption { + default = 4533; + description = "Port to run Navidrome on."; + type = port; + }; + }; }; + default = { }; example = { MusicFolder = "/mnt/music"; }; @@ -134,5 +157,5 @@ in networking.firewall.allowedTCPPorts = mkIf cfg.openFirewall [ cfg.settings.Port ]; }; - meta.maintainers = with maintainers; [ nu-nu-ko ]; + meta.maintainers = with maintainers; [ fsnkty ]; } diff --git a/nixos/modules/services/backup/borgbackup.nix b/nixos/modules/services/backup/borgbackup.nix index 04f971008073e..a3c0715c9e607 100644 --- a/nixos/modules/services/backup/borgbackup.nix +++ b/nixos/modules/services/backup/borgbackup.nix @@ -361,7 +361,7 @@ in { type = types.bool; example = true; description = '' - Set the `persistentTimer` option for the + Set the `Persistent` option for the {manpage}`systemd.timer(5)` which triggers the backup immediately if the last trigger was missed (e.g. if the system was powered down). diff --git a/nixos/modules/services/cluster/rke2/default.nix b/nixos/modules/services/cluster/rke2/default.nix new file mode 100644 index 0000000000000..9ddbd299fdf8d --- /dev/null +++ b/nixos/modules/services/cluster/rke2/default.nix @@ -0,0 +1,311 @@ +{ config, lib, pkgs, ... }: + +with lib; +let + cfg = config.services.rke2; +in +{ + imports = [ ]; + + options.services.rke2 = { + enable = mkEnableOption "rke2"; + + package = mkPackageOption pkgs "rke2" { }; + + role = mkOption { + type = types.enum [ "server" "agent" ]; + description = '' + Whether rke2 should run as a server or agent. + + If it's a server: + + - By default it also runs workloads as an agent. + - any optionals is allowed. + + If it's an agent: + + - `serverAddr` is required. + - `token` or `tokenFile` is required. + - `agentToken` or `agentTokenFile` or `disable` or `cni` are not allowed. + ''; + default = "server"; + }; + + configPath = mkOption { + type = types.path; + description = "Load configuration from FILE."; + default = "/etc/rancher/rke2/config.yaml"; + }; + + debug = mkOption { + type = types.bool; + description = "Turn on debug logs."; + default = false; + }; + + dataDir = mkOption { + type = types.path; + description = "The folder to hold state in."; + default = "/var/lib/rancher/rke2"; + }; + + token = mkOption { + type = types.str; + description = '' + Shared secret used to join a server or agent to a cluster. + + > WARNING: This option will expose store your token unencrypted world-readable in the nix store. + If this is undesired use the `tokenFile` option instead. + ''; + default = ""; + }; + + tokenFile = mkOption { + type = types.nullOr types.path; + description = "File path containing rke2 token to use when connecting to the server."; + default = null; + }; + + disable = mkOption { + type = types.listOf types.str; + description = "Do not deploy packaged components and delete any deployed components."; + default = [ ]; + }; + + nodeName = mkOption { + type = types.nullOr types.str; + description = "Node name."; + default = null; + }; + + nodeLabel = mkOption { + type = types.listOf types.str; + description = "Registering and starting kubelet with set of labels."; + default = [ ]; + }; + + nodeTaint = mkOption { + type = types.listOf types.str; + description = "Registering kubelet with set of taints."; + default = [ ]; + }; + + nodeIP = mkOption { + type = types.nullOr types.str; + description = "IPv4/IPv6 addresses to advertise for node."; + default = null; + }; + + agentToken = mkOption { + type = types.str; + description = '' + Shared secret used to join agents to the cluster, but not servers. + + > **WARNING**: This option will expose store your token unencrypted world-readable in the nix store. + If this is undesired use the `agentTokenFile` option instead. + ''; + default = ""; + }; + + agentTokenFile = mkOption { + type = types.nullOr types.path; + description = "File path containing rke2 agent token to use when connecting to the server."; + default = null; + }; + + serverAddr = mkOption { + type = types.str; + description = "The rke2 server to connect to, used to join a cluster."; + example = "https://10.0.0.10:6443"; + default = ""; + }; + + selinux = mkOption { + type = types.bool; + description = "Enable SELinux in containerd."; + default = false; + }; + + cni = mkOption { + type = types.enum [ "none" "canal" "cilium" "calico" "flannel" ]; + description = '' + CNI Plugins to deploy, one of `none`, `calico`, `canal`, `cilium` or `flannel`. + + All CNI plugins get installed via a helm chart after the main components are up and running + and can be [customized by modifying the helm chart options](https://docs.rke2.io/helm). + + [Learn more about RKE2 and CNI plugins](https://docs.rke2.io/networking/basic_network_options) + + > **WARNING**: Flannel support in RKE2 is currently experimental. + ''; + default = "canal"; + }; + + cisHardening = mkOption { + type = types.bool; + description = '' + Enable CIS Hardening for RKE2. + + It will set the configurations and controls required to address Kubernetes benchmark controls + from the Center for Internet Security (CIS). + + Learn more about [CIS Hardening for RKE2](https://docs.rke2.io/security/hardening_guide). + + > **NOTICE**: + > + > You may need restart the `systemd-sysctl` muaually by: + > + > ```shell + > sudo systemctl restart systemd-sysctl + > ``` + ''; + default = false; + }; + + extraFlags = mkOption { + type = types.listOf types.str; + description = '' + Extra flags to pass to the rke2 service/agent. + + Here you can find all the available flags: + + - [Server Configuration Reference](https://docs.rke2.io/reference/server_config) + - [Agent Configuration Reference](https://docs.rke2.io/reference/linux_agent_config) + ''; + example = [ "--disable-kube-proxy" "--cluster-cidr=10.24.0.0/16" ]; + default = [ ]; + }; + + environmentVars = mkOption { + type = types.attrsOf types.str; + description = '' + Environment variables for configuring the rke2 service/agent. + + Here you can find all the available environment variables: + + - [Server Configuration Reference](https://docs.rke2.io/reference/server_config) + - [Agent Configuration Reference](https://docs.rke2.io/reference/linux_agent_config) + + Besides the options above, you can also active environment variables by edit/create those files: + + - `/etc/default/rke2` + - `/etc/sysconfig/rke2` + - `/usr/local/lib/systemd/system/rke2.env` + ''; + # See: https://github.com/rancher/rke2/blob/master/bundle/lib/systemd/system/rke2-server.env#L1 + default = { + HOME = "/root"; + }; + }; + }; + + config = mkIf cfg.enable { + assertions = [ + { + assertion = cfg.role == "agent" -> (builtins.pathExists cfg.configPath || cfg.serverAddr != ""); + message = "serverAddr or configPath (with 'server' key) should be set if role is 'agent'"; + } + { + assertion = cfg.role == "agent" -> (builtins.pathExists cfg.configPath || cfg.tokenFile != null || cfg.token != ""); + message = "token or tokenFile or configPath (with 'token' or 'token-file' keys) should be set if role is 'agent'"; + } + { + assertion = cfg.role == "agent" -> ! (cfg.agentTokenFile != null || cfg.agentToken != ""); + message = "agentToken or agentTokenFile should be set if role is 'agent'"; + } + { + assertion = cfg.role == "agent" -> ! (cfg.disable != [ ]); + message = "disable should not be set if role is 'agent'"; + } + { + assertion = cfg.role == "agent" -> ! (cfg.cni != "canal"); + message = "cni should not be set if role is 'agent'"; + } + ]; + + environment.systemPackages = [ config.services.rke2.package ]; + # To configure NetworkManager to ignore calico/flannel related network interfaces. + # See: https://docs.rke2.io/known_issues#networkmanager + environment.etc."NetworkManager/conf.d/rke2-canal.conf" = { + enable = config.networking.networkmanager.enable; + text = '' + [keyfile] + unmanaged-devices=interface-name:cali*;interface-name:flannel* + ''; + }; + # See: https://docs.rke2.io/security/hardening_guide#set-kernel-parameters + boot.kernel.sysctl = mkIf cfg.cisHardening { + "vm.panic_on_oom" = 0; + "vm.overcommit_memory" = 1; + "kernel.panic" = 10; + "kernel.panic_on_oops" = 1; + }; + + systemd.services.rke2 = { + description = "Rancher Kubernetes Engine v2"; + documentation = [ "https://github.com/rancher/rke2#readme" ]; + after = [ "network-online.target" ]; + wants = [ "network-online.target" ]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = if cfg.role == "agent" then "exec" else "notify"; + EnvironmentFile = [ + "-/etc/default/%N" + "-/etc/sysconfig/%N" + "-/usr/local/lib/systemd/system/%N.env" + ]; + Environment = mapAttrsToList (k: v: "${k}=${v}") cfg.environmentVars; + KillMode = "process"; + Delegate = "yes"; + LimitNOFILE = 1048576; + LimitNPROC = "infinity"; + LimitCORE = "infinity"; + TasksMax = "infinity"; + TimeoutStartSec = 0; + Restart = "always"; + RestartSec = "5s"; + ExecStartPre = [ + # There is a conflict between RKE2 and `nm-cloud-setup.service`. This service add a routing table that + # interfere with the CNI plugin's configuration. This script checks if the service is enabled and if so, + # failed the RKE2 start. + # See: https://github.com/rancher/rke2/issues/1053 + (pkgs.writeScript "check-nm-cloud-setup.sh" '' + #! ${pkgs.runtimeShell} + set -x + ! /run/current-system/systemd/bin/systemctl is-enabled --quiet nm-cloud-setup.service + '') + "-${pkgs.kmod}/bin/modprobe br_netfilter" + "-${pkgs.kmod}/bin/modprobe overlay" + ]; + ExecStart = "${cfg.package}/bin/rke2 '${cfg.role}' ${escapeShellArgs ( + (optional (cfg.configPath != "/etc/rancher/rke2/config.yaml") "--config=${cfg.configPath}") + ++ (optional cfg.debug "--debug") + ++ (optional (cfg.dataDir != "/var/lib/rancher/rke2") "--data-dir=${cfg.dataDir}") + ++ (optional (cfg.token != "") "--token=${cfg.token}") + ++ (optional (cfg.tokenFile != null) "--token-file=${cfg.tokenFile}") + ++ (optionals (cfg.role == "server" && cfg.disable != [ ]) (map (d: "--disable=${d}") cfg.disable)) + ++ (optional (cfg.nodeName != null) "--node-name=${cfg.nodeName}") + ++ (optionals (cfg.nodeLabel != [ ]) (map (l: "--node-label=${l}") cfg.nodeLabel)) + ++ (optionals (cfg.nodeTaint != [ ]) (map (t: "--node-taint=${t}") cfg.nodeTaint)) + ++ (optional (cfg.nodeIP != null) "--node-ip=${cfg.nodeIP}") + ++ (optional (cfg.role == "server" && cfg.agentToken != "") "--agent-token=${cfg.agentToken}") + ++ (optional (cfg.role == "server" && cfg.agentTokenFile != null) "--agent-token-file=${cfg.agentTokenFile}") + ++ (optional (cfg.serverAddr != "") "--server=${cfg.serverAddr}") + ++ (optional cfg.selinux "--selinux") + ++ (optional (cfg.role == "server" && cfg.cni != "canal") "--cni=${cfg.cni}") + ++ (optional cfg.cisHardening "--profile=${if cfg.package.version >= "1.25" then "cis-1.23" else "cis-1.6"}") + ++ cfg.extraFlags + )}"; + ExecStopPost = let + killProcess = pkgs.writeScript "kill-process.sh" '' + #! ${pkgs.runtimeShell} + /run/current-system/systemd/bin/systemd-cgls /system.slice/$1 | \ + ${pkgs.gnugrep}/bin/grep -Eo '[0-9]+ (containerd|kubelet)' | \ + ${pkgs.gawk}/bin/awk '{print $1}' | \ + ${pkgs.findutils}/bin/xargs -r ${pkgs.util-linux}/bin/kill + ''; + in "-${killProcess} %n"; + }; + }; + }; +} diff --git a/nixos/modules/services/continuous-integration/hydra/default.nix b/nixos/modules/services/continuous-integration/hydra/default.nix index 23f07eb64b92d..b516c3d6192cb 100644 --- a/nixos/modules/services/continuous-integration/hydra/default.nix +++ b/nixos/modules/services/continuous-integration/hydra/default.nix @@ -335,7 +335,7 @@ in mkdir -m 0700 -p ${baseDir}/queue-runner mkdir -m 0750 -p ${baseDir}/build-logs mkdir -m 0750 -p ${baseDir}/runcommand-logs - chown hydra-queue-runner.hydra \ + chown hydra-queue-runner:hydra \ ${baseDir}/queue-runner \ ${baseDir}/build-logs \ ${baseDir}/runcommand-logs diff --git a/nixos/modules/services/desktop-managers/lomiri.nix b/nixos/modules/services/desktop-managers/lomiri.nix index e11867b691071..eec33597dc711 100644 --- a/nixos/modules/services/desktop-managers/lomiri.nix +++ b/nixos/modules/services/desktop-managers/lomiri.nix @@ -22,6 +22,7 @@ in { libusermetrics lomiri lomiri-download-manager + lomiri-filemanager-app lomiri-schemas # exposes some required dbus interfaces lomiri-session # wrappers to properly launch the session lomiri-sounds @@ -34,10 +35,15 @@ in { morph-browser qtmir # not having its desktop file for Xwayland available causes any X11 application to crash the session suru-icon-theme - telephony-service + # telephony-service # currently broken: https://github.com/NixOS/nixpkgs/pull/314043 ]); + variables = { + # To override the keyboard layouts in Lomiri + NIXOS_XKB_LAYOUTS = config.services.xserver.xkb.layout; + }; }; + hardware.pulseaudio.enable = lib.mkDefault true; networking.networkmanager.enable = lib.mkDefault true; systemd.packages = with pkgs.lomiri; [ @@ -71,10 +77,14 @@ in { enable = true; packages = (with pkgs; [ ayatana-indicator-datetime + ayatana-indicator-display ayatana-indicator-messages + ayatana-indicator-power ayatana-indicator-session + ] ++ lib.optionals (config.hardware.pulseaudio.enable || config.services.pipewire.pulse.enable) [ + ayatana-indicator-sound ]) ++ (with pkgs.lomiri; [ - telephony-service + # telephony-service # currently broken: https://github.com/NixOS/nixpkgs/pull/314043 ] ++ lib.optionals config.networking.networkmanager.enable [ lomiri-indicator-network ]); diff --git a/nixos/modules/services/desktop-managers/plasma6.nix b/nixos/modules/services/desktop-managers/plasma6.nix index 842b0716b928d..5bae328accde6 100644 --- a/nixos/modules/services/desktop-managers/plasma6.nix +++ b/nixos/modules/services/desktop-managers/plasma6.nix @@ -60,10 +60,8 @@ in { qt.enable = true; environment.systemPackages = with kdePackages; let requiredPackages = [ - # Hack? To make everything run on Wayland - qtwayland - # Needed to render SVG icons - qtsvg + qtwayland # Hack? To make everything run on Wayland + qtsvg # Needed to render SVG icons # Frameworks with globally loadable bits frameworkintegration # provides Qt plugin @@ -75,6 +73,9 @@ in { kiconthemes # provides Qt plugins kimageformats # provides Qt plugins kio # provides helper service + a bunch of other stuff + kio-admin # managing files as admin + kio-extras # stuff for MTP, AFC, etc + kio-fuse # fuse interface for KIO kpackage # provides kpackagetool tool kservice # provides kbuildsycoca6 tool kwallet # provides helper service @@ -87,30 +88,26 @@ in { # Core Plasma parts kwin pkgs.xwayland - kscreen libkscreen - kscreenlocker - kactivitymanagerd kde-cli-tools - kglobalacceld + kglobalacceld # keyboard shortcut daemon kwrited # wall message proxy, not to be confused with kwrite - - milou - polkit-kde-agent-1 - + baloo # system indexer + milou # search engine atop baloo + kdegraphics-thumbnailers # pdf etc thumbnailer + polkit-kde-agent-1 # polkit auth ui plasma-desktop plasma-workspace - - # Crash handler - drkonqi + drkonqi # crash handler + kde-inotify-survey # warns the user on low inotifywatch limits # Application integration libplasma # provides Kirigami platform theme plasma-integration # provides Qt platform theme - kde-gtk-config + kde-gtk-config # syncs KDE settings to GTK # Artwork + themes breeze @@ -124,44 +121,31 @@ in { # misc Plasma extras kdeplasma-addons - pkgs.xdg-user-dirs # recommended upstream # Plasma utilities kmenuedit - kinfocenter plasma-systemmonitor ksystemstats libksysguard - - spectacle systemsettings kcmutils - - # Gear - baloo - dolphin - dolphin-plugins - ffmpegthumbs - kdegraphics-thumbnailers - kde-inotify-survey - kio-admin - kio-extras - kio-fuse ]; optionalPackages = [ plasma-browser-integration konsole (lib.getBin qttools) # Expose qdbus in PATH - ark elisa gwenview okular kate khelpcenter - print-manager + dolphin + dolphin-plugins + spectacle + ffmpegthumbs ]; in requiredPackages @@ -183,12 +167,13 @@ in { ) kio-extras-kf5 ] - # Optional hardware support features + # Optional and hardware support features ++ lib.optionals config.hardware.bluetooth.enable [bluedevil bluez-qt pkgs.openobex pkgs.obexftp] ++ lib.optional config.networking.networkmanager.enable plasma-nm ++ lib.optional config.hardware.pulseaudio.enable plasma-pa ++ lib.optional config.services.pipewire.pulse.enable plasma-pa ++ lib.optional config.powerManagement.enable powerdevil + ++ lib.optional config.services.printing.enable print-manager ++ lib.optional config.services.colord.enable colord-kde ++ lib.optional config.services.hardware.bolt.enable plasma-thunderbolt ++ lib.optional config.services.samba.enable kdenetwork-filesharing @@ -217,7 +202,7 @@ in { environment.sessionVariables.KPACKAGE_DEP_RESOLVERS_PATH = "${kdePackages.frameworkintegration.out}/libexec/kf6/kpackagehandlers"; # Enable GTK applications to load SVG icons - services.xserver.gdk-pixbuf.modulePackages = [pkgs.librsvg]; + programs.gdk-pixbuf.modulePackages = [pkgs.librsvg]; fonts.packages = [cfg.notoPackage pkgs.hack-font]; fonts.fontconfig.defaultFonts = { diff --git a/nixos/modules/services/desktops/espanso.nix b/nixos/modules/services/desktops/espanso.nix index 4ef6724dda0a0..a6b8a078247b1 100644 --- a/nixos/modules/services/desktops/espanso.nix +++ b/nixos/modules/services/desktops/espanso.nix @@ -6,19 +6,24 @@ in { meta = { maintainers = with lib.maintainers; [ numkem ]; }; options = { - services.espanso = { enable = options.mkEnableOption "Espanso"; }; + services.espanso = { + enable = mkEnableOption "Espanso"; + package = mkPackageOption pkgs "espanso" { + example = "pkgs.espanso-wayland"; + }; + }; }; config = mkIf cfg.enable { systemd.user.services.espanso = { description = "Espanso daemon"; serviceConfig = { - ExecStart = "${pkgs.espanso}/bin/espanso daemon"; + ExecStart = "${lib.getExe cfg.package} daemon"; Restart = "on-failure"; }; wantedBy = [ "default.target" ]; }; - environment.systemPackages = [ pkgs.espanso ]; + environment.systemPackages = [ cfg.package ]; }; } diff --git a/nixos/modules/services/display-managers/sddm.nix b/nixos/modules/services/display-managers/sddm.nix index a6bfa213fe380..54356f7bb6171 100644 --- a/nixos/modules/services/display-managers/sddm.nix +++ b/nixos/modules/services/display-managers/sddm.nix @@ -66,7 +66,14 @@ let HideShells = "/run/current-system/sw/bin/nologin"; }; - X11 = optionalAttrs xcfg.enable { + Wayland = { + EnableHiDPI = cfg.enableHidpi; + SessionDir = "${dmcfg.sessionData.desktops}/share/wayland-sessions"; + CompositorCommand = lib.optionalString cfg.wayland.enable cfg.wayland.compositorCommand; + }; + + } // optionalAttrs xcfg.enable { + X11 = { MinimumVT = if xcfg.tty != null then xcfg.tty else 7; ServerPath = toString xserverWrapper; XephyrPath = "${pkgs.xorg.xorgserver.out}/bin/Xephyr"; @@ -77,12 +84,6 @@ let DisplayStopCommand = toString Xstop; EnableHiDPI = cfg.enableHidpi; }; - - Wayland = { - EnableHiDPI = cfg.enableHidpi; - SessionDir = "${dmcfg.sessionData.desktops}/share/wayland-sessions"; - CompositorCommand = lib.optionalString cfg.wayland.enable cfg.wayland.compositorCommand; - }; } // optionalAttrs dmcfg.autoLogin.enable { Autologin = { User = dmcfg.autoLogin.user; diff --git a/nixos/modules/services/editors/emacs.nix b/nixos/modules/services/editors/emacs.nix index 35f257cee1e3a..98d8506e67278 100644 --- a/nixos/modules/services/editors/emacs.nix +++ b/nixos/modules/services/editors/emacs.nix @@ -6,8 +6,7 @@ let cfg = config.services.emacs; - editorScript = pkgs.writeScriptBin "emacseditor" '' - #!${pkgs.runtimeShell} + editorScript = pkgs.writeShellScriptBin "emacseditor" '' if [ -z "$1" ]; then exec ${cfg.package}/bin/emacsclient --create-frame --alternate-editor ${cfg.package}/bin/emacs else @@ -70,8 +69,8 @@ in description = "Emacs: the extensible, self-documenting text editor"; serviceConfig = { - Type = "forking"; - ExecStart = "${pkgs.bash}/bin/bash -c 'source ${config.system.build.setEnvironment}; exec ${cfg.package}/bin/emacs --daemon'"; + Type = "notify"; + ExecStart = "${pkgs.runtimeShell} -c 'source ${config.system.build.setEnvironment}; exec ${cfg.package}/bin/emacs --fg-daemon'"; ExecStop = "${cfg.package}/bin/emacsclient --eval (kill-emacs)"; Restart = "always"; }; diff --git a/nixos/modules/services/games/archisteamfarm.nix b/nixos/modules/services/games/archisteamfarm.nix index 33898f8387e99..c9c41d6f4eb5e 100644 --- a/nixos/modules/services/games/archisteamfarm.nix +++ b/nixos/modules/services/games/archisteamfarm.nix @@ -164,8 +164,11 @@ in }; config = lib.mkIf cfg.enable { - # TODO: drop with 24.11 - services.archisteamfarm.dataDir = lib.mkIf (lib.versionAtLeast config.system.stateVersion "24.05") (lib.mkDefault "/var/lib/asf"); + services.archisteamfarm = { + # TODO: drop with 24.11 + dataDir = lib.mkIf (lib.versionAtLeast config.system.stateVersion "24.05") (lib.mkDefault "/var/lib/asf"); + settings.IPC = lib.mkIf (!cfg.web-ui.enable) false; + }; users = { users.archisteamfarm = { diff --git a/nixos/modules/services/hardware/amdvlk.nix b/nixos/modules/services/hardware/amdvlk.nix new file mode 100644 index 0000000000000..20879f2f21b43 --- /dev/null +++ b/nixos/modules/services/hardware/amdvlk.nix @@ -0,0 +1,61 @@ +{ config, lib, pkgs, ... }: + +let + cfg = config.hardware.amdgpu.amdvlk; +in { + options.hardware.amdgpu.amdvlk = { + enable = lib.mkEnableOption "AMDVLK Vulkan driver"; + + package = lib.mkPackageOption pkgs "amdvlk" { }; + + supportExperimental.enable = lib.mkEnableOption "Experimental features support"; + + support32Bit.enable = lib.mkEnableOption "32-bit driver support"; + support32Bit.package = lib.mkPackageOption pkgs [ "driversi686Linux" "amdvlk" ] { }; + + settings = lib.mkOption { + type = with lib.types; attrsOf (either str int); + default = { }; + example = { + AllowVkPipelineCachingToDisk = 1; + ShaderCacheMode = 1; + IFH = 0; + EnableVmAlwaysValid = 1; + IdleAfterSubmitGpuMask = 1; + }; + description = '' + Runtime settings for AMDVLK to be configured {file}`/etc/amd/amdVulkanSettings.cfg`. + See [AMDVLK GitHub page](https://github.com/GPUOpen-Drivers/AMDVLK?tab=readme-ov-file#runtime-settings). + ''; + }; + }; + + config = lib.mkIf cfg.enable { + hardware.opengl = { + enable = true; + driSupport = true; + extraPackages = [ cfg.package ]; + driSupport32Bit = cfg.support32Bit.enable; + extraPackages32 = [ cfg.support32Bit.package ]; + }; + + services.xserver.videoDrivers = [ "amdgpu" ]; + + environment.sessionVariables = lib.mkIf cfg.supportExperimental.enable { + AMDVLK_ENABLE_DEVELOPING_EXT = "all"; + }; + + environment.etc = lib.mkIf (cfg.settings != { }) { + "amd/amdVulkanSettings.cfg".text = lib.concatStrings + (lib.mapAttrsToList + (n: v: '' + ${n},${builtins.toString v} + '') + cfg.settings); + }; + }; + + meta = { + maintainers = with lib.maintainers; [ johnrtitor ]; + }; +} diff --git a/nixos/modules/services/hardware/handheld-daemon.nix b/nixos/modules/services/hardware/handheld-daemon.nix index 6c9d5aa3e22c8..a5ba1856d015b 100644 --- a/nixos/modules/services/hardware/handheld-daemon.nix +++ b/nixos/modules/services/hardware/handheld-daemon.nix @@ -8,7 +8,7 @@ with lib; let in { options.services.handheld-daemon = { - enable = mkEnableOption "Enable Handheld Daemon"; + enable = mkEnableOption "Handheld Daemon"; package = mkPackageOption pkgs "handheld-daemon" { }; user = mkOption { diff --git a/nixos/modules/services/hardware/kanata.nix b/nixos/modules/services/hardware/kanata.nix index 46af3e36b9859..60fb33881f256 100644 --- a/nixos/modules/services/hardware/kanata.nix +++ b/nixos/modules/services/hardware/kanata.nix @@ -7,7 +7,7 @@ let upstreamDoc = "See [the upstream documentation](https://github.com/jtroo/kanata/blob/main/docs/config.adoc) and [example config files](https://github.com/jtroo/kanata/tree/main/cfg_samples) for more information."; - keyboard = { + keyboard = { name, config, ... }: { options = { devices = mkOption { type = types.listOf types.str; @@ -48,6 +48,21 @@ let ${upstreamDoc} ''; }; + configFile = mkOption { + type = types.path; + default = mkConfig name config; + defaultText = + "A config file generated by values from other kanata module options."; + description = '' + The config file. + + By default, it is generated by values from other kanata + module options. + + You can also set it to your own full config file which + overrides all other kanata module options. ${upstreamDoc} + ''; + }; extraArgs = mkOption { type = types.listOf types.str; default = [ ]; @@ -85,6 +100,10 @@ let ${keyboard.config} ''; + # Only the config file generated by this module is checked. A + # user-provided one is not checked because it may not be available + # at build time. I think this is a good balance between module + # complexity and functionality. checkPhase = '' ${getExe cfg.package} --cfg "$target" --check --debug ''; @@ -96,7 +115,7 @@ let Type = "notify"; ExecStart = '' ${getExe cfg.package} \ - --cfg ${mkConfig name keyboard} \ + --cfg ${keyboard.configFile} \ --symlink-path ''${RUNTIME_DIRECTORY}/${name} \ ${optionalString (keyboard.port != null) "--port ${toString keyboard.port}"} \ ${utils.escapeSystemdExecArgs keyboard.extraArgs} diff --git a/nixos/modules/services/hardware/nvidia-container-toolkit/default.nix b/nixos/modules/services/hardware/nvidia-container-toolkit/default.nix index 6c6bc667e6498..bd12667a56474 100644 --- a/nixos/modules/services/hardware/nvidia-container-toolkit/default.nix +++ b/nixos/modules/services/hardware/nvidia-container-toolkit/default.nix @@ -69,14 +69,18 @@ virtualisation.docker.daemon.settings = lib.mkIf (config.hardware.nvidia-container-toolkit.enable && (lib.versionAtLeast config.virtualisation.docker.package.version "25")) { - features.cdi = true; - }; + features.cdi = true; + }; hardware.nvidia-container-toolkit.mounts = let nvidia-driver = config.hardware.nvidia.package; in (lib.mkMerge [ [{ hostPath = pkgs.addDriverRunpath.driverLink; containerPath = pkgs.addDriverRunpath.driverLink; } + { hostPath = "${lib.getLib nvidia-driver}/etc"; + containerPath = "${lib.getLib nvidia-driver}/etc"; } + { hostPath = "${lib.getLib nvidia-driver}/share"; + containerPath = "${lib.getLib nvidia-driver}/share"; } { hostPath = "${lib.getLib pkgs.glibc}/lib"; containerPath = "${lib.getLib pkgs.glibc}/lib"; } { hostPath = "${lib.getLib pkgs.glibc}/lib64"; diff --git a/nixos/modules/services/hardware/nvidia-optimus.nix b/nixos/modules/services/hardware/nvidia-optimus.nix index d53175052c74a..307bc78098d14 100644 --- a/nixos/modules/services/hardware/nvidia-optimus.nix +++ b/nixos/modules/services/hardware/nvidia-optimus.nix @@ -23,7 +23,7 @@ let kernel = config.boot.kernelPackages; in ###### implementation config = lib.mkIf config.hardware.nvidiaOptimus.disable { - boot.blacklistedKernelModules = ["nouveau" "nvidia" "nvidiafb" "nvidia-drm"]; + boot.blacklistedKernelModules = ["nouveau" "nvidia" "nvidiafb" "nvidia-drm" "nvidia-modeset"]; boot.kernelModules = [ "bbswitch" ]; boot.extraModulePackages = [ kernel.bbswitch ]; diff --git a/nixos/modules/services/hardware/power-profiles-daemon.nix b/nixos/modules/services/hardware/power-profiles-daemon.nix index 05e5b7a00b420..7651c65b9f181 100644 --- a/nixos/modules/services/hardware/power-profiles-daemon.nix +++ b/nixos/modules/services/hardware/power-profiles-daemon.nix @@ -39,6 +39,12 @@ in which conflicts with services.tlp.enable = true; ''; } + { assertion = !config.services.auto-cpufreq.enable; + message = '' + You have set services.power-profiles-daemon.enable = true; + which conflicts with services.auto-cpufreq.enable = true; + ''; + } ]; environment.systemPackages = [ cfg.package ]; diff --git a/nixos/modules/services/hardware/thermald.nix b/nixos/modules/services/hardware/thermald.nix index 25cfd97016288..fb7cf3735a7ea 100644 --- a/nixos/modules/services/hardware/thermald.nix +++ b/nixos/modules/services/hardware/thermald.nix @@ -28,7 +28,13 @@ in configFile = mkOption { type = types.nullOr types.path; default = null; - description = "the thermald manual configuration file."; + description = '' + The thermald manual configuration file. + + Leave unspecified to run with the `--adaptive` flag instead which will have thermald use your computer's DPTF adaptive tables. + + See `man thermald` for more information. + ''; }; package = mkPackageOption pkgs "thermald" { }; @@ -49,8 +55,7 @@ in --no-daemon \ ${optionalString cfg.debug "--loglevel=debug"} \ ${optionalString cfg.ignoreCpuidCheck "--ignore-cpuid-check"} \ - ${optionalString (cfg.configFile != null) "--config-file ${cfg.configFile}"} \ - ${optionalString (cfg.configFile == null) "--adaptive"} \ + ${if cfg.configFile != null then "--config-file ${cfg.configFile}" else "--adaptive"} \ --dbus-enable ''; }; diff --git a/nixos/modules/services/home-automation/ebusd.nix b/nixos/modules/services/home-automation/ebusd.nix index ac9ec06639c13..f5c5479e8eaff 100644 --- a/nixos/modules/services/home-automation/ebusd.nix +++ b/nixos/modules/services/home-automation/ebusd.nix @@ -138,7 +138,7 @@ in after = [ "network.target" ]; serviceConfig = { ExecStart = let - args = cli.toGNUCommandLineShell { } (foldr (a: b: a // b) { } [ + args = cli.toGNUCommandLineShell { optionValueSeparator = "="; } (foldr (a: b: a // b) { } [ { inherit (cfg) device port configpath scanconfig readonly; foreground = true; diff --git a/nixos/modules/services/home-automation/wyoming/faster-whisper.nix b/nixos/modules/services/home-automation/wyoming/faster-whisper.nix index d0fca6a41c7b6..45664103665f7 100644 --- a/nixos/modules/services/home-automation/wyoming/faster-whisper.nix +++ b/nixos/modules/services/home-automation/wyoming/faster-whisper.nix @@ -113,6 +113,9 @@ in nameValuePair "wyoming-faster-whisper-${server}" { inherit (options) enable; description = "Wyoming faster-whisper server instance ${server}"; + wants = [ + "network-online.target" + ]; after = [ "network-online.target" ]; diff --git a/nixos/modules/services/home-automation/wyoming/openwakeword.nix b/nixos/modules/services/home-automation/wyoming/openwakeword.nix index 856a4ef7366d0..f9848970bf734 100644 --- a/nixos/modules/services/home-automation/wyoming/openwakeword.nix +++ b/nixos/modules/services/home-automation/wyoming/openwakeword.nix @@ -108,6 +108,9 @@ in config = mkIf cfg.enable { systemd.services."wyoming-openwakeword" = { description = "Wyoming openWakeWord server"; + wants = [ + "network-online.target" + ]; after = [ "network-online.target" ]; diff --git a/nixos/modules/services/home-automation/wyoming/piper.nix b/nixos/modules/services/home-automation/wyoming/piper.nix index 5b5f898d7ca35..a26fe8e84f609 100644 --- a/nixos/modules/services/home-automation/wyoming/piper.nix +++ b/nixos/modules/services/home-automation/wyoming/piper.nix @@ -117,6 +117,9 @@ in nameValuePair "wyoming-piper-${server}" { inherit (options) enable; description = "Wyoming Piper server instance ${server}"; + wants = [ + "network-online.target" + ]; after = [ "network-online.target" ]; diff --git a/nixos/modules/services/logging/journalwatch.nix b/nixos/modules/services/logging/journalwatch.nix index 71b29d57b7eb7..48fd992ffb65a 100644 --- a/nixos/modules/services/logging/journalwatch.nix +++ b/nixos/modules/services/logging/journalwatch.nix @@ -56,6 +56,8 @@ in { ''; }; + package = mkPackageOption pkgs "journalwatch" { }; + priority = mkOption { type = types.int; default = 6; @@ -240,7 +242,7 @@ in { # requires a relative directory name to create beneath /var/lib StateDirectory = user; StateDirectoryMode = "0750"; - ExecStart = "${pkgs.python3Packages.journalwatch}/bin/journalwatch mail"; + ExecStart = "${getExe cfg.package} mail"; # lowest CPU and IO priority, but both still in best-effort class to prevent starvation Nice=19; IOSchedulingPriority=7; diff --git a/nixos/modules/services/mail/public-inbox.nix b/nixos/modules/services/mail/public-inbox.nix index 14a2ab48fa250..98063e0331bd8 100644 --- a/nixos/modules/services/mail/public-inbox.nix +++ b/nixos/modules/services/mail/public-inbox.nix @@ -455,7 +455,7 @@ in after = [ "public-inbox-init.service" "public-inbox-watch.service" ]; requires = [ "public-inbox-init.service" ]; serviceConfig = { - BindPathsReadOnly = + BindReadOnlyPaths = map (c: c.dir) (lib.attrValues cfg.settings.coderepo); ExecStart = escapeShellArgs ( [ "${cfg.package}/bin/public-inbox-httpd" ] ++ diff --git a/nixos/modules/services/mail/stalwart-mail.nix b/nixos/modules/services/mail/stalwart-mail.nix index 08b07b885b696..ed3c5389354ce 100644 --- a/nixos/modules/services/mail/stalwart-mail.nix +++ b/nixos/modules/services/mail/stalwart-mail.nix @@ -7,10 +7,12 @@ let configFormat = pkgs.formats.toml { }; configFile = configFormat.generate "stalwart-mail.toml" cfg.settings; dataDir = "/var/lib/stalwart-mail"; + useLegacyStorage = versionOlder config.system.stateVersion "24.11"; in { options.services.stalwart-mail = { enable = mkEnableOption "the Stalwart all-in-one email server"; + package = mkPackageOption pkgs "stalwart-mail" { }; settings = mkOption { @@ -26,79 +28,110 @@ in { }; config = mkIf cfg.enable { + # Default config: all local services.stalwart-mail.settings = { - global.tracing.method = mkDefault "stdout"; - global.tracing.level = mkDefault "info"; + tracer.stdout = { + type = mkDefault "stdout"; + level = mkDefault "info"; + ansi = mkDefault false; # no colour markers to journald + enable = mkDefault true; + }; queue.path = mkDefault "${dataDir}/queue"; report.path = mkDefault "${dataDir}/reports"; - store.db.type = mkDefault "sqlite"; - store.db.path = mkDefault "${dataDir}/data/index.sqlite3"; - store.blob.type = mkDefault "fs"; - store.blob.path = mkDefault "${dataDir}/data/blobs"; + store = if useLegacyStorage then { + # structured data in SQLite, blobs on filesystem + db.type = mkDefault "sqlite"; + db.path = mkDefault "${dataDir}/data/index.sqlite3"; + fs.type = mkDefault "fs"; + fs.path = mkDefault "${dataDir}/data/blobs"; + } else { + # everything in RocksDB + db.type = mkDefault "rocksdb"; + db.path = mkDefault "${dataDir}/db"; + db.compression = mkDefault "lz4"; + }; storage.data = mkDefault "db"; storage.fts = mkDefault "db"; storage.lookup = mkDefault "db"; - storage.blob = mkDefault "blob"; + storage.blob = mkDefault (if useLegacyStorage then "fs" else "db"); + directory.internal.type = mkDefault "internal"; + directory.internal.store = mkDefault "db"; + storage.directory = mkDefault "internal"; resolver.type = mkDefault "system"; - resolver.public-suffix = mkDefault ["https://publicsuffix.org/list/public_suffix_list.dat"]; + resolver.public-suffix = lib.mkDefault [ + "file://${pkgs.publicsuffix-list}/share/publicsuffix/public_suffix_list.dat" + ]; + }; + + # This service stores a potentially large amount of data. + # Running it as a dynamic user would force chown to be run everytime the + # service is restarted on a potentially large number of files. + # That would cause unnecessary and unwanted delays. + users = { + groups.stalwart-mail = { }; + users.stalwart-mail = { + isSystemUser = true; + group = "stalwart-mail"; + }; }; - systemd.services.stalwart-mail = { - wantedBy = [ "multi-user.target" ]; - after = [ "local-fs.target" "network.target" ]; + systemd = { + packages = [ cfg.package ]; + services.stalwart-mail = { + wantedBy = [ "multi-user.target" ]; + after = [ "local-fs.target" "network.target" ]; - preStart = '' - mkdir -p ${dataDir}/{queue,reports,data/blobs} - ''; + preStart = if useLegacyStorage then '' + mkdir -p ${dataDir}/{queue,reports,data/blobs} + '' else '' + mkdir -p ${dataDir}/{queue,reports,db} + ''; + + serviceConfig = { + ExecStart = [ + "" + "${cfg.package}/bin/stalwart-mail --config=${configFile}" + ]; + + StandardOutput = "journal"; + StandardError = "journal"; + + StateDirectory = "stalwart-mail"; + + # Bind standard privileged ports + AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ]; + CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; - serviceConfig = { - ExecStart = - "${cfg.package}/bin/stalwart-mail --config=${configFile}"; - - # Base from template resources/systemd/stalwart-mail.service - Type = "simple"; - LimitNOFILE = 65536; - KillMode = "process"; - KillSignal = "SIGINT"; - Restart = "on-failure"; - RestartSec = 5; - StandardOutput = "journal"; - StandardError = "journal"; - SyslogIdentifier = "stalwart-mail"; - - DynamicUser = true; - User = "stalwart-mail"; - StateDirectory = "stalwart-mail"; - - # Bind standard privileged ports - AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ]; - CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ]; - - # Hardening - DeviceAllow = [ "" ]; - LockPersonality = true; - MemoryDenyWriteExecute = true; - PrivateDevices = true; - PrivateUsers = false; # incompatible with CAP_NET_BIND_SERVICE - ProcSubset = "pid"; - PrivateTmp = true; - ProtectClock = true; - ProtectControlGroups = true; - ProtectHome = true; - ProtectHostname = true; - ProtectKernelLogs = true; - ProtectKernelModules = true; - ProtectKernelTunables = true; - ProtectProc = "invisible"; - ProtectSystem = "strict"; - RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; - RestrictNamespaces = true; - RestrictRealtime = true; - RestrictSUIDSGID = true; - SystemCallArchitectures = "native"; - SystemCallFilter = [ "@system-service" "~@privileged" ]; - UMask = "0077"; + # Hardening + DeviceAllow = [ "" ]; + LockPersonality = true; + MemoryDenyWriteExecute = true; + PrivateDevices = true; + PrivateUsers = false; # incompatible with CAP_NET_BIND_SERVICE + ProcSubset = "pid"; + PrivateTmp = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProtectSystem = "strict"; + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ "@system-service" "~@privileged" ]; + UMask = "0077"; + }; + unitConfig.ConditionPathExists = [ + "" + "${configFile}" + ]; }; }; @@ -107,6 +140,6 @@ in { }; meta = { - maintainers = with maintainers; [ happysalada pacien ]; + maintainers = with maintainers; [ happysalada pacien onny ]; }; } diff --git a/nixos/modules/services/misc/devpi-server.nix b/nixos/modules/services/misc/devpi-server.nix index 0234db4bc2c5b..92c0c6206c8b3 100644 --- a/nixos/modules/services/misc/devpi-server.nix +++ b/nixos/modules/services/misc/devpi-server.nix @@ -74,8 +74,9 @@ in # have 0600 permissions. preStart = '' - cp ${cfg.secretFile} ${runtimeDir}/${secretsFileName} - chmod 0600 ${runtimeDir}/*${secretsFileName} + ${optionalString (!isNull cfg.secretFile) + "install -Dm 0600 \${CREDENTIALS_DIRECTORY}/devpi-secret ${runtimeDir}/${secretsFileName}" + } if [ -f ${serverDir}/.nodeinfo ]; then # already initialized the package index, exit gracefully @@ -85,6 +86,9 @@ in + strings.optionalString cfg.replica "--role=replica --master-url=${cfg.primaryUrl}"; serviceConfig = { + LoadCredential = lib.mkIf (! isNull cfg.secretFile) [ + "devpi-secret:${cfg.secretFile}" + ]; Restart = "always"; ExecStart = let diff --git a/nixos/modules/services/misc/forgejo.nix b/nixos/modules/services/misc/forgejo.nix index babed2d5acd48..9a102918f35e3 100644 --- a/nixos/modules/services/misc/forgejo.nix +++ b/nixos/modules/services/misc/forgejo.nix @@ -12,6 +12,15 @@ let usePostgresql = cfg.database.type == "postgres"; useSqlite = cfg.database.type == "sqlite3"; + secrets = let + mkSecret = section: values: lib.mapAttrsToList (key: value: { + env = envEscape "FORGEJO__${section}__${key}__FILE"; + path = value; + }) values; + # https://codeberg.org/forgejo/forgejo/src/tag/v7.0.2/contrib/environment-to-ini/environment-to-ini.go + envEscape = string: lib.replaceStrings [ "." "-" ] [ "_0X2E_" "_0X2D_" ] (lib.strings.toUpper string); + in lib.flatten (lib.mapAttrsToList mkSecret cfg.secrets); + inherit (lib) literalExpression mkChangedOptionModule @@ -34,6 +43,7 @@ in (mkRenamedOptionModule [ "services" "forgejo" "appName" ] [ "services" "forgejo" "settings" "DEFAULT" "APP_NAME" ]) (mkRemovedOptionModule [ "services" "forgejo" "extraConfig" ] "services.forgejo.extraConfig has been removed. Please use the freeform services.forgejo.settings option instead") (mkRemovedOptionModule [ "services" "forgejo" "database" "password" ] "services.forgejo.database.password has been removed. Please use services.forgejo.database.passwordFile instead") + (mkRenamedOptionModule [ "services" "forgejo" "mailerPasswordFile" ] [ "services" "forgejo" "secrets" "mailer" "PASSWD" ]) # copied from services.gitea; remove at some point (mkRenamedOptionModule [ "services" "forgejo" "cookieSecure" ] [ "services" "forgejo" "settings" "session" "COOKIE_SECURE" ]) @@ -224,13 +234,6 @@ in description = "Path to the git repositories."; }; - mailerPasswordFile = mkOption { - type = types.nullOr types.str; - default = null; - example = "/run/keys/forgejo-mailpw"; - description = "Path to a file containing the SMTP password."; - }; - settings = mkOption { default = { }; description = '' @@ -347,6 +350,44 @@ in }; }; }; + + secrets = mkOption { + default = { }; + description = '' + This is a small wrapper over systemd's `LoadCredential`. + + It takes the same sections and keys as {option}`services.forgejo.settings`, + but the value of each key is a path instead of a string or bool. + + The path is then loaded as credential, exported as environment variable + and then feed through + . + + It does the required environment variable escaping for you. + + ::: {.note} + Keys specified here take priority over the ones in {option}`services.forgejo.settings`! + ::: + ''; + example = literalExpression '' + { + metrics = { + TOKEN = "/run/keys/forgejo-metrics-token"; + }; + camo = { + HMAC_KEY = "/run/keys/forgejo-camo-hmac"; + }; + service = { + HCAPTCHA_SECRET = "/run/keys/forgejo-hcaptcha-secret"; + HCAPTCHA_SITEKEY = "/run/keys/forgejo-hcaptcha-sitekey"; + }; + } + ''; + type = types.submodule { + freeformType = with types; attrsOf (attrsOf path); + options = { }; + }; + }; }; }; @@ -381,7 +422,6 @@ in HOST = if cfg.database.socket != null then cfg.database.socket else cfg.database.host + ":" + toString cfg.database.port; NAME = cfg.database.name; USER = cfg.database.user; - PASSWD = "#dbpass#"; }) (mkIf useSqlite { PATH = cfg.database.path; @@ -397,7 +437,6 @@ in server = mkIf cfg.lfs.enable { LFS_START_SERVER = true; - LFS_JWT_SECRET = "#lfsjwtsecret#"; }; session = { @@ -405,21 +444,30 @@ in }; security = { - SECRET_KEY = "#secretkey#"; - INTERNAL_TOKEN = "#internaltoken#"; INSTALL_LOCK = true; }; - mailer = mkIf (cfg.mailerPasswordFile != null) { - PASSWD = "#mailerpass#"; + lfs = mkIf cfg.lfs.enable { + PATH = cfg.lfs.contentDir; + }; + }; + + services.forgejo.secrets = { + security = { + SECRET_KEY = "${cfg.customDir}/conf/secret_key"; + INTERNAL_TOKEN = "${cfg.customDir}/conf/internal_token"; }; oauth2 = { - JWT_SECRET = "#oauth2jwtsecret#"; + JWT_SECRET = "${cfg.customDir}/conf/oauth2_jwt_secret"; }; - lfs = mkIf cfg.lfs.enable { - PATH = cfg.lfs.contentDir; + database = mkIf (cfg.database.passwordFile != null) { + PASSWD = cfg.database.passwordFile; + }; + + server = mkIf cfg.lfs.enable { + LFS_JWT_SECRET = "${cfg.customDir}/conf/lfs_jwt_secret"; }; }; @@ -476,6 +524,37 @@ in "z '${cfg.lfs.contentDir}' 0750 ${cfg.user} ${cfg.group} - -" ]; + systemd.services.forgejo-secrets = mkIf (!cfg.useWizard) { + description = "Forgejo secret bootstrap helper"; + script = '' + if [ ! -s '${cfg.secrets.security.SECRET_KEY}' ]; then + ${exe} generate secret SECRET_KEY > '${cfg.secrets.security.SECRET_KEY}' + fi + + if [ ! -s '${cfg.secrets.oauth2.JWT_SECRET}' ]; then + ${exe} generate secret JWT_SECRET > '${cfg.secrets.oauth2.JWT_SECRET}' + fi + + ${optionalString cfg.lfs.enable '' + if [ ! -s '${cfg.secrets.server.LFS_JWT_SECRET}' ]; then + ${exe} generate secret LFS_JWT_SECRET > '${cfg.secrets.server.LFS_JWT_SECRET}' + fi + ''} + + if [ ! -s '${cfg.secrets.security.INTERNAL_TOKEN}' ]; then + ${exe} generate secret INTERNAL_TOKEN > '${cfg.secrets.security.INTERNAL_TOKEN}' + fi + ''; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + User = cfg.user; + Group = cfg.group; + ReadWritePaths = [ cfg.customDir ]; + UMask = "0077"; + }; + }; + systemd.services.forgejo = { description = "Forgejo (Beyond coding. We forge.)"; after = [ @@ -484,11 +563,15 @@ in "postgresql.service" ] ++ optionals useMysql [ "mysql.service" + ] ++ optionals (!cfg.useWizard) [ + "forgejo-secrets.service" ]; requires = optionals (cfg.database.createDatabase && usePostgresql) [ "postgresql.service" ] ++ optionals (cfg.database.createDatabase && useMysql) [ "mysql.service" + ] ++ optionals (!cfg.useWizard) [ + "forgejo-secrets.service" ]; wantedBy = [ "multi-user.target" ]; path = [ cfg.package pkgs.git pkgs.gnupg ]; @@ -501,61 +584,15 @@ in # lfs_jwt_secret. # We have to consider this to stay compatible with older installations. preStart = - let - runConfig = "${cfg.customDir}/conf/app.ini"; - secretKey = "${cfg.customDir}/conf/secret_key"; - oauth2JwtSecret = "${cfg.customDir}/conf/oauth2_jwt_secret"; - oldLfsJwtSecret = "${cfg.customDir}/conf/jwt_secret"; # old file for LFS_JWT_SECRET - lfsJwtSecret = "${cfg.customDir}/conf/lfs_jwt_secret"; # new file for LFS_JWT_SECRET - internalToken = "${cfg.customDir}/conf/internal_token"; - replaceSecretBin = "${pkgs.replace-secret}/bin/replace-secret"; - in '' - # copy custom configuration and generate random secrets if needed - ${lib.optionalString (!cfg.useWizard) '' + ${optionalString (!cfg.useWizard) '' function forgejo_setup { - cp -f '${format.generate "app.ini" cfg.settings}' '${runConfig}' - - if [ ! -s '${secretKey}' ]; then - ${exe} generate secret SECRET_KEY > '${secretKey}' - fi - - # Migrate LFS_JWT_SECRET filename - if [[ -s '${oldLfsJwtSecret}' && ! -s '${lfsJwtSecret}' ]]; then - mv '${oldLfsJwtSecret}' '${lfsJwtSecret}' - fi - - if [ ! -s '${oauth2JwtSecret}' ]; then - ${exe} generate secret JWT_SECRET > '${oauth2JwtSecret}' - fi - - ${optionalString cfg.lfs.enable '' - if [ ! -s '${lfsJwtSecret}' ]; then - ${exe} generate secret LFS_JWT_SECRET > '${lfsJwtSecret}' - fi - ''} - - if [ ! -s '${internalToken}' ]; then - ${exe} generate secret INTERNAL_TOKEN > '${internalToken}' - fi - - chmod u+w '${runConfig}' - ${replaceSecretBin} '#secretkey#' '${secretKey}' '${runConfig}' - ${replaceSecretBin} '#oauth2jwtsecret#' '${oauth2JwtSecret}' '${runConfig}' - ${replaceSecretBin} '#internaltoken#' '${internalToken}' '${runConfig}' - - ${optionalString cfg.lfs.enable '' - ${replaceSecretBin} '#lfsjwtsecret#' '${lfsJwtSecret}' '${runConfig}' - ''} - - ${optionalString (cfg.database.passwordFile != null) '' - ${replaceSecretBin} '#dbpass#' '${cfg.database.passwordFile}' '${runConfig}' - ''} - - ${optionalString (cfg.mailerPasswordFile != null) '' - ${replaceSecretBin} '#mailerpass#' '${cfg.mailerPasswordFile}' '${runConfig}' - ''} - chmod u-w '${runConfig}' + config='${cfg.customDir}/conf/app.ini' + cp -f '${format.generate "app.ini" cfg.settings}' "$config" + + chmod u+w "$config" + ${lib.getExe' cfg.package "environment-to-ini"} --config "$config" + chmod u-w "$config" } (umask 027; forgejo_setup) ''} @@ -616,6 +653,8 @@ in # System Call Filtering SystemCallArchitectures = "native"; SystemCallFilter = [ "~@cpu-emulation @debug @keyring @mount @obsolete @privileged @setuid" "setrlimit" ]; + # cfg.secrets + LoadCredential = map (e: "${e.env}:${e.path}") secrets; }; environment = { @@ -625,7 +664,7 @@ in # is resolved. GITEA_WORK_DIR = cfg.stateDir; GITEA_CUSTOM = cfg.customDir; - }; + } // lib.listToAttrs (map (e: lib.nameValuePair e.env "%d/${e.env}") secrets); }; services.openssh.settings.AcceptEnv = mkIf (!cfg.settings.START_SSH_SERVER or false) "GIT_PROTOCOL"; diff --git a/nixos/modules/services/misc/gitea.nix b/nixos/modules/services/misc/gitea.nix index a8526688b074f..d43250c882683 100644 --- a/nixos/modules/services/misc/gitea.nix +++ b/nixos/modules/services/misc/gitea.nix @@ -722,5 +722,5 @@ in timerConfig.OnCalendar = cfg.dump.interval; }; }; - meta.maintainers = with lib.maintainers; [ srhb ma27 pyrox0 ]; + meta.maintainers = with lib.maintainers; [ ma27 techknowlogick SuperSandro2000 ]; } diff --git a/nixos/modules/services/misc/gollum.nix b/nixos/modules/services/misc/gollum.nix index 3966ef036bec4..f320e78a91060 100644 --- a/nixos/modules/services/misc/gollum.nix +++ b/nixos/modules/services/misc/gollum.nix @@ -110,7 +110,7 @@ in users.groups."${cfg.group}" = { }; systemd.tmpfiles.rules = [ - "d '${cfg.stateDir}' - ${config.users.users.gollum.name} ${config.users.groups.gollum.name} - -" + "d '${cfg.stateDir}' - ${cfg.user} ${cfg.group} - -" ]; systemd.services.gollum = { diff --git a/nixos/modules/services/misc/invidious-router.nix b/nixos/modules/services/misc/invidious-router.nix index 33da7e96b5235..7a90c6ab9ddc0 100644 --- a/nixos/modules/services/misc/invidious-router.nix +++ b/nixos/modules/services/misc/invidious-router.nix @@ -8,10 +8,10 @@ settingsFormat = pkgs.formats.yaml {}; configFile = settingsFormat.generate "config.yaml" cfg.settings; in { - meta.maintainers = [lib.maintainers.s1ls]; + meta.maintainers = [lib.maintainers.sils]; options.services.invidious-router = { - enable = lib.mkEnableOption "Enables the invidious-router service"; + enable = lib.mkEnableOption "the invidious-router service"; port = lib.mkOption { type = lib.types.port; default = 8050; diff --git a/nixos/modules/services/misc/jellyfin.nix b/nixos/modules/services/misc/jellyfin.nix index a1d3910bd93b0..a006090878422 100644 --- a/nixos/modules/services/misc/jellyfin.nix +++ b/nixos/modules/services/misc/jellyfin.nix @@ -160,5 +160,5 @@ in }; - meta.maintainers = with maintainers; [ minijackson nu-nu-ko ]; + meta.maintainers = with maintainers; [ minijackson fsnkty ]; } diff --git a/nixos/modules/services/misc/mqtt2influxdb.nix b/nixos/modules/services/misc/mqtt2influxdb.nix index a2d6a2b34a239..925139b449b8e 100644 --- a/nixos/modules/services/misc/mqtt2influxdb.nix +++ b/nixos/modules/services/misc/mqtt2influxdb.nix @@ -125,6 +125,7 @@ in { options = { services.mqtt2influxdb = { enable = mkEnableOption "BigClown MQTT to InfluxDB bridge."; + package = mkPackageOption pkgs ["python3Packages" "mqtt2influxdb"] {}; environmentFiles = mkOption { type = types.listOf types.path; default = []; @@ -245,7 +246,7 @@ in { ''; serviceConfig = { EnvironmentFile = cfg.environmentFiles; - ExecStart = "${cfg.package}/bin/mqtt2influxdb -dc ${finalConfig}"; + ExecStart = "${lib.getExe cfg.package} -dc ${finalConfig}"; RuntimeDirectory = "mqtt2influxdb"; }; }; diff --git a/nixos/modules/services/misc/ollama.nix b/nixos/modules/services/misc/ollama.nix index c0341984aa351..886eaa180b9ef 100644 --- a/nixos/modules/services/misc/ollama.nix +++ b/nixos/modules/services/misc/ollama.nix @@ -11,6 +11,11 @@ let }; in { + imports = [ + (lib.mkRemovedOptionModule [ "services" "ollama" "listenAddress" ] + "Use `services.ollama.host` and `services.ollama.port` instead.") + ]; + options = { services.ollama = { enable = lib.mkEnableOption "ollama server for local large language models"; @@ -64,12 +69,20 @@ in See also `services.ollama.sandbox`. ''; }; - listenAddress = lib.mkOption { + host = lib.mkOption { type = types.str; - default = "127.0.0.1:11434"; - example = "0.0.0.0:11111"; + default = "127.0.0.1"; + example = "0.0.0.0"; description = '' - The address which the ollama server HTTP interface binds and listens to. + The host address which the ollama server HTTP interface listens to. + ''; + }; + port = lib.mkOption { + type = types.port; + default = 11434; + example = 11111; + description = '' + Which port the ollama server listens to. ''; }; acceleration = lib.mkOption { @@ -80,9 +93,9 @@ in What interface to use for hardware acceleration. - `null`: default behavior - if `nixpkgs.config.rocmSupport` is enabled, uses `"rocm"` - if `nixpkgs.config.cudaSupport` is enabled, uses `"cuda"` - otherwise defaults to `false` + - if `nixpkgs.config.rocmSupport` is enabled, uses `"rocm"` + - if `nixpkgs.config.cudaSupport` is enabled, uses `"cuda"` + - otherwise defaults to `false` - `false`: disable GPU, only use CPU - `"rocm"`: supported by most modern AMD GPUs - `"cuda"`: supported by most modern NVIDIA GPUs @@ -103,6 +116,14 @@ in Since `ollama run` is mostly a shell around the ollama server, this is usually sufficient. ''; }; + openFirewall = lib.mkOption { + type = types.bool; + default = false; + description = '' + Whether to open the firewall for ollama. + This adds `services.ollama.port` to `networking.firewall.allowedTCPPorts`. + ''; + }; }; }; @@ -114,7 +135,7 @@ in environment = cfg.environmentVariables // { HOME = cfg.home; OLLAMA_MODELS = cfg.models; - OLLAMA_HOST = cfg.listenAddress; + OLLAMA_HOST = "${cfg.host}:${toString cfg.port}"; }; serviceConfig = { ExecStart = "${lib.getExe ollamaPackage} serve"; @@ -125,6 +146,8 @@ in }; }; + networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.port ]; }; + environment.systemPackages = [ ollamaPackage ]; }; diff --git a/nixos/modules/services/misc/open-webui.nix b/nixos/modules/services/misc/open-webui.nix new file mode 100644 index 0000000000000..b4016d03f675f --- /dev/null +++ b/nixos/modules/services/misc/open-webui.nix @@ -0,0 +1,114 @@ +{ + config, + lib, + pkgs, + ... +}: +let + inherit (lib) types; + + cfg = config.services.open-webui; +in +{ + options = { + services.open-webui = { + enable = lib.mkEnableOption "Open-WebUI server"; + package = lib.mkPackageOption pkgs "open-webui" { }; + + stateDir = lib.mkOption { + type = types.path; + default = "/var/lib/open-webui"; + example = "/home/foo"; + description = "State directory of Open-WebUI."; + }; + + host = lib.mkOption { + type = types.str; + default = "127.0.0.1"; + example = "0.0.0.0"; + description = '' + The host address which the Open-WebUI server HTTP interface listens to. + ''; + }; + + port = lib.mkOption { + type = types.port; + default = 8080; + example = 11111; + description = '' + Which port the Open-WebUI server listens to. + ''; + }; + + environment = lib.mkOption { + type = types.attrsOf types.str; + default = { + SCARF_NO_ANALYTICS = "True"; + DO_NOT_TRACK = "True"; + ANONYMIZED_TELEMETRY = "False"; + }; + example = '' + { + OLLAMA_API_BASE_URL = "http://127.0.0.1:11434"; + # Disable authentication + WEBUI_AUTH = "False"; + } + ''; + description = "Extra environment variables for Open-WebUI"; + }; + + openFirewall = lib.mkOption { + type = types.bool; + default = false; + description = '' + Whether to open the firewall for Open-WebUI. + This adds `services.open-webui.port` to `networking.firewall.allowedTCPPorts`. + ''; + }; + }; + }; + + config = lib.mkIf cfg.enable { + systemd.services.open-webui = { + description = "User-friendly WebUI for LLMs"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + + environment = { + STATIC_DIR = "."; + DATA_DIR = "."; + HF_HOME = "."; + SENTENCE_TRANSFORMERS_HOME = "."; + } // cfg.environment; + + serviceConfig = { + ExecStart = "${lib.getExe cfg.package} serve --host ${cfg.host} --port ${toString cfg.port}"; + WorkingDirectory = cfg.stateDir; + StateDirectory = "open-webui"; + RuntimeDirectory = "open-webui"; + RuntimeDirectoryMode = "0755"; + PrivateTmp = true; + DynamicUser = true; + DevicePolicy = "closed"; + LockPersonality = true; + MemoryDenyWriteExecute = false; # onnxruntime/capi/onnxruntime_pybind11_state.so: cannot enable executable stack as shared object requires: Permission Denied + PrivateUsers = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectControlGroups = true; + ProcSubset = "all"; # Error in cpuinfo: failed to parse processor information from /proc/cpuinfo + RestrictNamespaces = true; + RestrictRealtime = true; + SystemCallArchitectures = "native"; + UMask = "0077"; + }; + }; + + networking.firewall = lib.mkIf cfg.openFirewall { allowedTCPPorts = [ cfg.port ]; }; + }; + + meta.maintainers = with lib.maintainers; [ shivaraj-bh ]; +} diff --git a/nixos/modules/services/misc/pghero.nix b/nixos/modules/services/misc/pghero.nix new file mode 100644 index 0000000000000..39515f10c8e1d --- /dev/null +++ b/nixos/modules/services/misc/pghero.nix @@ -0,0 +1,142 @@ +{ config, pkgs, lib, utils, ... }: +let + cfg = config.services.pghero; + settingsFormat = pkgs.formats.yaml { }; + settingsFile = settingsFormat.generate "pghero.yaml" cfg.settings; +in +{ + options.services.pghero = { + enable = lib.mkEnableOption "PgHero service"; + package = lib.mkPackageOption pkgs "pghero" { }; + + listenAddress = lib.mkOption { + type = lib.types.str; + example = "[::1]:3000"; + description = '' + `hostname:port` to listen for HTTP traffic. + + This is bound using the systemd socket activation. + ''; + }; + + extraArgs = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + description = '' + Additional command-line arguments for the systemd service. + + Refer to the [Puma web server documentation] for available arguments. + + [Puma web server documentation]: https://puma.io/puma#configuration + ''; + }; + + settings = lib.mkOption { + type = settingsFormat.type; + default = { }; + example = { + databases = { + primary = { + url = "<%= ENV['PRIMARY_DATABASE_URL'] %>"; + }; + }; + }; + description = '' + PgHero configuration. Refer to the [PgHero documentation] for more + details. + + [PgHero documentation]: https://github.com/ankane/pghero/blob/master/guides/Linux.md#multiple-databases + ''; + }; + + environment = lib.mkOption { + type = lib.types.attrsOf lib.types.str; + default = { }; + description = '' + Environment variables to set for the service. Secrets should be + specified using {option}`environmentFile`. + ''; + }; + + environmentFiles = lib.mkOption { + type = lib.types.listOf lib.types.path; + default = [ ]; + description = '' + File to load environment variables from. Loaded variables override + values set in {option}`environment`. + ''; + }; + + extraGroups = lib.mkOption { + type = lib.types.listOf lib.types.str; + default = [ ]; + example = [ "tlskeys" ]; + description = '' + Additional groups for the systemd service. + ''; + }; + }; + + config = lib.mkIf cfg.enable { + systemd.sockets.pghero = { + unitConfig.Description = "PgHero HTTP socket"; + wantedBy = [ "sockets.target" ]; + listenStreams = [ cfg.listenAddress ]; + }; + + systemd.services.pghero = { + description = "PgHero performance dashboard for PostgreSQL"; + wantedBy = [ "multi-user.target" ]; + requires = [ "pghero.socket" ]; + after = [ "pghero.socket" "network.target" ]; + + environment = { + RAILS_ENV = "production"; + PGHERO_CONFIG_PATH = settingsFile; + } // cfg.environment; + + serviceConfig = { + Type = "notify"; + WatchdogSec = "10"; + + ExecStart = utils.escapeSystemdExecArgs ([ + (lib.getExe cfg.package) + "--bind-to-activated-sockets" + "only" + ] ++ cfg.extraArgs); + Restart = "always"; + + WorkingDirectory = "${cfg.package}/share/pghero"; + + EnvironmentFile = cfg.environmentFiles; + SupplementaryGroups = cfg.extraGroups; + + DynamicUser = true; + UMask = "0077"; + + ProtectHome = true; + ProtectProc = "invisible"; + ProcSubset = "pid"; + ProtectClock = true; + ProtectHostname = true; + ProtectControlGroups = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + PrivateUsers = true; + PrivateDevices = true; + RestrictRealtime = true; + RestrictNamespaces = true; + RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ]; + DeviceAllow = [ "" ]; + DevicePolicy = "closed"; + CapabilityBoundingSet = [ "" ]; + MemoryDenyWriteExecute = true; + LockPersonality = true; + SystemCallArchitectures = "native"; + SystemCallErrorNumber = "EPERM"; + SystemCallFilter = [ "@system-service" ]; + }; + }; + }; +} diff --git a/nixos/modules/services/misc/plex.nix b/nixos/modules/services/misc/plex.nix index fcd8ebbac6edd..212abda5d1e0b 100644 --- a/nixos/modules/services/misc/plex.nix +++ b/nixos/modules/services/misc/plex.nix @@ -93,6 +93,17 @@ in ''; }; + accelerationDevices = mkOption { + type = types.listOf types.str; + default = ["*"]; + example = [ "/dev/dri/renderD128" ]; + description = '' + A list of device paths to hardware acceleration devices that Plex should + have access to. This is useful when transcoding media files. + The special value `"*"` will allow all devices. + ''; + }; + package = mkPackageOption pkgs "plex" { extraDescription = '' Plex subscribers may wish to use their own package here, @@ -133,6 +144,24 @@ in KillSignal = "SIGQUIT"; PIDFile = "${cfg.dataDir}/Plex Media Server/plexmediaserver.pid"; Restart = "on-failure"; + + # Hardening + NoNewPrivileges = true; + PrivateTmp = true; + PrivateDevices = cfg.accelerationDevices == []; + DeviceAllow = mkIf (cfg.accelerationDevices != [] && !lib.elem "*" cfg.accelerationDevices) cfg.accelerationDevices; + ProtectSystem = true; + ProtectHome = true; + ProtectControlGroups = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + RestrictAddressFamilies = ["AF_UNIX" "AF_INET" "AF_INET6" "AF_NETLINK"]; + # This could be made to work if the namespaces needed were known + # RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + MemoryDenyWriteExecute = true; + LockPersonality = true; }; environment = { diff --git a/nixos/modules/services/misc/portunus.nix b/nixos/modules/services/misc/portunus.nix index bdb35da788e3a..c7abb2cfa2a3e 100644 --- a/nixos/modules/services/misc/portunus.nix +++ b/nixos/modules/services/misc/portunus.nix @@ -98,6 +98,10 @@ in The OIDC secret must be set as the `DEX_CLIENT_''${id}` environment variable in the [](#opt-services.dex.environmentFile) setting. + + ::: {.note} + Make sure the id only contains characters that are allowed in an environment variable name, e.g. no -. + ::: ''; }; @@ -111,10 +115,7 @@ in ldap = { package = mkOption { type = types.package; - # needs openldap built with a libxcrypt that support crypt sha256 until users have had time to migrate to newer hashes - # Ref: - # TODO: remove in NixOS 24.11 (cf. same note on pkgs/servers/portunus/default.nix) - default = pkgs.openldap.override { libxcrypt = pkgs.libxcrypt-legacy; }; + default = pkgs.openldap; defaultText = lib.literalExpression "pkgs.openldap.override { libxcrypt = pkgs.libxcrypt-legacy; }"; description = "The OpenLDAP package to use."; }; diff --git a/nixos/modules/services/misc/renovate.nix b/nixos/modules/services/misc/renovate.nix new file mode 100644 index 0000000000000..25a719c91cbd8 --- /dev/null +++ b/nixos/modules/services/misc/renovate.nix @@ -0,0 +1,153 @@ +{ + config, + lib, + pkgs, + ... +}: +let + inherit (lib) + mkEnableOption + mkPackageOption + mkOption + types + mkIf + ; + json = pkgs.formats.json { }; + cfg = config.services.renovate; + generateValidatedConfig = + name: value: + pkgs.callPackage ( + { runCommand, jq }: + runCommand name + { + nativeBuildInputs = [ + jq + cfg.package + ]; + value = builtins.toJSON value; + passAsFile = [ "value" ]; + preferLocalBuild = true; + } + '' + jq . "$valuePath"> $out + renovate-config-validator $out + '' + ) { }; + generateConfig = if cfg.validateSettings then generateValidatedConfig else json.generate; +in +{ + meta.maintainers = with lib.maintainers; [ marie natsukium ]; + + options.services.renovate = { + enable = mkEnableOption "renovate"; + package = mkPackageOption pkgs "renovate" { }; + schedule = mkOption { + type = with types; nullOr str; + description = "How often to run renovate. See {manpage}`systemd.time(7)` for the format."; + example = "*:0/10"; + default = null; + }; + credentials = mkOption { + type = with types; attrsOf path; + description = '' + Allows configuring environment variable credentials for renovate, read from files. + This should always be used for passing confidential data to renovate. + ''; + example = { + RENOVATE_TOKEN = "/etc/renovate/token"; + }; + default = { }; + }; + runtimePackages = mkOption { + type = with types; listOf package; + description = "Packages available to renovate."; + default = [ ]; + }; + validateSettings = mkOption { + type = types.bool; + default = true; + description = "Weither to run renovate's config validator on the built configuration."; + }; + settings = mkOption { + type = json.type; + default = { }; + example = { + platform = "gitea"; + endpoint = "https://git.example.com"; + gitAuthor = "Renovate "; + }; + description = '' + Renovate's global configuration. + If you want to pass secrets to renovate, please use {option}`services.renovate.credentials` for that. + ''; + }; + }; + + config = mkIf cfg.enable { + services.renovate.settings = { + cacheDir = "/var/cache/renovate"; + baseDir = "/var/lib/renovate"; + }; + + systemd.services.renovate = { + description = "Renovate dependency updater"; + documentation = [ "https://docs.renovatebot.com/" ]; + after = [ "network.target" ]; + startAt = lib.optional (cfg.schedule != null) cfg.schedule; + path = [ + config.systemd.package + pkgs.git + ] ++ cfg.runtimePackages; + + serviceConfig = { + Type = "oneshot"; + User = "renovate"; + Group = "renovate"; + DynamicUser = true; + LoadCredential = lib.mapAttrsToList (name: value: "SECRET-${name}:${value}") cfg.credentials; + RemainAfterExit = false; + Restart = "on-failure"; + CacheDirectory = "renovate"; + StateDirectory = "renovate"; + + # Hardening + CapabilityBoundingSet = [ "" ]; + DeviceAllow = [ "" ]; + LockPersonality = true; + PrivateDevices = true; + PrivateUsers = true; + ProcSubset = "pid"; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + SystemCallArchitectures = "native"; + UMask = "0077"; + }; + + script = '' + ${lib.concatStringsSep "\n" ( + builtins.map (name: "export ${name}=$(systemd-creds cat 'SECRET-${name}')") ( + lib.attrNames cfg.credentials + ) + )} + exec ${lib.escapeShellArg (lib.getExe cfg.package)} + ''; + + environment = { + RENOVATE_CONFIG_FILE = generateConfig "renovate-config.json" cfg.settings; + HOME = "/var/lib/renovate"; + }; + }; + }; +} diff --git a/nixos/modules/services/misc/snapper.nix b/nixos/modules/services/misc/snapper.nix index 3a3ed1b5c0f56..a42fca5b60289 100644 --- a/nixos/modules/services/misc/snapper.nix +++ b/nixos/modules/services/misc/snapper.nix @@ -103,6 +103,18 @@ in ''; }; + persistentTimer = mkOption { + default = false; + type = types.bool; + example = true; + description = '' + Set the `Persistent` option for the + {manpage}`systemd.timer(5)` + which triggers the snapshot immediately if the last trigger + was missed (e.g. if the system was powered down). + ''; + }; + cleanupInterval = mkOption { type = types.str; default = "1d"; @@ -198,7 +210,14 @@ in inherit documentation; requires = [ "local-fs.target" ]; serviceConfig.ExecStart = "${pkgs.snapper}/lib/snapper/systemd-helper --timeline"; - startAt = cfg.snapshotInterval; + }; + + systemd.timers.snapper-timeline = { + wantedBy = [ "timers.target" ]; + timerConfig = { + Persistent = cfg.persistentTimer; + OnCalendar = cfg.snapshotInterval; + }; }; systemd.services.snapper-cleanup = { diff --git a/nixos/modules/services/monitoring/alloy.nix b/nixos/modules/services/monitoring/alloy.nix new file mode 100644 index 0000000000000..abe8fcd7e1beb --- /dev/null +++ b/nixos/modules/services/monitoring/alloy.nix @@ -0,0 +1,80 @@ +{ lib, pkgs, config, ... }: +with lib; +let + cfg = config.services.alloy; +in +{ + meta = { + maintainers = with maintainers; [ flokli hbjydev ]; + }; + + options.services.alloy = { + enable = mkEnableOption "Grafana Alloy"; + + package = mkPackageOption pkgs "grafana-alloy" { }; + + configPath = mkOption { + type = lib.types.path; + default = "/etc/alloy"; + description = '' + Alloy configuration file/directory path. + + We default to `/etc/alloy` here, and expect the user to configure a + configuration file via `environment.etc."alloy/config.alloy"`. + + This allows config reload, contrary to specifying a store path. + A `reloadTrigger` for `config.alloy` is configured. + + Other `*.alloy` files in the same directory (ignoring subdirs) are also + honored, but it's necessary to manually extend + `systemd.services.alloy.reloadTriggers` to enable config reload + during nixos-rebuild switch. + + This can also point to another directory containing `*.alloy` files, or + a single Alloy file in the Nix store (at the cost of reload). + + Component names must be unique across all Alloy configuration files, and + configuration blocks must not be repeated. + + Alloy will continue to run if subsequent reloads of the configuration + file fail, potentially marking components as unhealthy depending on + the nature of the failure. When this happens, Alloy will continue + functioning in the last valid state. + ''; + }; + + extraFlags = mkOption { + type = with lib.types; listOf str; + default = [ ]; + example = [ "--server.http.listen-addr=127.0.0.1:12346" "--disable-reporting" ]; + description = '' + Extra command-line flags passed to {command}`alloy run`. + + See + ''; + }; + }; + + + config = mkIf cfg.enable { + systemd.services.alloy = { + wantedBy = [ "multi-user.target" ]; + reloadTriggers = [ config.environment.etc."alloy/config.alloy".source or null ]; + serviceConfig = { + Restart = "always"; + DynamicUser = true; + RestartSec = 2; + SupplementaryGroups = [ + # allow to read the systemd journal for loki log forwarding + "systemd-journal" + ]; + ExecStart = "${lib.getExe cfg.package} run ${cfg.configPath} ${escapeShellArgs cfg.extraFlags}"; + ExecReload = "${pkgs.coreutils}/bin/kill -SIGHUP $MAINPID"; + ConfigurationDirectory = "alloy"; + StateDirectory = "alloy"; + WorkingDirectory = "%S/alloy"; + Type = "simple"; + }; + }; + }; +} diff --git a/nixos/modules/services/monitoring/grafana.nix b/nixos/modules/services/monitoring/grafana.nix index 9d453c5394824..32919950adc1e 100644 --- a/nixos/modules/services/monitoring/grafana.nix +++ b/nixos/modules/services/monitoring/grafana.nix @@ -47,13 +47,6 @@ let datasourceFileOrDir = mkProvisionCfg "datasource" "datasources" cfg.provision.datasources; dashboardFileOrDir = mkProvisionCfg "dashboard" "providers" cfg.provision.dashboards; - notifierConfiguration = { - apiVersion = 1; - notifiers = cfg.provision.notifiers; - }; - - notifierFileOrDir = pkgs.writeText "notifier.yaml" (builtins.toJSON notifierConfiguration); - generateAlertingProvisioningYaml = x: if (cfg.provision.alerting."${x}".path == null) then provisioningSettingsFormat.generate "${x}.yaml" cfg.provision.alerting."${x}".settings @@ -74,10 +67,9 @@ let fi ''; provisionConfDir = pkgs.runCommand "grafana-provisioning" { nativeBuildInputs = [ pkgs.xorg.lndir ]; } '' - mkdir -p $out/{alerting,datasources,dashboards,notifiers,plugins} + mkdir -p $out/{alerting,datasources,dashboards,plugins} ${ln { src = datasourceFileOrDir; dir = "datasources"; filename = "datasource"; }} ${ln { src = dashboardFileOrDir; dir = "dashboards"; filename = "dashboard"; }} - ${ln { src = notifierFileOrDir; dir = "notifiers"; filename = "notifier"; }} ${ln { src = rulesFileOrDir; dir = "alerting"; filename = "rules"; }} ${ln { src = contactPointsFileOrDir; dir = "alerting"; filename = "contactPoints"; }} ${ln { src = policiesFileOrDir; dir = "alerting"; filename = "policies"; }} @@ -161,73 +153,13 @@ let }; }; }; - - grafanaTypes.notifierConfig = types.submodule { - options = { - name = mkOption { - type = types.str; - default = "default"; - description = "Notifier name."; - }; - type = mkOption { - type = types.enum [ "dingding" "discord" "email" "googlechat" "hipchat" "kafka" "line" "teams" "opsgenie" "pagerduty" "prometheus-alertmanager" "pushover" "sensu" "sensugo" "slack" "telegram" "threema" "victorops" "webhook" ]; - description = "Notifier type."; - }; - uid = mkOption { - type = types.str; - description = "Unique notifier identifier."; - }; - org_id = mkOption { - type = types.int; - default = 1; - description = "Organization ID."; - }; - org_name = mkOption { - type = types.str; - default = "Main Org."; - description = "Organization name."; - }; - is_default = mkOption { - type = types.bool; - description = "Is the default notifier."; - default = false; - }; - send_reminder = mkOption { - type = types.bool; - default = true; - description = "Should the notifier be sent reminder notifications while alerts continue to fire."; - }; - frequency = mkOption { - type = types.str; - default = "5m"; - description = "How frequently should the notifier be sent reminders."; - }; - disable_resolve_message = mkOption { - type = types.bool; - default = false; - description = "Turn off the message that sends when an alert returns to OK."; - }; - settings = mkOption { - type = types.nullOr types.attrs; - default = null; - description = "Settings for the notifier type."; - }; - secure_settings = mkOption { - type = types.nullOr types.attrs; - default = null; - description = '' - Secure settings for the notifier type. Please note that the contents of this option - will end up in a world-readable Nix store. Use the file provider - pointing at a reasonably secured file in the local filesystem - to work around that. Look at the documentation for details: - - ''; - }; - }; - }; in { imports = [ + (mkRemovedOptionModule [ "services" "grafana" "provision" "notifiers" ] '' + Notifiers (services.grafana.provision.notifiers) were removed in Grafana 11. + '') + (mkRenamedOptionModule [ "services" "grafana" "protocol" ] [ "services" "grafana" "settings" "server" "protocol" ]) (mkRenamedOptionModule [ "services" "grafana" "addr" ] [ "services" "grafana" "settings" "server" "http_addr" ]) (mkRenamedOptionModule [ "services" "grafana" "port" ] [ "services" "grafana" "settings" "server" "http_port" ]) @@ -1256,15 +1188,6 @@ in }; }; - - notifiers = mkOption { - description = "Grafana notifier configuration."; - default = [ ]; - type = types.listOf grafanaTypes.notifierConfig; - apply = x: map _filter x; - }; - - alerting = { rules = { path = mkOption { @@ -1746,12 +1669,6 @@ in Use file provider or an env-var instead. ''; - # Warn about deprecated notifiers. - deprecatedNotifiers = optional (cfg.provision.notifiers != [ ]) '' - Notifiers are deprecated upstream and will be removed in Grafana 11. - Use `services.grafana.provision.alerting.contactPoints` instead. - ''; - # Ensure that `secureJsonData` of datasources provisioned via `datasources.settings` # only uses file/env providers. secureJsonDataWithoutFileProvider = optional @@ -1770,15 +1687,10 @@ in Declarations in the `secureJsonData`-block of a datasource will be leaked to the Nix store unless a file-provider or an env-var is used! ''; - - notifierSecureSettingsWithoutFileProvider = optional - (any (x: x.secure_settings != null) cfg.provision.notifiers) - "Notifier secure settings will be stored as plaintext in the Nix store! Use file provider instead."; in passwordWithoutFileProvider - ++ deprecatedNotifiers ++ secureJsonDataWithoutFileProvider - ++ notifierSecureSettingsWithoutFileProvider; + ; environment.systemPackages = [ cfg.package ]; diff --git a/nixos/modules/services/monitoring/loki.nix b/nixos/modules/services/monitoring/loki.nix index ba63f95e7f1a8..307119ecbf8ba 100644 --- a/nixos/modules/services/monitoring/loki.nix +++ b/nixos/modules/services/monitoring/loki.nix @@ -94,11 +94,24 @@ in { systemd.services.loki = { description = "Loki Service Daemon"; wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; serviceConfig = let conf = if cfg.configFile == null - then prettyJSON cfg.configuration + then + # Config validation may fail when using extraFlags = [ "-config.expand-env=true" ]. + # To work around this, we simply skip it when extraFlags is not empty. + if cfg.extraFlags == [] + then validateConfig (prettyJSON cfg.configuration) + else prettyJSON cfg.configuration else cfg.configFile; + validateConfig = file: + pkgs.runCommand "validate-loki-conf" { + nativeBuildInputs = [ cfg.package ]; + } '' + loki -verify-config -config.file "${file}" + ln -s "${file}" "$out" + ''; in { ExecStart = "${cfg.package}/bin/loki --config.file=${conf} ${escapeShellArgs cfg.extraFlags}"; diff --git a/nixos/modules/services/monitoring/prometheus/default.nix b/nixos/modules/services/monitoring/prometheus/default.nix index 7e707a13b7903..4de80acfa9a8b 100644 --- a/nixos/modules/services/monitoring/prometheus/default.nix +++ b/nixos/modules/services/monitoring/prometheus/default.nix @@ -181,6 +181,10 @@ let communicating with external systems (federation, remote storage, Alertmanager). ''; + + query_log_file = mkOpt types.str '' + Path to the file prometheus should write its query log to. + ''; }; }; diff --git a/nixos/modules/services/monitoring/scrutiny.nix b/nixos/modules/services/monitoring/scrutiny.nix index 031f5a30cada6..c649d333e401a 100644 --- a/nixos/modules/services/monitoring/scrutiny.nix +++ b/nixos/modules/services/monitoring/scrutiny.nix @@ -140,8 +140,8 @@ in options.api.endpoint = mkOption { type = str; - default = "http://localhost:${toString cfg.settings.web.listen.port}"; - defaultText = literalExpression ''"http://localhost:''${config.services.scrutiny.settings.web.listen.port}"''; + default = "http://${cfg.settings.web.listen.host}:${toString cfg.settings.web.listen.port}"; + defaultText = literalExpression ''"http://''${config.services.scrutiny.settings.web.listen.host}:''${config.services.scrutiny.settings.web.listen.port}"''; description = "Scrutiny app API endpoint for sending metrics to."; }; diff --git a/nixos/modules/services/monitoring/zabbix-proxy.nix b/nixos/modules/services/monitoring/zabbix-proxy.nix index 7fa471b6404a8..dec403df85ea8 100644 --- a/nixos/modules/services/monitoring/zabbix-proxy.nix +++ b/nixos/modules/services/monitoring/zabbix-proxy.nix @@ -103,7 +103,7 @@ in port = mkOption { type = types.port; - default = if cfg.database.type == "mysql" then mysql.port else pgsql.services.port; + default = if cfg.database.type == "mysql" then mysql.port else pgsql.settings.port; defaultText = literalExpression '' if config.${opt.database.type} == "mysql" then config.${options.services.mysql.port} diff --git a/nixos/modules/services/network-filesystems/davfs2.nix b/nixos/modules/services/network-filesystems/davfs2.nix index 23c04658031fb..9a7d0daa6421f 100644 --- a/nixos/modules/services/network-filesystems/davfs2.nix +++ b/nixos/modules/services/network-filesystems/davfs2.nix @@ -20,14 +20,10 @@ let else toString value; configFile = pkgs.writeText "davfs2.conf" ( - if (cfg.settings != { }) then - (toINIWithGlobalSection { - mkSectionName = escapeString; - mkKeyValue = k: v: "${k} ${formatValue v}"; - } cfg.settings) - else - cfg.extraConfig - ); + toINIWithGlobalSection { + mkSectionName = escapeString; + mkKeyValue = k: v: "${k} ${formatValue v}"; + } cfg.settings); in { @@ -53,29 +49,6 @@ in ''; }; - extraConfig = mkOption { - type = lines; - default = ""; - example = '' - proxy foo.bar:8080 - use_locks 0 - - [/media/dav] - use_locks 1 - - [/home/otto/mywebspace] - gui_optimize 1 - ''; - description = '' - Extra lines appended to the configuration of davfs2. - See {manpage}`davfs2.conf(5)` for available settings. - - **Note**: Please pass structured settings via - {option}`settings` instead, this option - will get deprecated in the future. - '' ; - }; - settings = mkOption { type = submodule { freeformType = let @@ -109,21 +82,6 @@ in config = mkIf cfg.enable { - assertions = [ - { - assertion = cfg.extraConfig != "" -> cfg.settings == { }; - message = '' - services.davfs2.extraConfig and services.davfs2.settings cannot be used together. - Please prefer using services.davfs2.settings. - ''; - } - ]; - - warnings = optional (cfg.extraConfig != "") '' - services.davfs2.extraConfig will be deprecated in future releases; - please use services.davfs2.settings instead. - ''; - environment.systemPackages = [ pkgs.davfs2 ]; environment.etc."davfs2/davfs2.conf".source = configFile; diff --git a/nixos/modules/services/networking/adguardhome.nix b/nixos/modules/services/networking/adguardhome.nix index df9927351edc3..5be3e0bea224a 100644 --- a/nixos/modules/services/networking/adguardhome.nix +++ b/nixos/modules/services/networking/adguardhome.nix @@ -140,7 +140,7 @@ in { { assertion = cfg.settings != null -> !(hasAttrByPath [ "bind_port" ] cfg.settings); - message = "AdGuard option `settings.bind_host' has been superseded by `services.adguardhome.port'"; + message = "AdGuard option `settings.bind_port' has been superseded by `services.adguardhome.port'"; } { assertion = settings != null -> cfg.mutableSettings @@ -167,8 +167,13 @@ in { preStart = optionalString (settings != null) '' if [ -e "$STATE_DIRECTORY/AdGuardHome.yaml" ] \ && [ "${toString cfg.mutableSettings}" = "1" ]; then + # First run a schema_version update on the existing configuration + # This ensures that both the new config and the existing one have the same schema_version + # Note: --check-config has the side effect of modifying the file at rest! + ${lib.getExe cfg.package} -c "$STATE_DIRECTORY/AdGuardHome.yaml" --check-config + # Writing directly to AdGuardHome.yaml results in empty file - ${pkgs.yaml-merge}/bin/yaml-merge "$STATE_DIRECTORY/AdGuardHome.yaml" "${configFile}" > "$STATE_DIRECTORY/AdGuardHome.yaml.tmp" + ${lib.getExe pkgs.yaml-merge} "$STATE_DIRECTORY/AdGuardHome.yaml" "${configFile}" > "$STATE_DIRECTORY/AdGuardHome.yaml.tmp" mv "$STATE_DIRECTORY/AdGuardHome.yaml.tmp" "$STATE_DIRECTORY/AdGuardHome.yaml" else cp --force "${configFile}" "$STATE_DIRECTORY/AdGuardHome.yaml" @@ -178,7 +183,7 @@ in { serviceConfig = { DynamicUser = true; - ExecStart = "${cfg.package}/bin/adguardhome ${args}"; + ExecStart = "${lib.getExe cfg.package} ${args}"; AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ] ++ optionals cfg.allowDHCP [ "CAP_NET_RAW" ]; Restart = "always"; diff --git a/nixos/modules/services/networking/aria2.nix b/nixos/modules/services/networking/aria2.nix index f32f5682c9801..f0d5c5c8a21e3 100644 --- a/nixos/modules/services/networking/aria2.nix +++ b/nixos/modules/services/networking/aria2.nix @@ -1,98 +1,132 @@ { config, lib, pkgs, ... }: -with lib; - let cfg = config.services.aria2; homeDir = "/var/lib/aria2"; - - settingsDir = "${homeDir}"; - sessionFile = "${homeDir}/aria2.session"; - downloadDir = "${homeDir}/Downloads"; - - rangesToStringList = map (x: builtins.toString x.from +"-"+ builtins.toString x.to); - - settingsFile = pkgs.writeText "aria2.conf" - '' - dir=${cfg.downloadDir} - listen-port=${concatStringsSep "," (rangesToStringList cfg.listenPortRange)} - rpc-listen-port=${toString cfg.rpcListenPort} - ''; - + defaultRpcListenPort = 6800; + defaultDir = "${homeDir}/Downloads"; + + portRangesToString = ranges: lib.concatStringsSep "," (map + (x: + if x.from == x.to + then builtins.toString x.from + else builtins.toString x.from + "-" + builtins.toString x.to + ) + ranges); + + customToKeyValue = lib.generators.toKeyValue { + mkKeyValue = lib.generators.mkKeyValueDefault + { + mkValueString = v: + if builtins.isList v then portRangesToString v + else lib.generators.mkValueStringDefault { } v; + } "="; + }; in { imports = [ - (mkRemovedOptionModule [ "services" "aria2" "rpcSecret" ] "Use services.aria2.rpcSecretFile instead") + (lib.mkRemovedOptionModule [ "services" "aria2" "rpcSecret" ] "Use services.aria2.rpcSecretFile instead") + (lib.mkRemovedOptionModule [ "services" "aria2" "extraArguments" ] "Use services.aria2.settings instead") + (lib.mkRenamedOptionModule [ "services" "aria2" "downloadDir" ] [ "services" "aria2" "settings" "dir" ]) + (lib.mkRenamedOptionModule [ "services" "aria2" "listenPortRange" ] [ "services" "aria2" "settings" "listen-port" ]) + (lib.mkRenamedOptionModule [ "services" "aria2" "rpcListenPort" ] [ "services" "aria2" "settings" "rpc-listen-port" ]) ]; options = { services.aria2 = { - enable = mkOption { - type = types.bool; + enable = lib.mkOption { + type = lib.types.bool; default = false; description = '' Whether or not to enable the headless Aria2 daemon service. - Aria2 daemon can be controlled via the RPC interface using - one of many WebUI (http://localhost:6800/ by default). + Aria2 daemon can be controlled via the RPC interface using one of many + WebUIs (http://localhost:${toString defaultRpcListenPort}/ by default). - Targets are downloaded to ${downloadDir} by default and are - accessible to users in the "aria2" group. + Targets are downloaded to `${defaultDir}` by default and are + accessible to users in the `aria2` group. ''; }; - openPorts = mkOption { - type = types.bool; + openPorts = lib.mkOption { + type = lib.types.bool; default = false; description = '' - Open listen and RPC ports found in listenPortRange and rpcListenPort - options in the firewall. - ''; - }; - downloadDir = mkOption { - type = types.path; - default = downloadDir; - description = '' - Directory to store downloaded files. - ''; - }; - listenPortRange = mkOption { - type = types.listOf types.attrs; - default = [ { from = 6881; to = 6999; } ]; - description = '' - Set UDP listening port range used by DHT(IPv4, IPv6) and UDP tracker. + Open listen and RPC ports found in `settings.listen-port` and + `settings.rpc-listen-port` options in the firewall. ''; }; - rpcListenPort = mkOption { - type = types.int; - default = 6800; - description = "Specify a port number for JSON-RPC/XML-RPC server to listen to. Possible Values: 1024-65535"; - }; - rpcSecretFile = mkOption { - type = types.path; + rpcSecretFile = lib.mkOption { + type = lib.types.path; example = "/run/secrets/aria2-rpc-token.txt"; description = '' A file containing the RPC secret authorization token. Read https://aria2.github.io/manual/en/html/aria2c.html#rpc-auth to know how this option value is used. ''; }; - extraArguments = mkOption { - type = types.separatedString " "; - example = "--rpc-listen-all --remote-time=true"; - default = ""; + settings = lib.mkOption { description = '' - Additional arguments to be passed to Aria2. + Generates the `aria2.conf` file. Refer to [the documentation][0] for + all possible settings. + + [0]: https://aria2.github.io/manual/en/html/aria2c.html#synopsis ''; + default = { }; + type = lib.types.submodule { + freeformType = with lib.types; attrsOf (oneOf [ bool int float singleLineStr ]); + options = { + save-session = lib.mkOption { + type = lib.types.singleLineStr; + default = "${homeDir}/aria2.session"; + description = "Save error/unfinished downloads to FILE on exit."; + }; + dir = lib.mkOption { + type = lib.types.singleLineStr; + default = defaultDir; + description = "Directory to store downloaded files."; + }; + conf-path = lib.mkOption { + type = lib.types.singleLineStr; + default = "${homeDir}/aria2.conf"; + description = "Configuration file path."; + }; + enable-rpc = lib.mkOption { + type = lib.types.bool; + default = true; + description = "Enable JSON-RPC/XML-RPC server."; + }; + listen-port = lib.mkOption { + type = with lib.types; listOf (attrsOf port); + default = [{ from = 6881; to = 6999; }]; + description = "Set UDP listening port range used by DHT(IPv4, IPv6) and UDP tracker."; + }; + rpc-listen-port = lib.mkOption { + type = lib.types.port; + default = defaultRpcListenPort; + description = "Specify a port number for JSON-RPC/XML-RPC server to listen to. Possible Values: 1024-65535"; + }; + }; + }; }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { + assertions = [ + { + assertion = cfg.settings.enable-rpc; + message = "RPC has to be enabled, the default module option takes care of that."; + } + { + assertion = !(cfg.settings ? rpc-secret); + message = "Set the RPC secret through services.aria2.rpcSecretFile so it will not end up in the world-readable nix store."; + } + ]; # Need to open ports for proper functioning - networking.firewall = mkIf cfg.openPorts { - allowedUDPPortRanges = config.services.aria2.listenPortRange; - allowedTCPPorts = [ config.services.aria2.rpcListenPort ]; + networking.firewall = lib.mkIf cfg.openPorts { + allowedUDPPortRanges = config.services.aria2.settings.listen-port; + allowedTCPPorts = [ config.services.aria2.settings.rpc-listen-port ]; }; users.users.aria2 = { @@ -107,7 +141,7 @@ in systemd.tmpfiles.rules = [ "d '${homeDir}' 0770 aria2 aria2 - -" - "d '${config.services.aria2.downloadDir}' 0770 aria2 aria2 - -" + "d '${config.services.aria2.settings.dir}' 0770 aria2 aria2 - -" ]; systemd.services.aria2 = { @@ -115,22 +149,25 @@ in after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; preStart = '' - if [[ ! -e "${sessionFile}" ]] + if [[ ! -e "${cfg.settings.save-session}" ]] then - touch "${sessionFile}" + touch "${cfg.settings.save-session}" fi - cp -f "${settingsFile}" "${settingsDir}/aria2.conf" - echo "rpc-secret=$(cat "$CREDENTIALS_DIRECTORY/rpcSecretFile")" >> "${settingsDir}/aria2.conf" + cp -f "${pkgs.writeText "aria2.conf" (customToKeyValue cfg.settings)}" "${cfg.settings.conf-path}" + chmod +w "${cfg.settings.conf-path}" + echo "rpc-secret=$(cat "$CREDENTIALS_DIRECTORY/rpcSecretFile")" >> "${cfg.settings.conf-path}" ''; serviceConfig = { Restart = "on-abort"; - ExecStart = "${pkgs.aria2}/bin/aria2c --enable-rpc --conf-path=${settingsDir}/aria2.conf ${config.services.aria2.extraArguments} --save-session=${sessionFile}"; + ExecStart = "${pkgs.aria2}/bin/aria2c --conf-path=${cfg.settings.conf-path}"; ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID"; User = "aria2"; Group = "aria2"; - LoadCredential="rpcSecretFile:${cfg.rpcSecretFile}"; + LoadCredential = "rpcSecretFile:${cfg.rpcSecretFile}"; }; }; }; + + meta.maintainers = [ lib.maintainers.timhae ]; } diff --git a/nixos/modules/services/networking/ddclient.nix b/nixos/modules/services/networking/ddclient.nix index b912550e1155e..272a50eb92de8 100644 --- a/nixos/modules/services/networking/ddclient.nix +++ b/nixos/modules/services/networking/ddclient.nix @@ -11,7 +11,9 @@ let # This file can be used as a template for configFile or is automatically generated by Nix options. cache=${dataDir}/ddclient.cache foreground=YES - use=${cfg.use} + ${lib.optionalString (cfg.use != "") "use=${cfg.use}"} + ${lib.optionalString (cfg.use == "" && cfg.usev4 != "") "usev4=${cfg.usev4}"} + ${lib.optionalString (cfg.use == "" && cfg.usev6 != "") "usev6=${cfg.usev6}"} login=${cfg.username} password=${if cfg.protocol == "nsupdate" then "/run/${RuntimeDirectory}/ddclient.key" else "@password_placeholder@"} protocol=${cfg.protocol} @@ -163,12 +165,26 @@ with lib; }; use = mkOption { - default = "web, web=checkip.dyndns.com/, web-skip='Current IP Address: '"; + default = ""; type = str; description = '' Method to determine the IP address to send to the dynamic DNS provider. ''; }; + usev4 = mkOption { + default = "webv4, webv4=checkip.dyndns.com/, webv4-skip='Current IP Address: '"; + type = str; + description = '' + Method to determine the IPv4 address to send to the dynamic DNS provider. Only used if `use` is not set. + ''; + }; + usev6 = mkOption { + default = "webv6, webv6=checkipv6.dyndns.com/, webv6-skip='Current IP Address: '"; + type = str; + description = '' + Method to determine the IPv6 address to send to the dynamic DNS provider. Only used if `use` is not set. + ''; + }; verbose = mkOption { default = false; @@ -204,6 +220,8 @@ with lib; ###### implementation config = mkIf config.services.ddclient.enable { + warnings = lib.optional (cfg.use != "") "Setting `use` is deprecated, ddclient now supports `usev4` and `usev6` for separate IPv4/IPv6 configuration."; + systemd.services.ddclient = { description = "Dynamic DNS Client"; wantedBy = [ "multi-user.target" ]; diff --git a/nixos/modules/services/networking/frr.nix b/nixos/modules/services/networking/frr.nix index 7f611ce7b1c7d..df2b4035d2f07 100644 --- a/nixos/modules/services/networking/frr.nix +++ b/nixos/modules/services/networking/frr.nix @@ -23,10 +23,9 @@ let "pbr" "bfd" "fabric" - "mgmt" ]; - allServices = services ++ [ "zebra" ]; + allServices = services ++ [ "zebra" "mgmt" ]; isEnabled = service: cfg.${service}.enable; @@ -137,6 +136,20 @@ in ''; }; }; + mgmt = (serviceOptions "mgmt") // { + enable = mkOption { + type = types.bool; + default = isEnabled "static"; + defaultText = lib.literalExpression "config.services.frr.static.enable"; + description = '' + Whether to enable the Configuration management daemon. + + The Configuration management daemon is automatically + enabled if needed, at the moment this is when staticd + is enabled. + ''; + }; + }; }; } { options.services.frr = (genAttrs services serviceOptions); } @@ -164,7 +177,7 @@ in environment.etc = let mkEtcLink = service: { - name = "frr/${service}.conf"; + name = "frr/${daemonName service}.conf"; value.source = configFile service; }; in @@ -196,18 +209,18 @@ in unitConfig.Documentation = if service == "zebra" then "man:zebra(8)" else "man:${daemon}(8) man:zebra(8)"; - restartTriggers = [ + restartTriggers = mkIf (service != "mgmt") [ (configFile service) ]; - reloadIfChanged = true; + reloadIfChanged = (service != "mgmt"); serviceConfig = { PIDFile = "frr/${daemon}.pid"; - ExecStart = "${pkgs.frr}/libexec/frr/${daemon} -f /etc/frr/${service}.conf" + ExecStart = "${pkgs.frr}/libexec/frr/${daemon}" + optionalString (scfg.vtyListenAddress != "") " -A ${scfg.vtyListenAddress}" + optionalString (scfg.vtyListenPort != null) " -P ${toString scfg.vtyListenPort}" + " " + (concatStringsSep " " scfg.extraOptions); - ExecReload = "${pkgs.python3.interpreter} ${pkgs.frr}/libexec/frr/frr-reload.py --reload --daemon ${daemonName service} --bindir ${pkgs.frr}/bin --rundir /run/frr /etc/frr/${service}.conf"; + ExecReload = mkIf (service != "mgmt") "${pkgs.python3.interpreter} ${pkgs.frr}/libexec/frr/frr-reload.py --reload --daemon ${daemon} --bindir ${pkgs.frr}/bin --rundir /run/frr /etc/frr/${daemon}.conf"; Restart = "on-abnormal"; }; }); diff --git a/nixos/modules/services/networking/git-daemon.nix b/nixos/modules/services/networking/git-daemon.nix index 6be72505c216e..522e6b14f868f 100644 --- a/nixos/modules/services/networking/git-daemon.nix +++ b/nixos/modules/services/networking/git-daemon.nix @@ -27,6 +27,8 @@ in ''; }; + package = mkPackageOption pkgs "git" { }; + basePath = mkOption { type = types.str; default = ""; @@ -119,7 +121,7 @@ in systemd.services.git-daemon = { after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; - script = "${pkgs.git}/bin/git daemon --reuseaddr " + script = "${getExe cfg.package} daemon --reuseaddr " + (optionalString (cfg.basePath != "") "--base-path=${cfg.basePath} ") + (optionalString (cfg.listenAddress != "") "--listen=${cfg.listenAddress} ") + "--port=${toString cfg.port} --user=${cfg.user} --group=${cfg.group} ${cfg.options} " diff --git a/nixos/modules/services/networking/inadyn.nix b/nixos/modules/services/networking/inadyn.nix index baa4302096c2c..7022673538c8a 100644 --- a/nixos/modules/services/networking/inadyn.nix +++ b/nixos/modules/services/networking/inadyn.nix @@ -202,7 +202,7 @@ in startAt = cfg.interval; serviceConfig = { Type = "oneshot"; - ExecStart = ''${lib.getExe pkgs.inadyn} -f ${configFile} --cache-dir ''${CACHE_DIRECTORY}/inadyn -1 --foreground -l ${cfg.logLevel}''; + ExecStart = ''${lib.getExe pkgs.inadyn} -f ${configFile} --cache-dir ''${CACHE_DIRECTORY} -1 --foreground -l ${cfg.logLevel}''; LoadCredential = "config:${configFile}"; CacheDirectory = "inadyn"; diff --git a/nixos/modules/services/networking/kea.nix b/nixos/modules/services/networking/kea.nix index 66173c145d16a..11add600b66fb 100644 --- a/nixos/modules/services/networking/kea.nix +++ b/nixos/modules/services/networking/kea.nix @@ -278,6 +278,9 @@ in "https://kea.readthedocs.io/en/kea-${package.version}/arm/agent.html" ]; + wants = [ + "network-online.target" + ]; after = [ "network-online.target" "time-sync.target" diff --git a/nixos/modules/services/networking/mihomo.nix b/nixos/modules/services/networking/mihomo.nix index 312530caeaade..d4bb10496279d 100644 --- a/nixos/modules/services/networking/mihomo.nix +++ b/nixos/modules/services/networking/mihomo.nix @@ -25,6 +25,7 @@ in webui = lib.mkOption { default = null; type = lib.types.nullOr lib.types.path; + example = lib.literalExpression "pkgs.metacubexd"; description = '' Local web interface to use. diff --git a/nixos/modules/services/networking/mycelium.nix b/nixos/modules/services/networking/mycelium.nix index 9487a5daafee0..0d0b2945af4c1 100644 --- a/nixos/modules/services/networking/mycelium.nix +++ b/nixos/modules/services/networking/mycelium.nix @@ -60,6 +60,8 @@ in networking.firewall.allowedTCPPorts = lib.optionals cfg.openFirewall [ 9651 ]; networking.firewall.allowedUDPPorts = lib.optionals cfg.openFirewall [ 9650 9651 ]; + environment.systemPackages = [ cfg.package ]; + systemd.services.mycelium = { description = "Mycelium network"; after = [ "network.target" ]; diff --git a/nixos/modules/services/networking/netbird/coturn.nix b/nixos/modules/services/networking/netbird/coturn.nix index 746d70a07250d..29ff1e8fc15ee 100644 --- a/nixos/modules/services/networking/netbird/coturn.nix +++ b/nixos/modules/services/networking/netbird/coturn.nix @@ -60,6 +60,7 @@ in default = null; description = '' The password of the user used by netbird to connect to the coturn server. + Be advised this will be world readable in the nix store. ''; }; @@ -142,7 +143,11 @@ in ]; }); - security.acme.certs.${cfg.domain}.postRun = optionalString cfg.useAcmeCertificates "systemctl restart coturn.service"; + security.acme.certs = mkIf cfg.useAcmeCertificates { + ${cfg.domain}.postRun = '' + systemctl restart coturn.service + ''; + }; networking.firewall = { allowedUDPPorts = cfg.openPorts; diff --git a/nixos/modules/services/networking/netbird/server.nix b/nixos/modules/services/networking/netbird/server.nix index a4de0fda6a134..2b6ad696646e9 100644 --- a/nixos/modules/services/networking/netbird/server.nix +++ b/nixos/modules/services/networking/netbird/server.nix @@ -2,6 +2,7 @@ let inherit (lib) + mkDefault mkEnableOption mkIf mkOption @@ -15,7 +16,7 @@ in { meta = { - maintainers = with lib.maintainers; [ thubrecht ]; + maintainers = with lib.maintainers; [thubrecht patrickdag]; doc = ./server.md; }; @@ -41,26 +42,46 @@ in config = mkIf cfg.enable { services.netbird.server = { dashboard = { - inherit (cfg) enable domain enableNginx; + domain = mkDefault cfg.domain; + enable = mkDefault cfg.enable; + enableNginx = mkDefault cfg.enableNginx; managementServer = "https://${cfg.domain}"; }; management = { - inherit (cfg) enable domain enableNginx; + domain = mkDefault cfg.domain; + enable = mkDefault cfg.enable; + enableNginx = mkDefault cfg.enableNginx; } - // (optionalAttrs cfg.coturn.enable { + // (optionalAttrs cfg.coturn.enable rec { turnDomain = cfg.domain; turnPort = config.services.coturn.tls-listening-port; + # We cannot merge a list of attrsets so we have to redefine the whole list + settings = { + TURNConfig.Turns = mkDefault [ + { + Proto = "udp"; + URI = "turn:${turnDomain}:${builtins.toString turnPort}"; + Username = "netbird"; + Password = + if (cfg.coturn.password != null) + then cfg.coturn.password + else {_secret = cfg.coturn.passwordFile;}; + } + ]; + }; }); signal = { - inherit (cfg) enable domain enableNginx; + domain = mkDefault cfg.domain; + enable = mkDefault cfg.enable; + enableNginx = mkDefault cfg.enableNginx; }; coturn = { - inherit (cfg) domain; + domain = mkDefault cfg.domain; }; }; }; diff --git a/nixos/modules/services/networking/oink.nix b/nixos/modules/services/networking/oink.nix new file mode 100644 index 0000000000000..cd0fdf172331d --- /dev/null +++ b/nixos/modules/services/networking/oink.nix @@ -0,0 +1,84 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.oink; + makeOinkConfig = attrs: (pkgs.formats.json { }).generate + "oink.json" (mapAttrs' (k: v: nameValuePair (toLower k) v) attrs); + oinkConfig = makeOinkConfig { + global = cfg.settings; + domains = cfg.domains; + }; +in +{ + options.services.oink = { + enable = mkEnableOption "Oink, a dynamic DNS client for Porkbun"; + package = mkPackageOption pkgs "oink" { }; + settings = { + apiKey = mkOption { + type = types.str; + description = "API key to use when modifying DNS records."; + }; + secretApiKey = mkOption { + type = types.str; + description = "Secret API key to use when modifying DNS records."; + }; + interval = mkOption { + # https://github.com/rlado/oink/blob/v1.1.1/src/main.go#L364 + type = types.ints.between 60 172800; # 48 hours + default = 900; + description = "Seconds to wait before sending another request."; + }; + ttl = mkOption { + type = types.ints.between 600 172800; + default = 600; + description = '' + The TTL ("Time to Live") value to set for your DNS records. + + The TTL controls how long in seconds your records will be cached + for. A smaller value will allow the record to update quicker. + ''; + }; + }; + domains = mkOption { + type = with types; listOf (attrsOf anything); + default = []; + example = [ + { + domain = "nixos.org"; + subdomain = ""; + ttl = 1200; + } + { + domain = "nixos.org"; + subdomain = "hydra"; + } + ]; + description = '' + List of attribute sets containing configuration for each domain. + + Each attribute set must have two attributes, one named *domain* + and another named *subdomain*. The domain attribute must specify + the root domain that you want to configure, and the subdomain + attribute must specify its subdomain if any. If you want to + configure the root domain rather than a subdomain, leave the + subdomain attribute as an empty string. + + Additionally, you can use attributes from *services.oink.settings* + to override settings per-domain. + + Every domain listed here *must* have API access enabled in + Porkbun's control panel. + ''; + }; + }; + + config = mkIf cfg.enable { + systemd.services.oink = { + description = "Dynamic DNS client for Porkbun"; + wantedBy = [ "multi-user.target" ]; + script = "${cfg.package}/bin/oink -c ${oinkConfig}"; + }; + }; +} diff --git a/nixos/modules/services/networking/rosenpass.nix b/nixos/modules/services/networking/rosenpass.nix index 373a6c7690799..92ecc1cb31a36 100644 --- a/nixos/modules/services/networking/rosenpass.nix +++ b/nixos/modules/services/networking/rosenpass.nix @@ -130,8 +130,8 @@ in relevant = config.systemd.network.enable; root = config.systemd.network.netdevs; peer = (x: x.wireguardPeers); - key = (x: if x.wireguardPeerConfig ? PublicKey then x.wireguardPeerConfig.PublicKey else null); - description = "${options.systemd.network.netdevs}.\"\".wireguardPeers.*.wireguardPeerConfig.PublicKey"; + key = x: x.PublicKey or null; + description = "${options.systemd.network.netdevs}.\"\".wireguardPeers.*.PublicKey"; } { relevant = config.networking.wireguard.enable; @@ -225,8 +225,10 @@ in # See environment.CONFIG = "%t/${serviceConfig.RuntimeDirectory}/config.toml"; - preStart = "${getExe pkgs.envsubst} -i ${config} -o \"$CONFIG\""; - script = "rosenpass exchange-config \"$CONFIG\""; + script = '' + ${getExe pkgs.envsubst} -i ${config} -o "$CONFIG" + rosenpass exchange-config "$CONFIG" + ''; }; }; } diff --git a/nixos/modules/services/networking/ssh/sshd.nix b/nixos/modules/services/networking/ssh/sshd.nix index 0fdb708bf052f..1e4e34a4f1675 100644 --- a/nixos/modules/services/networking/ssh/sshd.nix +++ b/nixos/modules/services/networking/ssh/sshd.nix @@ -5,11 +5,11 @@ with lib; let # The splicing information needed for nativeBuildInputs isn't available - # on the derivations likely to be used as `cfgc.package`. + # on the derivations likely to be used as `cfg.package`. # This middle-ground solution ensures *an* sshd can do their basic validation # on the configuration. validationPackage = if pkgs.stdenv.buildPlatform == pkgs.stdenv.hostPlatform - then cfgc.package + then cfg.package else pkgs.buildPackages.openssh; # dont use the "=" operator @@ -169,6 +169,13 @@ in ''; }; + package = mkOption { + type = types.package; + default = config.programs.ssh.package; + defaultText = literalExpression "programs.ssh.package"; + description = "OpenSSH package to use for sshd."; + }; + startWhenNeeded = mkOption { type = types.bool; default = false; @@ -342,7 +349,7 @@ in freeformType = settingsFormat.type; options = { AuthorizedPrincipalsFile = mkOption { - type = types.str; + type = types.nullOr types.str; default = "none"; # upstream default description = '' Specifies a file that lists principal names that are accepted for certificate authentication. The default @@ -350,16 +357,18 @@ in ''; }; LogLevel = mkOption { - type = types.enum [ "QUIET" "FATAL" "ERROR" "INFO" "VERBOSE" "DEBUG" "DEBUG1" "DEBUG2" "DEBUG3" ]; + type = types.nullOr (types.enum [ "QUIET" "FATAL" "ERROR" "INFO" "VERBOSE" "DEBUG" "DEBUG1" "DEBUG2" "DEBUG3" ]); default = "INFO"; # upstream default description = '' Gives the verbosity level that is used when logging messages from sshd(8). Logging with a DEBUG level violates the privacy of users and is not recommended. ''; }; - UsePAM = mkEnableOption "PAM authentication" // { default = true; }; + UsePAM = + mkEnableOption "PAM authentication" + // { default = true; type = types.nullOr types.bool; }; UseDns = mkOption { - type = types.bool; + type = types.nullOr types.bool; # apply if cfg.useDns then "yes" else "no" default = false; description = '' @@ -370,14 +379,14 @@ in ''; }; X11Forwarding = mkOption { - type = types.bool; + type = types.nullOr types.bool; default = false; description = '' Whether to allow X11 connections to be forwarded. ''; }; PasswordAuthentication = mkOption { - type = types.bool; + type = types.nullOr types.bool; default = true; description = '' Specifies whether password authentication is allowed. @@ -385,20 +394,20 @@ in }; PermitRootLogin = mkOption { default = "prohibit-password"; - type = types.enum ["yes" "without-password" "prohibit-password" "forced-commands-only" "no"]; + type = types.nullOr (types.enum ["yes" "without-password" "prohibit-password" "forced-commands-only" "no"]); description = '' Whether the root user can login using ssh. ''; }; KbdInteractiveAuthentication = mkOption { - type = types.bool; + type = types.nullOr types.bool; default = true; description = '' Specifies whether keyboard-interactive authentication is allowed. ''; }; GatewayPorts = mkOption { - type = types.str; + type = types.nullOr types.str; default = "no"; description = '' Specifies whether remote hosts are allowed to connect to @@ -407,7 +416,7 @@ in ''; }; KexAlgorithms = mkOption { - type = types.listOf types.str; + type = types.nullOr (types.listOf types.str); default = [ "sntrup761x25519-sha512@openssh.com" "curve25519-sha256" @@ -424,7 +433,7 @@ in ''; }; Macs = mkOption { - type = types.listOf types.str; + type = types.nullOr (types.listOf types.str); default = [ "hmac-sha2-512-etm@openssh.com" "hmac-sha2-256-etm@openssh.com" @@ -440,14 +449,14 @@ in ''; }; StrictModes = mkOption { - type = types.bool; + type = types.nullOr (types.bool); default = true; description = '' Whether sshd should check file modes and ownership of directories ''; }; Ciphers = mkOption { - type = types.listOf types.str; + type = types.nullOr (types.listOf types.str); default = [ "chacha20-poly1305@openssh.com" "aes256-gcm@openssh.com" @@ -502,7 +511,9 @@ in ''; }; # Disabled by default, since pam_motd handles this. - PrintMotd = mkEnableOption "printing /etc/motd when a user logs in interactively"; + PrintMotd = + mkEnableOption "printing /etc/motd when a user logs in interactively" + // { type = types.nullOr types.bool; }; }; }); }; @@ -544,8 +555,8 @@ in }; users.groups.sshd = {}; - services.openssh.moduliFile = mkDefault "${cfgc.package}/etc/ssh/moduli"; - services.openssh.sftpServerExecutable = mkDefault "${cfgc.package}/libexec/sftp-server"; + services.openssh.moduliFile = mkDefault "${cfg.package}/etc/ssh/moduli"; + services.openssh.sftpServerExecutable = mkDefault "${cfg.package}/libexec/sftp-server"; environment.etc = authKeysFiles // authPrincipalsFiles // { "ssh/moduli".source = cfg.moduliFile; @@ -559,7 +570,7 @@ in wantedBy = optional (!cfg.startWhenNeeded) "multi-user.target"; after = [ "network.target" ]; stopIfChanged = false; - path = [ cfgc.package pkgs.gawk ]; + path = [ cfg.package pkgs.gawk ]; environment.LD_LIBRARY_PATH = nssModulesPath; restartTriggers = optionals (!cfg.startWhenNeeded) [ @@ -593,7 +604,7 @@ in serviceConfig = { ExecStart = (optionalString cfg.startWhenNeeded "-") + - "${cfgc.package}/bin/sshd " + (optionalString cfg.startWhenNeeded "-i ") + + "${cfg.package}/bin/sshd " + (optionalString cfg.startWhenNeeded "-i ") + "-D " + # don't detach into a daemon process "-f /etc/ssh/sshd_config"; KillMode = "process"; @@ -639,7 +650,10 @@ in security.pam.services.sshd = lib.mkIf cfg.settings.UsePAM { startSession = true; showMotd = true; - unixAuth = cfg.settings.PasswordAuthentication; + unixAuth = + if cfg.settings.PasswordAuthentication == true + then true + else false; }; # These values are merged with the ones defined externally, see: @@ -701,6 +715,10 @@ in assertions = [{ assertion = if cfg.settings.X11Forwarding then cfgc.setXAuthLocation else true; message = "cannot enable X11 forwarding without setting xauth location";} + { assertion = (builtins.match "(.*\n)?(\t )*[Kk][Ee][Rr][Bb][Ee][Rr][Oo][Ss][Aa][Uu][Tt][Hh][Ee][Nn][Tt][Ii][Cc][Aa][Tt][Ii][Oo][Nn][ |\t|=|\"]+yes.*" "${configFile}\n${cfg.extraConfig}") != null -> cfgc.package.withKerberos; + message = "cannot enable Kerberos authentication without using a package with Kerberos support";} + { assertion = (builtins.match "(.*\n)?(\t )*[Gg][Ss][Ss][Aa][Pp][Ii][Aa][Uu][Tt][Hh][Ee][Nn][Tt][Ii][Cc][Aa][Tt][Ii][Oo][Nn][ |\t|=|\"]+yes.*" "${configFile}\n${cfg.extraConfig}") != null -> cfgc.package.withKerberos; + message = "cannot enable GSSAPI authentication without using a package with Kerberos support";} (let duplicates = # Filter out the groups with more than 1 element diff --git a/nixos/modules/services/networking/tailscale-auth.nix b/nixos/modules/services/networking/tailscale-auth.nix index c3a515212e782..f21d1f108911c 100644 --- a/nixos/modules/services/networking/tailscale-auth.nix +++ b/nixos/modules/services/networking/tailscale-auth.nix @@ -14,7 +14,7 @@ let in { options.services.tailscaleAuth = { - enable = mkEnableOption "Enable tailscale.nginx-auth, to authenticate users via tailscale."; + enable = mkEnableOption "tailscale.nginx-auth, to authenticate users via tailscale"; package = mkPackageOption pkgs "tailscale-nginx-auth" {}; diff --git a/nixos/modules/services/networking/tailscale.nix b/nixos/modules/services/networking/tailscale.nix index a79e47d8491b8..a690dc610e825 100644 --- a/nixos/modules/services/networking/tailscale.nix +++ b/nixos/modules/services/networking/tailscale.nix @@ -61,12 +61,21 @@ in { }; extraUpFlags = mkOption { - description = "Extra flags to pass to {command}`tailscale up`."; + description = '' + Extra flags to pass to {command}`tailscale up`. Only applied if `authKeyFile` is specified."; + ''; type = types.listOf types.str; default = []; example = ["--ssh"]; }; + extraSetFlags = mkOption { + description = "Extra flags to pass to {command}`tailscale set`."; + type = types.listOf types.str; + default = []; + example = ["--advertise-exit-node"]; + }; + extraDaemonFlags = mkOption { description = "Extra flags to pass to {command}`tailscaled`."; type = types.listOf types.str; @@ -120,6 +129,18 @@ in { ''; }; + systemd.services.tailscaled-set = mkIf (cfg.extraSetFlags != []) { + after = ["tailscaled.service"]; + wants = ["tailscaled.service"]; + wantedBy = [ "multi-user.target" ]; + serviceConfig = { + Type = "oneshot"; + }; + script = '' + ${cfg.package}/bin/tailscale set ${escapeShellArgs cfg.extraSetFlags} + ''; + }; + boot.kernel.sysctl = mkIf (cfg.useRoutingFeatures == "server" || cfg.useRoutingFeatures == "both") { "net.ipv4.conf.all.forwarding" = mkOverride 97 true; "net.ipv6.conf.all.forwarding" = mkOverride 97 true; diff --git a/nixos/modules/services/networking/wireguard.nix b/nixos/modules/services/networking/wireguard.nix index 3f68af3a86c96..81abae2c9303d 100644 --- a/nixos/modules/services/networking/wireguard.nix +++ b/nixos/modules/services/networking/wireguard.nix @@ -80,6 +80,15 @@ let description = "Commands called at the end of the interface setup."; }; + preShutdown = mkOption { + example = literalExpression ''"''${pkgs.iproute2}/bin/ip netns del foo"''; + default = ""; + type = with types; coercedTo (listOf str) (concatStringsSep "\n") lines; + description = '' + Commands called before shutting down the interface. + ''; + }; + postShutdown = mkOption { example = literalExpression ''"''${pkgs.openresolv}/bin/resolvconf -d wg0"''; default = ""; @@ -497,6 +506,7 @@ let ''; postStop = '' + ${values.preShutdown} ${ipPostMove} link del dev "${name}" ${values.postShutdown} ''; diff --git a/nixos/modules/services/networking/wstunnel.nix b/nixos/modules/services/networking/wstunnel.nix index efb65aead116a..1b169567624c0 100644 --- a/nixos/modules/services/networking/wstunnel.nix +++ b/nixos/modules/services/networking/wstunnel.nix @@ -7,6 +7,9 @@ let (name: value: if value == true then "--${name}" else "--${name}=${value}") attrs ); + + hostPortToString = { host, port }: "${host}:${builtins.toString port}"; + hostPortSubmodule = { options = { host = mkOption { @@ -19,28 +22,7 @@ let }; }; }; - localRemoteSubmodule = { - options = { - local = mkOption { - description = "Local address and port to listen on."; - type = types.submodule hostPortSubmodule; - example = { - host = "127.0.0.1"; - port = 51820; - }; - }; - remote = mkOption { - description = "Address and port on remote to forward traffic to."; - type = types.submodule hostPortSubmodule; - example = { - host = "127.0.0.1"; - port = 51820; - }; - }; - }; - }; - hostPortToString = { host, port }: "${host}:${builtins.toString port}"; - localRemoteToString = { local, remote }: utils.escapeSystemdExecArg "${hostPortToString local}:${hostPortToString remote}"; + commonOptions = { enable = mkOption { description = "Whether to enable this `wstunnel` instance."; @@ -66,10 +48,16 @@ let }; }; - verboseLogging = mkOption { - description = "Enable verbose logging."; - type = types.bool; - default = false; + loggingLevel = mkOption { + description = '' + Passed to --log-lvl + + Control the log verbosity. i.e: TRACE, DEBUG, INFO, WARN, ERROR, OFF + For more details, checkout [EnvFilter](https://docs.rs/tracing-subscriber/latest/tracing_subscriber/filter/struct.EnvFilter.html#example-syntax) + ''; + type = types.nullOr types.str; + example = "INFO"; + default = null; }; environmentFile = mkOption { @@ -99,11 +87,12 @@ let restrictTo = mkOption { description = "Accepted traffic will be forwarded only to this service. Set to `null` to allow forwarding to arbitrary addresses."; - type = types.nullOr (types.submodule hostPortSubmodule); - example = { + type = types.listOf (types.submodule hostPortSubmodule); + default = []; + example = [{ host = "127.0.0.1"; port = 51820; - }; + }]; }; enableHTTPS = mkOption { @@ -134,59 +123,36 @@ let }; }; }; + clientSubmodule = { config, ... }: { options = commonOptions // { connectTo = mkOption { description = "Server address and port to connect to."; - type = types.submodule hostPortSubmodule; - example = { - host = "example.com"; - }; - }; - - enableHTTPS = mkOption { - description = "Enable HTTPS when connecting to the server."; - type = types.bool; - default = true; + type = types.str; + example = "https://wstunnel.server.com:8443"; }; localToRemote = mkOption { - description = "Local hosts and ports to listen on, plus the hosts and ports on remote to forward traffic to. Setting a local port to a value less than 1024 will additionally give the process the required CAP_NET_BIND_SERVICE capability."; - type = types.listOf (types.submodule localRemoteSubmodule); + description = ''Listen on local and forwards traffic from remote.''; + type = types.listOf (types.str); default = []; - example = [ { - local = { - host = "127.0.0.1"; - port = 8080; - }; - remote = { - host = "127.0.0.1"; - port = 8080; - }; - } ]; + example = [ + "tcp://1212:google.com:443" + "unix:///tmp/wstunnel.sock:g.com:443" + ]; }; - dynamicToRemote = mkOption { - description = "Host and port for the SOCKS5 proxy to dynamically forward traffic to. Leave this at `null` to disable the SOCKS5 proxy. Setting the port to a value less than 1024 will additionally give the service the required CAP_NET_BIND_SERVICE capability."; - type = types.nullOr (types.submodule hostPortSubmodule); - default = null; - example = { - host = "127.0.0.1"; - port = 1080; - }; - }; - - udp = mkOption { - description = "Whether to forward UDP instead of TCP traffic."; - type = types.bool; - default = false; + remoteToLocal = mkOption { + description = "Listen on remote and forwards traffic from local. Only tcp is supported"; + type = types.listOf (types.str); + default = []; + example = [ + "tcp://1212:google.com:443" + "unix://wstunnel.sock:g.com:443" + ]; }; - udpTimeout = mkOption { - description = "When using UDP forwarding, timeout in seconds after which the tunnel connection is closed. `-1` means no timeout."; - type = types.int; - default = 30; - }; + addNetBind = mkEnableOption "Whether add CAP_NET_BIND_SERVICE to the tunnel service, this should be enabled if you want to bind port < 1024"; httpProxy = mkOption { description = '' @@ -214,12 +180,6 @@ let example = "wstunnel"; }; - hostHeader = mkOption { - description = "Use this as the HTTP host header instead of the real hostname. Useful for circumventing hostname-based firewalls."; - type = types.nullOr types.str; - default = null; - }; - tlsSNI = mkOption { description = "Use this as the SNI while connecting via TLS. Useful for circumventing hostname-based firewalls."; type = types.nullOr types.str; @@ -234,7 +194,7 @@ let # The original argument name `websocketPingFrequency` is a misnomer, as the frequency is the inverse of the interval. websocketPingInterval = mkOption { - description = "Do a heartbeat ping every N seconds to keep up the websocket connection."; + description = "Frequency at which the client will send websocket ping to the server."; type = types.nullOr types.ints.unsigned; default = null; }; @@ -261,6 +221,7 @@ let }; }; }; + generateServerUnit = name: serverCfg: { name = "wstunnel-server-${name}"; value = { @@ -282,11 +243,11 @@ let else tlsKey; in '' ${package}/bin/wstunnel \ - --server \ - ${optionalString (restrictTo != null) "--restrictTo=${utils.escapeSystemdExecArg (hostPortToString restrictTo)}"} \ - ${optionalString (resolvedTlsCertificate != null) "--tlsCertificate=${utils.escapeSystemdExecArg resolvedTlsCertificate}"} \ - ${optionalString (resolvedTlsKey != null) "--tlsKey=${utils.escapeSystemdExecArg resolvedTlsKey}"} \ - ${optionalString verboseLogging "--verbose"} \ + server \ + ${concatStringsSep " " (builtins.map (hostPair: "--restrict-to ${utils.escapeSystemdExecArg (hostPortToString hostPair)}") restrictTo)} \ + ${optionalString (resolvedTlsCertificate != null) "--tls-certificate ${utils.escapeSystemdExecArg resolvedTlsCertificate}"} \ + ${optionalString (resolvedTlsKey != null) "--tls-private-key ${utils.escapeSystemdExecArg resolvedTlsKey}"} \ + ${optionalString (loggingLevel != null) "--log-lvl ${loggingLevel}"} \ ${attrsToArgs extraArgs} \ ${utils.escapeSystemdExecArg "${if enableHTTPS then "wss" else "ws"}://${hostPortToString listen}"} ''; @@ -304,10 +265,10 @@ let ProtectControlGroups = true; PrivateDevices = true; RestrictSUIDSGID = true; - }; }; }; + generateClientUnit = name: clientCfg: { name = "wstunnel-client-${name}"; value = { @@ -319,28 +280,25 @@ let serviceConfig = { Type = "simple"; ExecStart = with clientCfg; '' - ${package}/bin/wstunnel \ - ${concatStringsSep " " (builtins.map (x: "--localToRemote=${localRemoteToString x}") localToRemote)} \ - ${concatStringsSep " " (mapAttrsToList (n: v: "--customHeaders=\"${n}: ${v}\"") customHeaders)} \ - ${optionalString (dynamicToRemote != null) "--dynamicToRemote=${utils.escapeSystemdExecArg (hostPortToString dynamicToRemote)}"} \ - ${optionalString udp "--udp"} \ - ${optionalString (httpProxy != null) "--httpProxy=${httpProxy}"} \ - ${optionalString (soMark != null) "--soMark=${toString soMark}"} \ - ${optionalString (upgradePathPrefix != null) "--upgradePathPrefix=${upgradePathPrefix}"} \ - ${optionalString (hostHeader != null) "--hostHeader=${hostHeader}"} \ - ${optionalString (tlsSNI != null) "--tlsSNI=${tlsSNI}"} \ - ${optionalString tlsVerifyCertificate "--tlsVerifyCertificate"} \ - ${optionalString (websocketPingInterval != null) "--websocketPingFrequency=${toString websocketPingInterval}"} \ - ${optionalString (upgradeCredentials != null) "--upgradeCredentials=${upgradeCredentials}"} \ - --udpTimeoutSec=${toString udpTimeout} \ - ${optionalString verboseLogging "--verbose"} \ + ${package}/bin/wstunnel client \ + ${concatStringsSep " " (builtins.map (x: "--local-to-remote ${x}") localToRemote)} \ + ${concatStringsSep " " (builtins.map (x: "--remote-to-local ${x}") remoteToLocal)} \ + ${concatStringsSep " " (mapAttrsToList (n: v: "--http-headers \"${n}: ${v}\"") customHeaders)} \ + ${optionalString (httpProxy != null) "--http-proxy ${httpProxy}"} \ + ${optionalString (soMark != null) "--socket-so-mark=${toString soMark}"} \ + ${optionalString (upgradePathPrefix != null) "--http-upgrade-path-prefix ${upgradePathPrefix}"} \ + ${optionalString (tlsSNI != null) "--tls-sni-override ${tlsSNI}"} \ + ${optionalString tlsVerifyCertificate "--tls-verify-certificate"} \ + ${optionalString (websocketPingInterval != null) "--websocket-ping-frequency-sec ${toString websocketPingInterval}"} \ + ${optionalString (upgradeCredentials != null) "--http-upgrade-credentials ${upgradeCredentials}"} \ + ${optionalString (loggingLevel != null) "--log-lvl ${loggingLevel}"} \ ${attrsToArgs extraArgs} \ - ${utils.escapeSystemdExecArg "${if enableHTTPS then "wss" else "ws"}://${hostPortToString connectTo}"} + ${utils.escapeSystemdExecArg connectTo} ''; EnvironmentFile = optional (clientCfg.environmentFile != null) clientCfg.environmentFile; DynamicUser = true; PrivateTmp = true; - AmbientCapabilities = (optionals (clientCfg.soMark != null) [ "CAP_NET_ADMIN" ]) ++ (optionals ((clientCfg.dynamicToRemote.port or 1024) < 1024 || (any (x: x.local.port < 1024) clientCfg.localToRemote)) [ "CAP_NET_BIND_SERVICE" ]); + AmbientCapabilities = (optionals (clientCfg.soMark != null) [ "CAP_NET_ADMIN" ]) ++ (optionals (clientCfg.addNetBind) [ "CAP_NET_BIND_SERVICE" ]); NoNewPrivileges = true; RestrictNamespaces = "uts ipc pid user cgroup"; ProtectSystem = "strict"; @@ -363,14 +321,17 @@ in { default = {}; example = { "wg-tunnel" = { - listen.port = 8080; + listen = { + host = "0.0.0.0"; + port = 8080; + }; enableHTTPS = true; tlsCertificate = "/var/lib/secrets/fullchain.pem"; tlsKey = "/var/lib/secrets/key.pem"; - restrictTo = { + restrictTo = [{ host = "127.0.0.1"; port = 51820; - }; + }]; }; }; }; @@ -381,22 +342,15 @@ in { default = {}; example = { "wg-tunnel" = { - connectTo = { - host = "example.com"; - port = 8080; - }; - enableHTTPS = true; - localToRemote = { - local = { - host = "127.0.0.1"; - port = 51820; - }; - remote = { - host = "127.0.0.1"; - port = 51820; - }; - }; - udp = true; + connectTo = "https://wstunnel.server.com:8443"; + localToRemote = [ + "tcp://1212:google.com:443" + "tcp://2:n.lan:4?proxy_protocol" + ]; + remoteToLocal = [ + "socks5://[::1]:1212" + "unix://wstunnel.sock:g.com:443" + ]; }; }; }; @@ -418,12 +372,12 @@ in { ''; }) cfg.servers) ++ (mapAttrsToList (name: clientCfg: { - assertion = !(clientCfg.localToRemote == [] && clientCfg.dynamicToRemote == null); + assertion = !(clientCfg.localToRemote == [] && clientCfg.remoteToLocal == []); message = '' - Either one of services.wstunnel.clients."${name}".localToRemote or services.wstunnel.clients."${name}".dynamicToRemote must be set. + Either one of services.wstunnel.clients."${name}".localToRemote or services.wstunnel.clients."${name}".remoteToLocal must be set. ''; }) cfg.clients); }; - meta.maintainers = with maintainers; [ alyaeanyx ]; + meta.maintainers = with maintainers; [ alyaeanyx neverbehave ]; } diff --git a/nixos/modules/services/search/quickwit.nix b/nixos/modules/services/search/quickwit.nix new file mode 100644 index 0000000000000..6b2db935cf0bf --- /dev/null +++ b/nixos/modules/services/search/quickwit.nix @@ -0,0 +1,190 @@ +{ config, lib, pkgs, ... }: + +with lib; + +let + cfg = config.services.quickwit; + + settingsFormat = pkgs.formats.yaml {}; + quickwitYml = settingsFormat.generate "quickwit.yml" cfg.settings; + + usingDefaultDataDir = cfg.dataDir == "/var/lib/quickwit"; + usingDefaultUserAndGroup = cfg.user == "quickwit" && cfg.group == "quickwit"; +in +{ + + options.services.quickwit = { + enable = mkEnableOption "Quickwit"; + + package = lib.mkPackageOption pkgs "Quickwit" { + default = [ "quickwit" ]; + }; + + settings = lib.mkOption { + type = lib.types.submodule { + freeformType = settingsFormat.type; + + options."rest" = lib.mkOption { + default = {}; + description = '' + Rest server configuration for Quickwit + ''; + + type = lib.types.submodule { + freeformType = settingsFormat.type; + + options."listen_port" = lib.mkOption { + type = lib.types.port; + default = 7280; + description = '' + The port to listen on for HTTP REST traffic. + ''; + }; + }; + }; + + options."grpc_listen_port" = lib.mkOption { + type = lib.types.port; + default = 7281; + description = '' + The port to listen on for gRPC traffic. + ''; + }; + + options."listen_address" = lib.mkOption { + type = lib.types.str; + default = "127.0.0.1"; + description = '' + Listen address of Quickwit. + ''; + }; + + options."version" = lib.mkOption { + type = lib.types.float; + default = 0.7; + description = '' + Configuration file version. + ''; + }; + }; + + default = {}; + + description = '' + Quickwit configuration. + ''; + }; + + dataDir = lib.mkOption { + type = lib.types.path; + default = "/var/lib/quickwit"; + apply = converge (removeSuffix "/"); + description = '' + Data directory for Quickwit. If you change this, you need to + manually create the directory. You also need to create the + `quickwit` user and group, or change + [](#opt-services.quickwit.user) and + [](#opt-services.quickwit.group) to existing ones with + access to the directory. + ''; + }; + + user = lib.mkOption { + type = lib.types.str; + default = "quickwit"; + description = '' + The user Quickwit runs as. Should be left at default unless + you have very specific needs. + ''; + }; + + group = lib.mkOption { + type = lib.types.str; + default = "quickwit"; + description = '' + The group quickwit runs as. Should be left at default unless + you have very specific needs. + ''; + }; + + extraFlags = lib.mkOption { + description = "Extra command line options to pass to Quickwit."; + default = [ ]; + type = lib.types.listOf lib.types.str; + }; + + restartIfChanged = lib.mkOption { + type = lib.types.bool; + description = '' + Automatically restart the service on config change. + This can be set to false to defer restarts on a server or cluster. + Please consider the security implications of inadvertently running an older version, + and the possibility of unexpected behavior caused by inconsistent versions across a cluster when disabling this option. + ''; + default = true; + }; + }; + + config = mkIf cfg.enable { + systemd.services.quickwit = { + description = "Quickwit"; + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + inherit (cfg) restartIfChanged; + environment = { + QW_DATA_DIR = cfg.dataDir; + }; + serviceConfig = { + ExecStart = '' + ${cfg.package}/bin/quickwit run --config ${quickwitYml} \ + ${escapeShellArgs cfg.extraFlags} + ''; + User = cfg.user; + Group = cfg.group; + Restart = "on-failure"; + DynamicUser = usingDefaultUserAndGroup && usingDefaultDataDir; + CapabilityBoundingSet = [ "" ]; + DevicePolicy = "closed"; + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateDevices = true; + ProcSubset = "pid"; + ProtectClock = true; + ProtectHome = true; + ProtectHostname = true; + ProtectControlGroups = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProtectSystem = "strict"; + ReadWritePaths = [ + "/var/lib/quickwit" + ]; + RestrictAddressFamilies = [ + "AF_NETLINK" + "AF_INET" + "AF_INET6" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + # 1. allow a reasonable set of syscalls + "@system-service @resources" + # 2. and deny unreasonable ones + "~@privileged" + # 3. then allow the required subset within denied groups + "@chown" + ]; + } // (optionalAttrs (usingDefaultDataDir) { + StateDirectory = "quickwit"; + StateDirectoryMode = "0700"; + }); + }; + + environment.systemPackages = [ cfg.package ]; + }; +} diff --git a/nixos/modules/services/security/bitwarden-directory-connector-cli.nix b/nixos/modules/services/security/bitwarden-directory-connector-cli.nix index d21322caf4c33..fef4a88648979 100644 --- a/nixos/modules/services/security/bitwarden-directory-connector-cli.nix +++ b/nixos/modules/services/security/bitwarden-directory-connector-cli.nix @@ -260,6 +260,7 @@ in { description = "Sync timer for Bitwarden Directory Connector"; wantedBy = ["timers.target"]; after = ["network-online.target"]; + wants = ["network-online.target"]; timerConfig = { OnCalendar = cfg.interval; Unit = "bitwarden-directory-connector-cli.service"; diff --git a/nixos/modules/services/security/oauth2-proxy-nginx.nix b/nixos/modules/services/security/oauth2-proxy-nginx.nix index 07192e7287b05..44bf56233e95e 100644 --- a/nixos/modules/services/security/oauth2-proxy-nginx.nix +++ b/nixos/modules/services/security/oauth2-proxy-nginx.nix @@ -83,6 +83,15 @@ in } ++ (lib.mapAttrsToList (vhost: conf: { virtualHosts.${vhost} = { locations = { + "/".extraConfig = '' + # pass information via X-User and X-Email headers to backend, requires running with --set-xauthrequest flag + proxy_set_header X-User $user; + proxy_set_header X-Email $email; + + # if you enabled --cookie-refresh, this is needed for it to work with auth_request + add_header Set-Cookie $auth_cookie; + ''; + "/oauth2/auth" = let maybeQueryArg = name: value: if value == null then null @@ -102,6 +111,7 @@ in proxy_pass_request_body off; ''; }; + "@redirectToAuth2ProxyLogin" = { return = "307 https://${cfg.domain}/oauth2/start?rd=$scheme://$host$request_uri"; extraConfig = '' @@ -114,16 +124,10 @@ in auth_request /oauth2/auth; error_page 401 = @redirectToAuth2ProxyLogin; - # pass information via X-User and X-Email headers to backend, - # requires running with --set-xauthrequest flag + # set variables being used in locations."/".extraConfig auth_request_set $user $upstream_http_x_auth_request_user; auth_request_set $email $upstream_http_x_auth_request_email; - proxy_set_header X-User $user; - proxy_set_header X-Email $email; - - # if you enabled --cookie-refresh, this is needed for it to work with auth_request auth_request_set $auth_cookie $upstream_http_set_cookie; - add_header Set-Cookie $auth_cookie; ''; }; }) cfg.virtualHosts))); diff --git a/nixos/modules/services/security/vaultwarden/default.nix b/nixos/modules/services/security/vaultwarden/default.nix index 33957be437b30..41f7de5d80fab 100644 --- a/nixos/modules/services/security/vaultwarden/default.nix +++ b/nixos/modules/services/security/vaultwarden/default.nix @@ -5,6 +5,8 @@ let user = config.users.users.vaultwarden.name; group = config.users.groups.vaultwarden.name; + StateDirectory = if lib.versionOlder config.system.stateVersion "24.11" then "bitwarden_rs" else "vaultwarden"; + # Convert name from camel case (e.g. disable2FARemember) to upper case snake case (e.g. DISABLE_2FA_REMEMBER). nameToEnvVar = name: let @@ -23,7 +25,7 @@ let configEnv = lib.concatMapAttrs (name: value: lib.optionalAttrs (value != null) { ${nameToEnvVar name} = if lib.isBool value then lib.boolToString value else toString value; }) cfg.config; - in { DATA_FOLDER = "/var/lib/bitwarden_rs"; } // lib.optionalAttrs (!(configEnv ? WEB_VAULT_ENABLED) || configEnv.WEB_VAULT_ENABLED == "true") { + in { DATA_FOLDER = "/var/lib/${StateDirectory}"; } // lib.optionalAttrs (!(configEnv ? WEB_VAULT_ENABLED) || configEnv.WEB_VAULT_ENABLED == "true") { WEB_VAULT_FOLDER = "${cfg.webVaultPackage}/share/vaultwarden/vault"; } // configEnv; @@ -176,16 +178,45 @@ in { User = user; Group = group; EnvironmentFile = [ configFile ] ++ lib.optional (cfg.environmentFile != null) cfg.environmentFile; - ExecStart = "${vaultwarden}/bin/vaultwarden"; + ExecStart = lib.getExe vaultwarden; LimitNOFILE = "1048576"; - PrivateTmp = "true"; - PrivateDevices = "true"; - ProtectHome = "true"; + CapabilityBoundingSet = [ "" ]; + DeviceAllow = [ "" ]; + DevicePolicy = "closed"; + LockPersonality = true; + MemoryDenyWriteExecute = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateTmp = true; + PrivateUsers = true; + ProcSubset = "pid"; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "noaccess"; ProtectSystem = "strict"; - AmbientCapabilities = "CAP_NET_BIND_SERVICE"; - StateDirectory = "bitwarden_rs"; + RemoveIPC = true; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + "AF_UNIX" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + inherit StateDirectory; StateDirectoryMode = "0700"; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "~@privileged" + ]; Restart = "always"; + UMask = "0077"; }; wantedBy = [ "multi-user.target" ]; }; @@ -193,7 +224,7 @@ in { systemd.services.backup-vaultwarden = lib.mkIf (cfg.backupDir != null) { description = "Backup vaultwarden"; environment = { - DATA_FOLDER = "/var/lib/bitwarden_rs"; + DATA_FOLDER = "/var/lib/${StateDirectory}"; BACKUP_FOLDER = cfg.backupDir; }; path = with pkgs; [ sqlite ]; diff --git a/nixos/modules/services/system/dbus.nix b/nixos/modules/services/system/dbus.nix index 26f4eba707f92..d84136125f934 100644 --- a/nixos/modules/services/system/dbus.nix +++ b/nixos/modules/services/system/dbus.nix @@ -128,10 +128,14 @@ in contents."/etc/dbus-1".source = pkgs.makeDBusConf { inherit (cfg) apparmor; suidHelper = "/bin/false"; - serviceDirectories = [ pkgs.dbus ]; + serviceDirectories = [ pkgs.dbus config.boot.initrd.systemd.package ]; }; packages = [ pkgs.dbus ]; - storePaths = [ "${pkgs.dbus}/bin/dbus-daemon" ]; + storePaths = [ + "${pkgs.dbus}/bin/dbus-daemon" + "${config.boot.initrd.systemd.package}/share/dbus-1/system-services" + "${config.boot.initrd.systemd.package}/share/dbus-1/system.d" + ]; targets.sockets.wants = [ "dbus.socket" ]; }; }) diff --git a/nixos/modules/services/system/kerberos/default.nix b/nixos/modules/services/system/kerberos/default.nix index 7fe970c9609a9..34c7c6c84f865 100644 --- a/nixos/modules/services/system/kerberos/default.nix +++ b/nixos/modules/services/system/kerberos/default.nix @@ -1,75 +1,59 @@ -{config, lib, ...}: +{ config, pkgs, lib, ... }: let - inherit (lib) mkOption mkIf types length attrNames; + inherit (lib) mkOption types; cfg = config.services.kerberos_server; - kerberos = config.security.krb5.package; + inherit (config.security.krb5) package; - aclEntry = { - options = { - principal = mkOption { - type = types.str; - description = "Which principal the rule applies to"; - }; - access = mkOption { - type = types.either - (types.listOf (types.enum ["add" "cpw" "delete" "get" "list" "modify"])) - (types.enum ["all"]); - default = "all"; - description = "The changes the principal is allowed to make."; - }; - target = mkOption { - type = types.str; - default = "*"; - description = "The principals that 'access' applies to."; - }; - }; - }; - - realm = { - options = { - acl = mkOption { - type = types.listOf (types.submodule aclEntry); - default = [ - { principal = "*/admin"; access = "all"; } - { principal = "admin"; access = "all"; } - ]; - description = '' - The privileges granted to a user. - ''; - }; - }; - }; + format = import ../../../security/krb5/krb5-conf-format.nix { inherit pkgs lib; } { enableKdcACLEntries = true; }; in { imports = [ + (lib.mkRenamedOptionModule [ "services" "kerberos_server" "realms" ] [ "services" "kerberos_server" "settings" "realms" ]) + ./mit.nix ./heimdal.nix ]; - ###### interface options = { services.kerberos_server = { enable = lib.mkEnableOption "the kerberos authentication server"; - realms = mkOption { - type = types.attrsOf (types.submodule realm); + settings = mkOption { + type = format.type; description = '' - The realm(s) to serve keys for. + Settings for the kerberos server of choice. + + See the following documentation: + - Heimdal: {manpage}`kdc.conf(5)` + - MIT Kerberos: ''; + default = { }; }; }; }; + config = lib.mkIf cfg.enable { + environment.systemPackages = [ package ]; + assertions = [ + { + assertion = cfg.settings.realms != { }; + message = "The server needs at least one realm"; + } + { + assertion = lib.length (lib.attrNames cfg.settings.realms) <= 1; + message = "Only one realm per server is currently supported."; + } + ]; + + systemd.slices.system-kerberos-server = { }; + systemd.targets.kerberos-server = { + wantedBy = [ "multi-user.target" ]; + }; + }; - ###### implementation - - config = mkIf cfg.enable { - environment.systemPackages = [ kerberos ]; - assertions = [{ - assertion = length (attrNames cfg.realms) <= 1; - message = "Only one realm per server is currently supported."; - }]; + meta = { + doc = ./kerberos-server.md; }; } diff --git a/nixos/modules/services/system/kerberos/heimdal.nix b/nixos/modules/services/system/kerberos/heimdal.nix index ecafc92766704..cec4dd276e6b9 100644 --- a/nixos/modules/services/system/kerberos/heimdal.nix +++ b/nixos/modules/services/system/kerberos/heimdal.nix @@ -1,68 +1,87 @@ { pkgs, config, lib, ... } : let - inherit (lib) mkIf concatStringsSep concatMapStrings toList mapAttrs - mapAttrsToList; + inherit (lib) mapAttrs; cfg = config.services.kerberos_server; - kerberos = config.security.krb5.package; - stateDir = "/var/heimdal"; - aclFiles = mapAttrs - (name: {acl, ...}: pkgs.writeText "${name}.acl" (concatMapStrings (( - {principal, access, target, ...} : - "${principal}\t${concatStringsSep "," (toList access)}\t${target}\n" - )) acl)) cfg.realms; + package = config.security.krb5.package; - kdcConfigs = mapAttrsToList (name: value: '' - database = { - dbname = ${stateDir}/heimdal - acl_file = ${value} - } - '') aclFiles; - kdcConfFile = pkgs.writeText "kdc.conf" '' - [kdc] - ${concatStringsSep "\n" kdcConfigs} - ''; + aclConfigs = lib.pipe cfg.settings.realms [ + (mapAttrs (name: { acl, ... }: lib.concatMapStringsSep "\n" ( + { principal, access, target, ... }: + "${principal}\t${lib.concatStringsSep "," (lib.toList access)}\t${target}" + ) acl)) + (lib.mapAttrsToList (name: text: + { + dbname = "/var/lib/heimdal/heimdal"; + acl_file = pkgs.writeText "${name}.acl" text; + } + )) + ]; + + finalConfig = cfg.settings // { + realms = mapAttrs (_: v: removeAttrs v [ "acl" ]) (cfg.settings.realms or { }); + kdc = (cfg.settings.kdc or { }) // { + database = aclConfigs; + }; + }; + + format = import ../../../security/krb5/krb5-conf-format.nix { inherit pkgs lib; } { enableKdcACLEntries = true; }; + + kdcConfFile = format.generate "kdc.conf" finalConfig; in { - # No documentation about correct triggers, so guessing at them. + config = lib.mkIf (cfg.enable && package.passthru.implementation == "heimdal") { + environment.etc."heimdal-kdc/kdc.conf".source = kdcConfFile; + + systemd.tmpfiles.settings."10-heimdal" = let + databases = lib.pipe finalConfig.kdc.database [ + (map (dbAttrs: dbAttrs.dbname or null)) + (lib.filter (x: x != null)) + lib.unique + ]; + in lib.genAttrs databases (_: { + d = { + user = "root"; + group = "root"; + mode = "0700"; + }; + }); - config = mkIf (cfg.enable && kerberos == pkgs.heimdal) { systemd.services.kadmind = { description = "Kerberos Administration Daemon"; - wantedBy = [ "multi-user.target" ]; - preStart = '' - mkdir -m 0755 -p ${stateDir} - ''; - serviceConfig.ExecStart = - "${kerberos}/libexec/kadmind --config-file=/etc/heimdal-kdc/kdc.conf"; + partOf = [ "kerberos-server.target" ]; + wantedBy = [ "kerberos-server.target" ]; + serviceConfig = { + ExecStart = "${package}/libexec/kadmind --config-file=/etc/heimdal-kdc/kdc.conf"; + Slice = "system-kerberos-server.slice"; + StateDirectory = "heimdal"; + }; restartTriggers = [ kdcConfFile ]; }; systemd.services.kdc = { description = "Key Distribution Center daemon"; - wantedBy = [ "multi-user.target" ]; - preStart = '' - mkdir -m 0755 -p ${stateDir} - ''; - serviceConfig.ExecStart = - "${kerberos}/libexec/kdc --config-file=/etc/heimdal-kdc/kdc.conf"; + partOf = [ "kerberos-server.target" ]; + wantedBy = [ "kerberos-server.target" ]; + serviceConfig = { + ExecStart = "${package}/libexec/kdc --config-file=/etc/heimdal-kdc/kdc.conf"; + Slice = "system-kerberos-server.slice"; + StateDirectory = "heimdal"; + }; restartTriggers = [ kdcConfFile ]; }; systemd.services.kpasswdd = { description = "Kerberos Password Changing daemon"; - wantedBy = [ "multi-user.target" ]; - preStart = '' - mkdir -m 0755 -p ${stateDir} - ''; - serviceConfig.ExecStart = "${kerberos}/libexec/kpasswdd"; + partOf = [ "kerberos-server.target" ]; + wantedBy = [ "kerberos-server.target" ]; + serviceConfig = { + ExecStart = "${package}/libexec/kpasswdd"; + Slice = "system-kerberos-server.slice"; + StateDirectory = "heimdal"; + }; restartTriggers = [ kdcConfFile ]; }; - - environment.etc = { - # Can be set via the --config-file option to KDC - "heimdal-kdc/kdc.conf".source = kdcConfFile; - }; }; } diff --git a/nixos/modules/services/system/kerberos/kerberos-server.md b/nixos/modules/services/system/kerberos/kerberos-server.md new file mode 100644 index 0000000000000..80c71be1541e4 --- /dev/null +++ b/nixos/modules/services/system/kerberos/kerberos-server.md @@ -0,0 +1,55 @@ +# kerberos_server {#module-services-kerberos-server} + +Kerberos is a computer-network authentication protocol that works on the basis of tickets to allow nodes communicating over a non-secure network to prove their identity to one another in a secure manner. + +This module provides both the MIT and Heimdal implementations of the a Kerberos server. + +## Usage {#module-services-kerberos-server-usage} + +To enable a Kerberos server: + +```nix +{ + security.krb5 = { + # Here you can choose between the MIT and Heimdal implementations. + package = pkgs.krb5; + # package = pkgs.heimdal; + + # Optionally set up a client on the same machine as the server + enable = true; + settings = { + libdefaults.default_realm = "EXAMPLE.COM"; + realms."EXAMPLE.COM" = { + kdc = "kerberos.example.com"; + admin_server = "kerberos.example.com"; + }; + }; + } + + services.kerberos-server = { + enable = true; + settings = { + realms."EXAMPLE.COM" = { + acl = [{ principal = "adminuser"; access= ["add" "cpw"]; }]; + }; + }; + }; +} +``` + +## Notes {#module-services-kerberos-server-notes} + +- The Heimdal documentation will sometimes assume that state is stored in `/var/heimdal`, but this module uses `/var/lib/heimdal` instead. +- Due to the heimdal implementation being chosen through `security.krb5.package`, it is not possible to have a system with one implementation of the client and another of the server. +- While `services.kerberos_server.settings` has a common freeform type between the two implementations, the actual settings that can be set can vary between the two implementations. To figure out what settings are available, you should consult the upstream documentation for the implementation you are using. + +## Upstream Documentation {#module-services-kerberos-server-upstream-documentation} + +- MIT Kerberos homepage: https://web.mit.edu/kerberos +- MIT Kerberos docs: https://web.mit.edu/kerberos/krb5-latest/doc/index.html + +- Heimdal Kerberos GitHub wiki: https://github.com/heimdal/heimdal/wiki +- Heimdal kerberos doc manpages (Debian unstable): https://manpages.debian.org/unstable/heimdal-docs/index.html +- Heimdal Kerberos kdc manpages (Debian unstable): https://manpages.debian.org/unstable/heimdal-kdc/index.html + +Note the version number in the URLs, it may be different for the latest version. diff --git a/nixos/modules/services/system/kerberos/mit.nix b/nixos/modules/services/system/kerberos/mit.nix index a654bd1fe7e1b..9ce58986e27af 100644 --- a/nixos/modules/services/system/kerberos/mit.nix +++ b/nixos/modules/services/system/kerberos/mit.nix @@ -1,31 +1,37 @@ { pkgs, config, lib, ... } : let - inherit (lib) mkIf concatStrings concatStringsSep concatMapStrings toList - mapAttrs mapAttrsToList; + inherit (lib) mapAttrs; cfg = config.services.kerberos_server; - kerberos = config.security.krb5.package; - stateDir = "/var/lib/krb5kdc"; + package = config.security.krb5.package; PIDFile = "/run/kdc.pid"; + + format = import ../../../security/krb5/krb5-conf-format.nix { inherit pkgs lib; } { enableKdcACLEntries = true; }; + aclMap = { add = "a"; cpw = "c"; delete = "d"; get = "i"; list = "l"; modify = "m"; all = "*"; }; - aclFiles = mapAttrs - (name: {acl, ...}: (pkgs.writeText "${name}.acl" (concatMapStrings ( - {principal, access, target, ...} : - let access_code = map (a: aclMap.${a}) (toList access); in - "${principal} ${concatStrings access_code} ${target}\n" - ) acl))) cfg.realms; - kdcConfigs = mapAttrsToList (name: value: '' - ${name} = { - acl_file = ${value} - } - '') aclFiles; - kdcConfFile = pkgs.writeText "kdc.conf" '' - [realms] - ${concatStringsSep "\n" kdcConfigs} - ''; + + aclConfigs = lib.pipe cfg.settings.realms [ + (mapAttrs (name: { acl, ... }: lib.concatMapStringsSep "\n" ( + { principal, access, target, ... }: let + access_code = map (a: aclMap.${a}) (lib.toList access); + in "${principal} ${lib.concatStrings access_code} ${target}" + ) acl)) + + (lib.concatMapAttrs (name: text: { + ${name} = { + acl_file = pkgs.writeText "${name}.acl" text; + }; + })) + ]; + + finalConfig = cfg.settings // { + realms = mapAttrs (n: v: (removeAttrs v [ "acl" ]) // aclConfigs.${n}) (cfg.settings.realms or { }); + }; + + kdcConfFile = format.generate "kdc.conf" finalConfig; env = { # What Debian uses, could possibly link directly to Nix store? KRB5_KDC_PROFILE = "/etc/krb5kdc/kdc.conf"; @@ -33,36 +39,38 @@ let in { - config = mkIf (cfg.enable && kerberos == pkgs.krb5) { + config = lib.mkIf (cfg.enable && package.passthru.implementation == "krb5") { + environment = { + etc."krb5kdc/kdc.conf".source = kdcConfFile; + variables = env; + }; + systemd.services.kadmind = { description = "Kerberos Administration Daemon"; - wantedBy = [ "multi-user.target" ]; - preStart = '' - mkdir -m 0755 -p ${stateDir} - ''; - serviceConfig.ExecStart = "${kerberos}/bin/kadmind -nofork"; + partOf = [ "kerberos-server.target" ]; + wantedBy = [ "kerberos-server.target" ]; + serviceConfig = { + ExecStart = "${package}/bin/kadmind -nofork"; + Slice = "system-kerberos-server.slice"; + StateDirectory = "krb5kdc"; + }; restartTriggers = [ kdcConfFile ]; environment = env; }; systemd.services.kdc = { description = "Key Distribution Center daemon"; - wantedBy = [ "multi-user.target" ]; - preStart = '' - mkdir -m 0755 -p ${stateDir} - ''; + partOf = [ "kerberos-server.target" ]; + wantedBy = [ "kerberos-server.target" ]; serviceConfig = { Type = "forking"; PIDFile = PIDFile; - ExecStart = "${kerberos}/bin/krb5kdc -P ${PIDFile}"; + ExecStart = "${package}/bin/krb5kdc -P ${PIDFile}"; + Slice = "system-kerberos-server.slice"; + StateDirectory = "krb5kdc"; }; restartTriggers = [ kdcConfFile ]; environment = env; }; - - environment.etc = { - "krb5kdc/kdc.conf".source = kdcConfFile; - }; - environment.variables = env; }; } diff --git a/nixos/modules/services/system/nix-daemon.nix b/nixos/modules/services/system/nix-daemon.nix index 0a5b0e2fcb80a..3d44bdac34bf6 100644 --- a/nixos/modules/services/system/nix-daemon.nix +++ b/nixos/modules/services/system/nix-daemon.nix @@ -164,7 +164,7 @@ in nixPackage pkgs.nix-info ] - ++ optional (config.programs.bash.enableCompletion) pkgs.nix-bash-completions; + ++ optional (config.programs.bash.completion.enable) pkgs.nix-bash-completions; systemd.packages = [ nixPackage ]; diff --git a/nixos/modules/services/ttys/getty.nix b/nixos/modules/services/ttys/getty.nix index 011016dd5fd14..e88bb4628635e 100644 --- a/nixos/modules/services/ttys/getty.nix +++ b/nixos/modules/services/ttys/getty.nix @@ -101,7 +101,7 @@ in config = { # Note: this is set here rather than up there so that changing # nixos.label would not rebuild manual pages - services.getty.greetingLine = mkDefault ''<<< Welcome to NixOS ${config.system.nixos.label} (\m) - \l >>>''; + services.getty.greetingLine = mkDefault ''<<< Welcome to ${config.system.nixos.distroName} ${config.system.nixos.label} (\m) - \l >>>''; services.getty.helpLine = mkIf (config.documentation.nixos.enable && config.documentation.doc.enable) "\nRun 'nixos-help' for the NixOS manual."; systemd.services."getty@" = @@ -158,4 +158,5 @@ in }; + meta.maintainers = with maintainers; [ RossComputerGuy ]; } diff --git a/nixos/modules/services/video/frigate.nix b/nixos/modules/services/video/frigate.nix index 0e6bde447c033..c3ec4a3c76c34 100644 --- a/nixos/modules/services/video/frigate.nix +++ b/nixos/modules/services/video/frigate.nix @@ -427,10 +427,6 @@ in PrivateTmp = true; CacheDirectory = "frigate"; CacheDirectoryMode = "0750"; - - BindPaths = [ - "/migrations:${cfg.package}/share/frigate/migrations:ro" - ]; }; }; }; diff --git a/nixos/modules/services/video/photonvision.nix b/nixos/modules/services/video/photonvision.nix index d4568258db7d2..e2b27b3cc4104 100644 --- a/nixos/modules/services/video/photonvision.nix +++ b/nixos/modules/services/video/photonvision.nix @@ -6,7 +6,7 @@ in { options = { services.photonvision = { - enable = lib.mkEnableOption "Enable PhotonVision"; + enable = lib.mkEnableOption "PhotonVision"; package = lib.mkPackageOption pkgs "photonvision" {}; diff --git a/nixos/modules/services/wayland/hypridle.nix b/nixos/modules/services/wayland/hypridle.nix new file mode 100644 index 0000000000000..5442802df9871 --- /dev/null +++ b/nixos/modules/services/wayland/hypridle.nix @@ -0,0 +1,26 @@ +{ lib, pkgs, config, ... }: + +let + cfg = config.services.hypridle; +in +{ + options.services.hypridle = { + enable = lib.mkEnableOption "hypridle, Hyprland's idle daemon"; + package = lib.mkPackageOption pkgs "hypridle" { }; + }; + + config = lib.mkIf cfg.enable { + environment.systemPackages = [ + cfg.package + ]; + + systemd.user.services.hypridle = { + description = "Hypridle idle daemon"; + wantedBy = [ "graphical-session.target" ]; + partOf = [ "graphical-session.target" ]; + script = lib.getExe cfg.package; + }; + }; + + meta.maintainers = with lib.maintainers; [ johnrtitor ]; +} diff --git a/nixos/modules/services/web-apps/akkoma.nix b/nixos/modules/services/web-apps/akkoma.nix index 7c9bf6c465164..338e7c7383380 100644 --- a/nixos/modules/services/web-apps/akkoma.nix +++ b/nixos/modules/services/web-apps/akkoma.nix @@ -119,7 +119,7 @@ let -o ${escapeShellArg cfg.user } \ -g ${escapeShellArg cfg.group} \ <(hexdump -n 16 -e '"%02x"' /dev/urandom) \ - "$RUNTIME_DIRECTORY/cookie" + "''${RUNTIME_DIRECTORY%%:*}/cookie" ''; }; @@ -131,7 +131,7 @@ let -o ${escapeShellArg cfg.user} \ -g ${escapeShellArg cfg.group} \ ${escapeShellArg cfg.dist.cookie._secret} \ - "$RUNTIME_DIRECTORY/cookie" + "''${RUNTIME_DIRECTORY%%:*}/cookie" ''; }; @@ -181,7 +181,7 @@ let name = "akkoma-config"; runtimeInputs = with pkgs; [ coreutils replace-secret ]; text = '' - cd "$RUNTIME_DIRECTORY" + cd "''${RUNTIME_DIRECTORY%%:*}" tmp="$(mktemp config.exs.XXXXXXXXXX)" trap 'rm -f "$tmp"' EXIT TERM @@ -279,7 +279,7 @@ let cd "${cfg.package}" RUNTIME_DIRECTORY="''${RUNTIME_DIRECTORY:-/run/akkoma}" - AKKOMA_CONFIG_PATH="$RUNTIME_DIRECTORY/config.exs" \ + AKKOMA_CONFIG_PATH="''${RUNTIME_DIRECTORY%%:*}/config.exs" \ ERL_EPMD_ADDRESS="${cfg.dist.address}" \ ERL_EPMD_PORT="${toString cfg.dist.epmdPort}" \ ERL_FLAGS=${lib.escapeShellArg (lib.escapeShellArgs ([ @@ -287,7 +287,7 @@ let "-kernel" "inet_dist_listen_min" (toString cfg.dist.portMin) "-kernel" "inet_dist_listen_max" (toString cfg.dist.portMax) ] ++ cfg.dist.extraFlags))} \ - RELEASE_COOKIE="$(<"$RUNTIME_DIRECTORY/cookie")" \ + RELEASE_COOKIE="$(<"''${RUNTIME_DIRECTORY%%:*}/cookie")" \ RELEASE_NAME="akkoma" \ exec "${cfg.package}/bin/$(basename "$0")" "$@" ''; @@ -984,7 +984,7 @@ in { RemainAfterExit = true; UMask = "0077"; - RuntimeDirectory = "akkoma"; + RuntimeDirectory = mkBefore "akkoma"; ExecStart = mkMerge [ (mkIf (cfg.dist.cookie == null) [ genScript ]) @@ -1072,7 +1072,7 @@ in { ProtectProc = "noaccess"; ProcSubset = "pid"; - ProtectSystem = mkIf (!isConfined) "strict"; + ProtectSystem = "strict"; ProtectHome = true; PrivateTmp = true; PrivateDevices = true; diff --git a/nixos/modules/services/web-apps/artalk.nix b/nixos/modules/services/web-apps/artalk.nix new file mode 100644 index 0000000000000..d3d06f1521b6a --- /dev/null +++ b/nixos/modules/services/web-apps/artalk.nix @@ -0,0 +1,131 @@ +{ + config, + lib, + pkgs, + utils, + ... +}: +let + cfg = config.services.artalk; + settingsFormat = pkgs.formats.json { }; +in +{ + + meta = { + maintainers = with lib.maintainers; [ moraxyc ]; + }; + + options = { + services.artalk = { + enable = lib.mkEnableOption "artalk, a comment system"; + configFile = lib.mkOption { + type = lib.types.str; + default = "/etc/artalk/config.yml"; + description = "Artalk config file path. If it is not exist, Artalk will generate one."; + }; + allowModify = lib.mkOption { + type = lib.types.bool; + default = true; + description = "allow Artalk store the settings to config file persistently"; + }; + workdir = lib.mkOption { + type = lib.types.str; + default = "/var/lib/artalk"; + description = "Artalk working directory"; + }; + user = lib.mkOption { + type = lib.types.str; + default = "artalk"; + description = "Artalk user name."; + }; + + group = lib.mkOption { + type = lib.types.str; + default = "artalk"; + description = "Artalk group name."; + }; + + package = lib.mkPackageOption pkgs "artalk" { }; + settings = lib.mkOption { + type = lib.types.submodule { + freeformType = settingsFormat.type; + options = { + host = lib.mkOption { + type = lib.types.str; + default = "0.0.0.0"; + description = '' + Artalk server listen host + ''; + }; + port = lib.mkOption { + type = lib.types.port; + default = 23366; + description = '' + Artalk server listen port + ''; + }; + }; + }; + default = { }; + description = '' + The artalk configuration. + + If you set allowModify to true, Artalk will be able to store the settings in the config file persistently. This section's content will update in the config file after the service restarts. + + Options containing secret data should be set to an attribute set + containing the attribute `_secret` - a string pointing to a file + containing the value the option should be set to. + ''; + }; + }; + }; + + config = lib.mkIf cfg.enable { + users.users.artalk = lib.optionalAttrs (cfg.user == "artalk") { + description = "artalk user"; + isSystemUser = true; + group = cfg.group; + }; + users.groups.artalk = lib.optionalAttrs (cfg.group == "artalk") { }; + + environment.systemPackages = [ cfg.package ]; + + systemd.services.artalk = { + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + preStart = + '' + umask 0077 + ${utils.genJqSecretsReplacementSnippet cfg.settings "/run/artalk/new"} + '' + + ( + if cfg.allowModify then + '' + [ -e "${cfg.configFile}" ] || ${lib.getExe cfg.package} gen config "${cfg.configFile}" + cat "${cfg.configFile}" | ${lib.getExe pkgs.yj} > "/run/artalk/old" + ${lib.getExe pkgs.jq} -s '.[0] * .[1]' "/run/artalk/old" "/run/artalk/new" > "/run/artalk/result" + cat "/run/artalk/result" | ${lib.getExe pkgs.yj} -r > "${cfg.configFile}" + rm /run/artalk/{old,new,result} + '' + else + '' + cat /run/artalk/new | ${lib.getExe pkgs.yj} -r > "${cfg.configFile}" + rm /run/artalk/new + '' + ); + serviceConfig = { + User = cfg.user; + Group = cfg.group; + Type = "simple"; + ExecStart = "${lib.getExe cfg.package} server --config ${cfg.configFile} --workdir ${cfg.workdir} --host ${cfg.settings.host} --port ${builtins.toString cfg.settings.port}"; + Restart = "on-failure"; + RestartSec = "5s"; + ConfigurationDirectory = [ "artalk" ]; + StateDirectory = [ "artalk" ]; + RuntimeDirectory = [ "artalk" ]; + AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ]; + ProtectHome = "yes"; + }; + }; + }; +} diff --git a/nixos/modules/services/web-apps/commafeed.nix b/nixos/modules/services/web-apps/commafeed.nix new file mode 100644 index 0000000000000..354e3625bb999 --- /dev/null +++ b/nixos/modules/services/web-apps/commafeed.nix @@ -0,0 +1,114 @@ +{ + config, + lib, + pkgs, + ... +}: +let + cfg = config.services.commafeed; +in +{ + options.services.commafeed = { + enable = lib.mkEnableOption "CommaFeed"; + + package = lib.mkPackageOption pkgs "commafeed" { }; + + user = lib.mkOption { + type = lib.types.str; + description = "User under which CommaFeed runs."; + default = "commafeed"; + }; + + group = lib.mkOption { + type = lib.types.str; + description = "Group under which CommaFeed runs."; + default = "commafeed"; + }; + + stateDir = lib.mkOption { + type = lib.types.path; + description = "Directory holding all state for CommaFeed to run."; + default = "/var/lib/commafeed"; + }; + + environment = lib.mkOption { + type = lib.types.attrsOf ( + lib.types.oneOf [ + lib.types.bool + lib.types.int + lib.types.str + ] + ); + description = '' + Extra environment variables passed to CommaFeed, refer to + + for supported values. The default user is `admin` and the default password is `admin`. + Correct configuration for H2 database is already provided. + ''; + default = { }; + example = { + CF_SERVER_APPLICATIONCONNECTORS_0_TYPE = "http"; + CF_SERVER_APPLICATIONCONNECTORS_0_PORT = 9090; + }; + }; + + environmentFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; + description = '' + Environment file as defined in {manpage}`systemd.exec(5)`. + ''; + default = null; + example = "/var/lib/commafeed/commafeed.env"; + }; + }; + + config = lib.mkIf cfg.enable { + systemd.services.commafeed = { + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + environment = lib.mapAttrs ( + _: v: if lib.isBool v then lib.boolToString v else toString v + ) cfg.environment; + serviceConfig = { + ExecStart = "${lib.getExe cfg.package} server ${cfg.package}/share/config.yml"; + User = cfg.user; + Group = cfg.group; + StateDirectory = baseNameOf cfg.stateDir; + WorkingDirectory = cfg.stateDir; + # Hardening + CapabilityBoundingSet = [ "" ]; + DevicePolicy = "closed"; + DynamicUser = true; + LockPersonality = true; + NoNewPrivileges = true; + PrivateDevices = true; + PrivateUsers = true; + ProcSubset = "pid"; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHome = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + ProtectProc = "invisible"; + ProtectSystem = true; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + RestrictSUIDSGID = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "~@privileged" + ]; + UMask = "0077"; + } // lib.optionalAttrs (cfg.environmentFile != null) { EnvironmentFile = cfg.environmentFile; }; + }; + }; + + meta.maintainers = [ lib.maintainers.raroh73 ]; +} diff --git a/nixos/modules/services/web-apps/filesender.md b/nixos/modules/services/web-apps/filesender.md new file mode 100644 index 0000000000000..44d066761b9a4 --- /dev/null +++ b/nixos/modules/services/web-apps/filesender.md @@ -0,0 +1,49 @@ +# FileSender {#module-services-filesender} + +[FileSender](https://filesender.org/software/) is a software that makes it easy to send and receive big files. + +## Quickstart {#module-services-filesender-quickstart} + +FileSender uses [SimpleSAMLphp](https://simplesamlphp.org/) for authentication, which needs to be configured separately. + +Minimal working instance of FileSender that uses password-authentication would look like this: + +```nix +{ + networking.firewall.allowedTCPPorts = [ 80 443 ]; + services.filesender = { + enable = true; + localDomain = "filesender.example.com"; + configureNginx = true; + database.createLocally = true; + + settings = { + auth_sp_saml_authentication_source = "default"; + auth_sp_saml_uid_attribute = "uid"; + storage_filesystem_path = ""; + admin = "admin"; + admin_email = "admin@example.com"; + email_reply_to = "noreply@example.com"; + }; + }; + services.simplesamlphp.filesender = { + settings = { + "module.enable".exampleauth = true; + }; + authSources = { + admin = [ "core:AdminPassword" ]; + default = format.lib.mkMixedArray [ "exampleauth:UserPass" ] { + "admin:admin123" = { + uid = [ "admin" ]; + cn = [ "admin" ]; + mail = [ "admin@example.com" ]; + }; + }; + }; + }; +} +``` + +::: {.warning} +Example above uses hardcoded clear-text password, in production you should use other authentication method like LDAP. You can check supported authentication methods [in SimpleSAMLphp documentation](https://simplesamlphp.org/docs/stable/simplesamlphp-idp.html). +::: diff --git a/nixos/modules/services/web-apps/filesender.nix b/nixos/modules/services/web-apps/filesender.nix new file mode 100644 index 0000000000000..bc8d465643f2f --- /dev/null +++ b/nixos/modules/services/web-apps/filesender.nix @@ -0,0 +1,253 @@ +{ + config, + lib, + pkgs, + ... +}: +let + format = pkgs.formats.php { finalVariable = "config"; }; + + cfg = config.services.filesender; + simpleSamlCfg = config.services.simplesamlphp.filesender; + fpm = config.services.phpfpm.pools.filesender; + + filesenderConfigDirectory = pkgs.runCommand "filesender-config" { } '' + mkdir $out + cp ${format.generate "config.php" cfg.settings} $out/config.php + ''; +in +{ + meta = { + maintainers = with lib.maintainers; [ nhnn ]; + doc = ./filesender.md; + }; + + options.services.filesender = with lib; { + enable = mkEnableOption "FileSender"; + package = mkPackageOption pkgs "filesender" { }; + user = mkOption { + description = "User under which filesender runs."; + type = types.str; + default = "filesender"; + }; + database = { + createLocally = mkOption { + type = types.bool; + default = true; + description = '' + Create the PostgreSQL database and database user locally. + ''; + }; + hostname = mkOption { + type = types.str; + default = "/run/postgresql"; + description = "Database hostname."; + }; + port = mkOption { + type = types.port; + default = 5432; + description = "Database port."; + }; + name = mkOption { + type = types.str; + default = "filesender"; + description = "Database name."; + }; + user = mkOption { + type = types.str; + default = "filesender"; + description = "Database user."; + }; + passwordFile = mkOption { + type = types.nullOr types.path; + default = null; + example = "/run/keys/filesender-dbpassword"; + description = '' + A file containing the password corresponding to + [](#opt-services.filesender.database.user). + ''; + }; + }; + settings = mkOption { + type = types.submodule { + freeformType = format.type; + options = { + site_url = mkOption { + type = types.str; + description = "Site URL. Used in emails, to build URLs for logging in, logging out, build URL for upload endpoint for web workers, to include scripts etc."; + }; + admin = mkOption { + type = types.commas; + description = '' + UIDs (as per the configured saml_uid_attribute) of FileSender administrators. + Accounts with these UIDs can access the Admin page through the web UI. + ''; + }; + admin_email = mkOption { + type = types.commas; + description = '' + Email address of FileSender administrator(s). + Emails regarding disk full etc. are sent here. + You should use a role-address here. + ''; + }; + storage_filesystem_path = mkOption { + type = types.nullOr types.str; + description = "When using storage type filesystem this is the absolute path to the file system where uploaded files are stored until they expire. Your FileSender storage root."; + }; + log_facilities = mkOption { + type = format.type; + default = [ { type = "error_log"; } ]; + description = "Defines where FileSender logging is sent. You can sent logging to a file, to syslog or to the default PHP log facility (as configured through your webserver's PHP module). The directive takes an array of one or more logging targets. Logging can be sent to multiple targets simultaneously. Each logging target is a list containing the name of the logging target and a number of attributes which vary per log target. See below for the exact definiation of each log target."; + }; + }; + }; + default = { }; + description = '' + Configuration options used by FileSender. + See [](https://docs.filesender.org/filesender/v2.0/admin/configuration/) + for available options. + ''; + }; + configureNginx = mkOption { + type = types.bool; + default = true; + description = "Configure nginx as a reverse proxy for FileSender."; + }; + localDomain = mkOption { + type = types.str; + example = "filesender.example.org"; + description = "The domain serving your FileSender instance."; + }; + poolSettings = mkOption { + type = + with types; + attrsOf (oneOf [ + str + int + bool + ]); + default = { + "pm" = "dynamic"; + "pm.max_children" = "32"; + "pm.start_servers" = "2"; + "pm.min_spare_servers" = "2"; + "pm.max_spare_servers" = "4"; + "pm.max_requests" = "500"; + }; + description = '' + Options for FileSender's PHP pool. See the documentation on `php-fpm.conf` for details on configuration directives. + ''; + }; + }; + config = lib.mkIf cfg.enable { + services.simplesamlphp.filesender = { + phpfpmPool = "filesender"; + localDomain = cfg.localDomain; + settings.baseurlpath = lib.mkDefault "https://${cfg.localDomain}/saml"; + }; + + services.phpfpm = { + pools.filesender = { + user = cfg.user; + group = config.services.nginx.group; + phpEnv = { + FILESENDER_CONFIG_DIR = toString filesenderConfigDirectory; + SIMPLESAMLPHP_CONFIG_DIR = toString simpleSamlCfg.configDir; + }; + settings = { + "listen.owner" = config.services.nginx.user; + "listen.group" = config.services.nginx.group; + } // cfg.poolSettings; + }; + }; + + services.nginx = lib.mkIf cfg.configureNginx { + enable = true; + virtualHosts.${cfg.localDomain} = { + root = "${cfg.package}/www"; + extraConfig = '' + index index.php; + ''; + locations = { + "/".extraConfig = '' + try_files $uri $uri/ /index.php?args; + ''; + "~ [^/]\\.php(/|$)" = { + extraConfig = '' + fastcgi_split_path_info ^(.+\.php)(/.+)$; + fastcgi_pass unix:${fpm.socket}; + include ${pkgs.nginx}/conf/fastcgi.conf; + fastcgi_intercept_errors on; + fastcgi_param PATH_INFO $fastcgi_path_info; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + ''; + }; + "~ /\\.".extraConfig = "deny all;"; + }; + }; + }; + + services.postgresql = lib.mkIf cfg.database.createLocally { + enable = true; + ensureDatabases = [ cfg.database.name ]; + ensureUsers = [ + { + name = cfg.database.user; + ensureDBOwnership = true; + } + ]; + }; + + services.filesender.settings = lib.mkMerge [ + (lib.mkIf cfg.database.createLocally { + db_host = "/run/postgresql"; + db_port = "5432"; + db_password = "."; # FileSender requires it even when on UNIX socket auth. + }) + (lib.mkIf (!cfg.database.createLocally) { + db_host = cfg.database.hostname; + db_port = toString cfg.database.port; + db_password = format.lib.mkRaw "file_get_contents('${cfg.database.passwordFile}')"; + }) + { + site_url = lib.mkDefault "https://${cfg.localDomain}"; + db_type = "pgsql"; + db_username = cfg.database.user; + db_database = cfg.database.name; + "auth_sp_saml_simplesamlphp_url" = "/saml"; + "auth_sp_saml_simplesamlphp_location" = "${simpleSamlCfg.libDir}"; + } + ]; + + systemd.services.filesender-initdb = { + description = "Init filesender DB"; + + wantedBy = [ + "multi-user.target" + "phpfpm-filesender.service" + ]; + after = [ "postgresql.service" ]; + + restartIfChanged = true; + + serviceConfig = { + Environment = [ + "FILESENDER_CONFIG_DIR=${toString filesenderConfigDirectory}" + "SIMPLESAMLPHP_CONFIG_DIR=${toString simpleSamlCfg.configDir}" + ]; + Type = "oneshot"; + Group = config.services.nginx.group; + User = "filesender"; + ExecStart = "${fpm.phpPackage}/bin/php ${cfg.package}/scripts/upgrade/database.php"; + }; + }; + + users.extraUsers.filesender = lib.mkIf (cfg.user == "filesender") { + home = "/var/lib/filesender"; + group = config.services.nginx.group; + createHome = true; + isSystemUser = true; + }; + }; +} diff --git a/nixos/modules/services/web-apps/firefly-iii.nix b/nixos/modules/services/web-apps/firefly-iii.nix index b0024ce09c38e..6b383139c8911 100644 --- a/nixos/modules/services/web-apps/firefly-iii.nix +++ b/nixos/modules/services/web-apps/firefly-iii.nix @@ -3,8 +3,8 @@ let inherit (lib) optionalString mkDefault mkIf mkOption mkEnableOption literalExpression; inherit (lib.types) nullOr attrsOf oneOf str int bool path package enum submodule; - inherit (lib.strings) concatMapStringsSep removePrefix toShellVars removeSuffix hasSuffix; - inherit (lib.attrsets) attrValues genAttrs filterAttrs mapAttrs' nameValuePair; + inherit (lib.strings) concatLines removePrefix toShellVars removeSuffix hasSuffix; + inherit (lib.attrsets) mapAttrsToList attrValues genAttrs filterAttrs mapAttrs' nameValuePair; inherit (builtins) isInt isString toString typeOf; cfg = config.services.firefly-iii; @@ -21,18 +21,10 @@ let (filterAttrs (n: v: hasSuffix "_FILE" n) cfg.settings); env-nonfile-values = filterAttrs (n: v: ! hasSuffix "_FILE" n) cfg.settings; - envfile = pkgs.writeText "firefly-iii-env" '' - ${toShellVars env-file-values} - ${toShellVars env-nonfile-values} - ''; - fileenv-func = '' - cp --no-preserve=mode ${envfile} /tmp/firefly-iii-env - ${concatMapStringsSep "\n" - (n: "${pkgs.replace-secret}/bin/replace-secret ${n} ${n} /tmp/firefly-iii-env") - (attrValues env-file-values)} set -a - . /tmp/firefly-iii-env + ${toShellVars env-nonfile-values} + ${concatLines (mapAttrsToList (n: v: "${n}=\"$(< ${v})\"") env-file-values)} set +a ''; @@ -41,15 +33,13 @@ let ${optionalString (cfg.settings.DB_CONNECTION == "sqlite") "touch ${cfg.dataDir}/storage/database/database.sqlite"} - ${artisan} migrate --seed --no-interaction --force - ${artisan} firefly-iii:decrypt-all + ${artisan} package:discover ${artisan} firefly-iii:upgrade-database - ${artisan} firefly-iii:correct-database - ${artisan} firefly-iii:report-integrity ${artisan} firefly-iii:laravel-passport-keys ${artisan} cache:clear - - mv /tmp/firefly-iii-env /run/phpfpm/firefly-iii-env + ${artisan} view:cache + ${artisan} route:cache + ${artisan} config:cache ''; commonServiceConfig = { @@ -146,6 +136,7 @@ in { virtualHost = mkOption { type = str; + default = "localhost"; description = '' The hostname at which you wish firefly-iii to be served. If you have enabled nginx using `services.firefly-iii.enableNginx` then this will @@ -170,14 +161,15 @@ in { }; settings = mkOption { + default = {}; description = '' Options for firefly-iii configuration. Refer to for details on supported values. All