Project import generated by Copybara.

GitOrigin-RevId: 062a0c5437b68f950b081bbfc8a699d57a4ee026
This commit is contained in:
Default email 2022-03-05 17:20:37 +01:00
parent 75a5b40962
commit 8e65f7f0cc
2156 changed files with 58830 additions and 19294 deletions

View file

@ -0,0 +1,32 @@
# This file contains a list of commits that are not likely what you
# are looking for in a blame, such as mass reformatting or renaming.
# You can set this file as a default ignore file for blame by running
# the following command.
#
# $ git config blame.ignoreRevsFile .git-blame-ignore-revs
#
# To temporarily not use this file add
# --ignore-revs-file=""
# to your blame command.
#
# The ignoreRevsFile can't be set globally due to blame failing if the file isn't present.
# To not have to set the option in every repository it is needed in,
# save the following script in your path with the name "git-bblame"
# now you can run
# $ git bblame $FILE
# to use the .git-blame-ignore-revs file if it is present.
#
# #!/usr/bin/env bash
# repo_root=$(git rev-parse --show-toplevel)
# if [[ -e $repo_root/.git-blame-ignore-revs ]]; then
# git blame --ignore-revs-file="$repo_root/.git-blame-ignore-revs" $@
# else
# git blame $@
# fi
# nixos/modules/rename: Sort alphabetically
1f71224fe86605ef4cd23ed327b3da7882dad382
# nixos: fix module paths in rename.nix
d08ede042b74b8199dc748323768227b88efcf7c

View file

@ -226,10 +226,10 @@
/pkgs/applications/editors/neovim @jonringer @teto /pkgs/applications/editors/neovim @jonringer @teto
# VimPlugins # VimPlugins
/pkgs/misc/vim-plugins @jonringer @softinio /pkgs/applications/editors/vim/plugins @jonringer
# VsCode Extensions # VsCode Extensions
/pkgs/misc/vscode-extensions @jonringer /pkgs/applications/editors/vscode/extensions @jonringer
# Prometheus exporter modules and tests # Prometheus exporter modules and tests
/nixos/modules/services/monitoring/prometheus/exporters.nix @WilliButz /nixos/modules/services/monitoring/prometheus/exporters.nix @WilliButz

View file

@ -142,7 +142,7 @@
"6.topic: vim": "6.topic: vim":
- doc/languages-frameworks/vim.section.md - doc/languages-frameworks/vim.section.md
- pkgs/applications/editors/vim/**/* - pkgs/applications/editors/vim/**/*
- pkgs/misc/vim-plugins/**/* - pkgs/applications/editors/vim/plugins/**/*
- nixos/modules/programs/neovim.nix - nixos/modules/programs/neovim.nix
- pkgs/applications/editors/neovim/**/* - pkgs/applications/editors/neovim/**/*

View file

@ -8,7 +8,7 @@ jobs:
if: github.repository_owner == 'NixOS' && github.event.pull_request.merged == true && (github.event_name != 'labeled' || startsWith('backport', github.event.label.name)) if: github.repository_owner == 'NixOS' && github.event.pull_request.merged == true && (github.event_name != 'labeled' || startsWith('backport', github.event.label.name))
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
with: with:
# required to find all branches # required to find all branches
fetch-depth: 0 fetch-depth: 0

View file

@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
# we don't limit this action to only NixOS repo since the checks are cheap and useful developer feedback # we don't limit this action to only NixOS repo since the checks are cheap and useful developer feedback
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- uses: cachix/install-nix-action@v16 - uses: cachix/install-nix-action@v16
# explicit list of supportedSystems is needed until aarch64-darwin becomes part of the trunk jobset # explicit list of supportedSystems is needed until aarch64-darwin becomes part of the trunk jobset
- run: nix-build pkgs/top-level/release.nix -A tarball.nixpkgs-basic-release-checks --arg supportedSystems '[ "aarch64-darwin" "aarch64-linux" "x86_64-linux" "x86_64-darwin" ]' - run: nix-build pkgs/top-level/release.nix -A tarball.nixpkgs-basic-release-checks --arg supportedSystems '[ "aarch64-darwin" "aarch64-linux" "x86_64-linux" "x86_64-darwin" ]'

View file

@ -24,7 +24,7 @@ jobs:
- name: print list of changed files - name: print list of changed files
run: | run: |
cat "$HOME/changed_files" cat "$HOME/changed_files"
- uses: actions/checkout@v2 - uses: actions/checkout@v3
with: with:
# pull_request_target checks out the base branch by default # pull_request_target checks out the base branch by default
ref: refs/pull/${{ github.event.pull_request.number }}/merge ref: refs/pull/${{ github.event.pull_request.number }}/merge

View file

@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: github.repository_owner == 'NixOS' if: github.repository_owner == 'NixOS'
steps: steps:
- uses: actions/labeler@v3 - uses: actions/labeler@v4
with: with:
repo-token: ${{ secrets.GITHUB_TOKEN }} repo-token: ${{ secrets.GITHUB_TOKEN }}
sync-labels: true sync-labels: true

View file

@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: github.repository_owner == 'NixOS' if: github.repository_owner == 'NixOS'
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
with: with:
# pull_request_target checks out the base branch by default # pull_request_target checks out the base branch by default
ref: refs/pull/${{ github.event.pull_request.number }}/merge ref: refs/pull/${{ github.event.pull_request.number }}/merge

View file

@ -14,7 +14,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: github.repository_owner == 'NixOS' if: github.repository_owner == 'NixOS'
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
with: with:
# pull_request_target checks out the base branch by default # pull_request_target checks out the base branch by default
ref: refs/pull/${{ github.event.pull_request.number }}/merge ref: refs/pull/${{ github.event.pull_request.number }}/merge

View file

@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: github.repository_owner == 'NixOS' if: github.repository_owner == 'NixOS'
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
with: with:
# pull_request_target checks out the base branch by default # pull_request_target checks out the base branch by default
ref: refs/pull/${{ github.event.pull_request.number }}/merge ref: refs/pull/${{ github.event.pull_request.number }}/merge

View file

@ -38,7 +38,7 @@ jobs:
into: staging-21.11 into: staging-21.11
name: ${{ matrix.pairs.from }} → ${{ matrix.pairs.into }} name: ${{ matrix.pairs.from }} → ${{ matrix.pairs.into }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: ${{ matrix.pairs.from }} → ${{ matrix.pairs.into }} - name: ${{ matrix.pairs.from }} → ${{ matrix.pairs.into }}
uses: devmasx/merge-branch@1.4.0 uses: devmasx/merge-branch@1.4.0

View file

@ -32,7 +32,7 @@ jobs:
into: staging into: staging
name: ${{ matrix.pairs.from }} → ${{ matrix.pairs.into }} name: ${{ matrix.pairs.from }} → ${{ matrix.pairs.into }}
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- name: ${{ matrix.pairs.from }} → ${{ matrix.pairs.into }} - name: ${{ matrix.pairs.from }} → ${{ matrix.pairs.into }}
uses: devmasx/merge-branch@1.4.0 uses: devmasx/merge-branch@1.4.0

View file

@ -10,7 +10,7 @@ jobs:
if: github.repository_owner == 'NixOS' && github.ref == 'refs/heads/master' # ensure workflow_dispatch only runs on master if: github.repository_owner == 'NixOS' && github.ref == 'refs/heads/master' # ensure workflow_dispatch only runs on master
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v3
- uses: cachix/install-nix-action@v16 - uses: cachix/install-nix-action@v16
- name: setup - name: setup
id: setup id: setup

View file

@ -56,7 +56,7 @@ Use `programs.steam.enable = true;` if you want to add steam to systemPackages a
## steam-run {#sec-steam-run} ## steam-run {#sec-steam-run}
The FHS-compatible chroot used for Steam can also be used to run other Linux games that expect a FHS environment. To use it, install the `steam-run-native` package and run the game with The FHS-compatible chroot used for Steam can also be used to run other Linux games that expect a FHS environment. To use it, install the `steam-run` package and run the game with
``` ```
steam-run ./foo steam-run ./foo

View file

@ -98,7 +98,7 @@ We use jbidwatcher as an example for a discontinued project here.
1. Create a new branch for your change, e.g. `git checkout -b jbidwatcher` 1. Create a new branch for your change, e.g. `git checkout -b jbidwatcher`
1. Remove the actual package including its directory, e.g. `rm -rf pkgs/applications/misc/jbidwatcher` 1. Remove the actual package including its directory, e.g. `rm -rf pkgs/applications/misc/jbidwatcher`
1. Remove the package from the list of all packages (`pkgs/top-level/all-packages.nix`). 1. Remove the package from the list of all packages (`pkgs/top-level/all-packages.nix`).
1. Add an alias for the package name in `pkgs/top-level/aliases.nix` (There is also `pkgs/misc/vim-plugins/aliases.nix`. Package sets typically do not have aliases, so we can't add them there.) 1. Add an alias for the package name in `pkgs/top-level/aliases.nix` (There is also `pkgs/applications/editors/vim/plugins/aliases.nix`. Package sets typically do not have aliases, so we can't add them there.)
For example in this case: For example in this case:

View file

@ -29,7 +29,8 @@ The recommended way of defining a derivation for a Coq library, is to use the `c
* `releaseRev` (optional, defaults to `(v: v)`), provides a default mapping from release names to revision hashes/branch names/tags, * `releaseRev` (optional, defaults to `(v: v)`), provides a default mapping from release names to revision hashes/branch names/tags,
* `displayVersion` (optional), provides a way to alter the computation of `name` from `pname`, by explaining how to display version numbers, * `displayVersion` (optional), provides a way to alter the computation of `name` from `pname`, by explaining how to display version numbers,
* `namePrefix` (optional, defaults to `[ "coq" ]`), provides a way to alter the computation of `name` from `pname`, by explaining which dependencies must occur in `name`, * `namePrefix` (optional, defaults to `[ "coq" ]`), provides a way to alter the computation of `name` from `pname`, by explaining which dependencies must occur in `name`,
* `extraBuildInputs` (optional), by default `buildInputs` just contains `coq`, this allows to add more build inputs, * `extraNativeBuildInputs` (optional), by default `nativeBuildInputs` just contains `coq`, this allows to add more native build inputs, `nativeBuildInputs` are executables and `buildInputs` are libraries and dependencies,
* `extraBuildInputs` (optional), this allows to add more build inputs,
* `mlPlugin` (optional, defaults to `false`). Some extensions (plugins) might require OCaml and sometimes other OCaml packages. Standard dependencies can be added by setting the current option to `true`. For a finer grain control, the `coq.ocamlPackages` attribute can be used in `extraBuildInputs` to depend on the same package set Coq was built against. * `mlPlugin` (optional, defaults to `false`). Some extensions (plugins) might require OCaml and sometimes other OCaml packages. Standard dependencies can be added by setting the current option to `true`. For a finer grain control, the `coq.ocamlPackages` attribute can be used in `extraBuildInputs` to depend on the same package set Coq was built against.
* `useDune2ifVersion` (optional, default to `(x: false)` uses Dune2 to build the package if the provided predicate evaluates to true on the version, e.g. `useDune2if = versions.isGe "1.1"` will use dune if the version of the package is greater or equal to `"1.1"`, * `useDune2ifVersion` (optional, default to `(x: false)` uses Dune2 to build the package if the provided predicate evaluates to true on the version, e.g. `useDune2if = versions.isGe "1.1"` will use dune if the version of the package is greater or equal to `"1.1"`,
* `useDune2` (optional, defaults to `false`) uses Dune2 to build the package if set to true, the presence of this attribute overrides the behavior of the previous one. * `useDune2` (optional, defaults to `false`) uses Dune2 to build the package if set to true, the presence of this attribute overrides the behavior of the previous one.

View file

@ -979,6 +979,31 @@ with import <nixpkgs> {};
in python.withPackages(ps: [ps.blaze])).env in python.withPackages(ps: [ps.blaze])).env
``` ```
#### Optional extra dependencies
Some packages define optional dependencies for additional features. With
`setuptools` this is called `extras_require` and `flit` calls it `extras-require`. A
method for supporting this is by declaring the extras of a package in its
`passthru`, e.g. in case of the package `dask`
```nix
passthru.extras-require = {
complete = [ distributed ];
};
```
and letting the package requiring the extra add the list to its dependencies
```nix
propagatedBuildInputs = [
...
] ++ dask.extras-require.complete;
```
Note this method is preferred over adding parameters to builders, as that can
result in packages depending on different variants and thereby causing
collisions.
#### `buildPythonApplication` function {#buildpythonapplication-function} #### `buildPythonApplication` function {#buildpythonapplication-function}
The `buildPythonApplication` function is practically the same as The `buildPythonApplication` function is practically the same as

View file

@ -464,6 +464,8 @@ you of the correct hash.
be disabled by setting `dontUseCargoParallelTests`. be disabled by setting `dontUseCargoParallelTests`.
* `cargoInstallHook`: install binaries and static/shared libraries * `cargoInstallHook`: install binaries and static/shared libraries
that were built using `cargoBuildHook`. that were built using `cargoBuildHook`.
* `bindgenHook`: for crates which use `bindgen` as a build dependency, lets
`bindgen` find `libclang` and `libclang` find the libraries in `buildInputs`.
### Examples {#examples} ### Examples {#examples}

View file

@ -309,9 +309,9 @@ Sample output2:
## Adding new plugins to nixpkgs {#adding-new-plugins-to-nixpkgs} ## Adding new plugins to nixpkgs {#adding-new-plugins-to-nixpkgs}
Nix expressions for Vim plugins are stored in [pkgs/misc/vim-plugins](https://github.com/NixOS/nixpkgs/tree/master/pkgs/misc/vim-plugins). For the vast majority of plugins, Nix expressions are automatically generated by running [`./update.py`](https://github.com/NixOS/nixpkgs/blob/master/pkgs/misc/vim-plugins/update.py). This creates a [generated.nix](https://github.com/NixOS/nixpkgs/blob/master/pkgs/misc/vim-plugins/generated.nix) file based on the plugins listed in [vim-plugin-names](https://github.com/NixOS/nixpkgs/blob/master/pkgs/misc/vim-plugins/vim-plugin-names). Plugins are listed in alphabetical order in `vim-plugin-names` using the format `[github username]/[repository]@[gitref]`. For example https://github.com/scrooloose/nerdtree becomes `scrooloose/nerdtree`. Nix expressions for Vim plugins are stored in [pkgs/applications/editors/vim/plugins](https://github.com/NixOS/nixpkgs/tree/master/pkgs/applications/editors/vim/plugins). For the vast majority of plugins, Nix expressions are automatically generated by running [`./update.py`](https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/editors/vim/plugins/update.py). This creates a [generated.nix](https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/editors/vim/plugins/generated.nix) file based on the plugins listed in [vim-plugin-names](https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/editors/vim/plugins/vim-plugin-names). Plugins are listed in alphabetical order in `vim-plugin-names` using the format `[github username]/[repository]@[gitref]`. For example https://github.com/scrooloose/nerdtree becomes `scrooloose/nerdtree`.
Some plugins require overrides in order to function properly. Overrides are placed in [overrides.nix](https://github.com/NixOS/nixpkgs/blob/master/pkgs/misc/vim-plugins/overrides.nix). Overrides are most often required when a plugin requires some dependencies, or extra steps are required during the build process. For example `deoplete-fish` requires both `deoplete-nvim` and `vim-fish`, and so the following override was added: Some plugins require overrides in order to function properly. Overrides are placed in [overrides.nix](https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/editors/vim/plugins/overrides.nix). Overrides are most often required when a plugin requires some dependencies, or extra steps are required during the build process. For example `deoplete-fish` requires both `deoplete-nvim` and `vim-fish`, and so the following override was added:
```nix ```nix
deoplete-fish = super.deoplete-fish.overrideAttrs(old: { deoplete-fish = super.deoplete-fish.overrideAttrs(old: {
@ -330,13 +330,13 @@ Finally, there are some plugins that are also packaged in nodePackages because t
Run the update script with a GitHub API token that has at least `public_repo` access. Running the script without the token is likely to result in rate-limiting (429 errors). For steps on creating an API token, please refer to [GitHub's token documentation](https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/creating-a-personal-access-token). Run the update script with a GitHub API token that has at least `public_repo` access. Running the script without the token is likely to result in rate-limiting (429 errors). For steps on creating an API token, please refer to [GitHub's token documentation](https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/creating-a-personal-access-token).
```sh ```sh
GITHUB_API_TOKEN=my_token ./pkgs/misc/vim-plugins/update.py GITHUB_API_TOKEN=my_token ./pkgs/applications/editors/vim/plugins/update.py
``` ```
Alternatively, set the number of processes to a lower count to avoid rate-limiting. Alternatively, set the number of processes to a lower count to avoid rate-limiting.
```sh ```sh
./pkgs/misc/vim-plugins/update.py --proc 1 ./pkgs/applications/editors/vim/plugins/update.py --proc 1
``` ```
## Important repositories {#important-repositories} ## Important repositories {#important-repositories}

View file

@ -126,7 +126,7 @@ let
getValues getFiles getValues getFiles
optionAttrSetToDocList optionAttrSetToDocList' optionAttrSetToDocList optionAttrSetToDocList'
scrubOptionValue literalExpression literalExample literalDocBook scrubOptionValue literalExpression literalExample literalDocBook
showOption showFiles unknownModule mkOption; showOption showFiles unknownModule mkOption mkPackageOption;
inherit (self.types) isType setType defaultTypeMerge defaultFunctor inherit (self.types) isType setType defaultTypeMerge defaultFunctor
isOptionType mkOptionType; isOptionType mkOptionType;
inherit (self.asserts) inherit (self.asserts)

View file

@ -138,7 +138,7 @@ rec {
# support for that, in turn it's lazy in its values. This means e.g. # support for that, in turn it's lazy in its values. This means e.g.
# a `_module.args.pkgs = import (fetchTarball { ... }) {}` won't # a `_module.args.pkgs = import (fetchTarball { ... }) {}` won't
# start a download when `pkgs` wasn't evaluated. # start a download when `pkgs` wasn't evaluated.
type = types.lazyAttrsOf types.unspecified; type = types.lazyAttrsOf types.raw;
internal = true; internal = true;
description = "Arguments passed to each module."; description = "Arguments passed to each module.";
}; };
@ -151,8 +151,7 @@ rec {
}; };
_module.freeformType = mkOption { _module.freeformType = mkOption {
# Disallow merging for now, but could be implemented nicely with a `types.optionType` type = types.nullOr types.optionType;
type = types.nullOr (types.uniq types.attrs);
internal = true; internal = true;
default = null; default = null;
description = '' description = ''

View file

@ -240,6 +240,11 @@ checkConfigOutput '^"24"$' config.foo ./freeform-attrsOf.nix ./freeform-str-dep-
checkConfigError 'infinite recursion encountered' config.foo ./freeform-attrsOf.nix ./freeform-unstr-dep-str.nix checkConfigError 'infinite recursion encountered' config.foo ./freeform-attrsOf.nix ./freeform-unstr-dep-str.nix
checkConfigError 'The option .* is used but not defined' config.foo ./freeform-lazyAttrsOf.nix ./freeform-unstr-dep-str.nix checkConfigError 'The option .* is used but not defined' config.foo ./freeform-lazyAttrsOf.nix ./freeform-unstr-dep-str.nix
checkConfigOutput '^"24"$' config.foo ./freeform-lazyAttrsOf.nix ./freeform-unstr-dep-str.nix ./define-value-string.nix checkConfigOutput '^"24"$' config.foo ./freeform-lazyAttrsOf.nix ./freeform-unstr-dep-str.nix ./define-value-string.nix
# submodules in freeformTypes should have their locations annotated
checkConfigOutput '/freeform-submodules.nix"$' config.fooDeclarations.0 ./freeform-submodules.nix
# freeformTypes can get merged using `types.type`, including submodules
checkConfigOutput '^10$' config.free.xxx.foo ./freeform-submodules.nix
checkConfigOutput '^10$' config.free.yyy.bar ./freeform-submodules.nix
## types.anything ## types.anything
# Check that attribute sets are merged recursively # Check that attribute sets are merged recursively
@ -284,6 +289,28 @@ checkConfigOutput '^"a b"$' config.resultFoo ./declare-variants.nix ./define-var
checkConfigOutput '^"a y z"$' config.resultFooBar ./declare-variants.nix ./define-variant.nix checkConfigOutput '^"a y z"$' config.resultFooBar ./declare-variants.nix ./define-variant.nix
checkConfigOutput '^"a b c"$' config.resultFooFoo ./declare-variants.nix ./define-variant.nix checkConfigOutput '^"a b c"$' config.resultFooFoo ./declare-variants.nix ./define-variant.nix
## emptyValue's
checkConfigOutput "[ ]" config.list.a ./emptyValues.nix
checkConfigOutput "{ }" config.attrs.a ./emptyValues.nix
checkConfigOutput "null" config.null.a ./emptyValues.nix
checkConfigOutput "{ }" config.submodule.a ./emptyValues.nix
# These types don't have empty values
checkConfigError 'The option .int.a. is used but not defined' config.int.a ./emptyValues.nix
checkConfigError 'The option .nonEmptyList.a. is used but not defined' config.nonEmptyList.a ./emptyValues.nix
## types.raw
checkConfigOutput "{ foo = <CODE>; }" config.unprocessedNesting ./raw.nix
checkConfigOutput "10" config.processedToplevel ./raw.nix
checkConfigError "The option .multiple. is defined multiple times" config.multiple ./raw.nix
checkConfigOutput "bar" config.priorities ./raw.nix
# Test that types.optionType merges types correctly
checkConfigOutput '^10$' config.theOption.int ./optionTypeMerging.nix
checkConfigOutput '^"hello"$' config.theOption.str ./optionTypeMerging.nix
# Test that types.optionType correctly annotates option locations
checkConfigError 'The option .theOption.nested. in .other.nix. is already declared in .optionTypeFile.nix.' config.theOption.nested ./optionTypeFile.nix
cat <<EOF cat <<EOF
====== module tests ====== ====== module tests ======
$pass Pass $pass Pass

View file

@ -0,0 +1,36 @@
{ lib, ... }:
let
inherit (lib) types;
in {
options = {
int = lib.mkOption {
type = types.lazyAttrsOf types.int;
};
list = lib.mkOption {
type = types.lazyAttrsOf (types.listOf types.int);
};
nonEmptyList = lib.mkOption {
type = types.lazyAttrsOf (types.nonEmptyListOf types.int);
};
attrs = lib.mkOption {
type = types.lazyAttrsOf (types.attrsOf types.int);
};
null = lib.mkOption {
type = types.lazyAttrsOf (types.nullOr types.int);
};
submodule = lib.mkOption {
type = types.lazyAttrsOf (types.submodule {});
};
};
config = {
int.a = lib.mkIf false null;
list.a = lib.mkIf false null;
nonEmptyList.a = lib.mkIf false null;
attrs.a = lib.mkIf false null;
null.a = lib.mkIf false null;
submodule.a = lib.mkIf false null;
};
}

View file

@ -0,0 +1,22 @@
{ lib, options, ... }: with lib.types; {
options.fooDeclarations = lib.mkOption {
default = (options.free.type.getSubOptions [])._freeformOptions.foo.declarations;
};
options.free = lib.mkOption {
type = submodule {
config._module.freeformType = lib.mkMerge [
(attrsOf (submodule {
options.foo = lib.mkOption {};
}))
(attrsOf (submodule {
options.bar = lib.mkOption {};
}))
];
};
};
config.free.xxx.foo = 10;
config.free.yyy.bar = 10;
}

View file

@ -0,0 +1,28 @@
{ config, lib, ... }: {
_file = "optionTypeFile.nix";
options.theType = lib.mkOption {
type = lib.types.optionType;
};
options.theOption = lib.mkOption {
type = config.theType;
default = {};
};
config.theType = lib.mkMerge [
(lib.types.submodule {
options.nested = lib.mkOption {
type = lib.types.int;
};
})
(lib.types.submodule {
_file = "other.nix";
options.nested = lib.mkOption {
type = lib.types.str;
};
})
];
}

View file

@ -0,0 +1,27 @@
{ config, lib, ... }: {
options.theType = lib.mkOption {
type = lib.types.optionType;
};
options.theOption = lib.mkOption {
type = config.theType;
};
config.theType = lib.mkMerge [
(lib.types.submodule {
options.int = lib.mkOption {
type = lib.types.int;
default = 10;
};
})
(lib.types.submodule {
options.str = lib.mkOption {
type = lib.types.str;
};
})
];
config.theOption.str = "hello";
}

View file

@ -0,0 +1,30 @@
{ lib, ... }: {
options = {
processedToplevel = lib.mkOption {
type = lib.types.raw;
};
unprocessedNesting = lib.mkOption {
type = lib.types.raw;
};
multiple = lib.mkOption {
type = lib.types.raw;
};
priorities = lib.mkOption {
type = lib.types.raw;
};
};
config = {
processedToplevel = lib.mkIf true 10;
unprocessedNesting.foo = throw "foo";
multiple = lib.mkMerge [
"foo"
"foo"
];
priorities = lib.mkMerge [
"foo"
(lib.mkForce "bar")
];
};
}

View file

@ -61,7 +61,11 @@ let
boolToString boolToString
; ;
inherit (lib.modules) mergeDefinitions; inherit (lib.modules)
mergeDefinitions
fixupOptionType
mergeOptionDecls
;
outer_types = outer_types =
rec { rec {
isType = type: x: (x._type or "") == type; isType = type: x: (x._type or "") == type;
@ -162,6 +166,13 @@ rec {
# nixos/doc/manual/development/option-types.xml! # nixos/doc/manual/development/option-types.xml!
types = rec { types = rec {
raw = mkOptionType rec {
name = "raw";
description = "raw value";
check = value: true;
merge = mergeOneOption;
};
anything = mkOptionType { anything = mkOptionType {
name = "anything"; name = "anything";
description = "anything"; description = "anything";
@ -390,7 +401,7 @@ rec {
).optionalValue ).optionalValue
) def.value ) def.value
) defs))); ) defs)));
emptyValue = { value = {}; }; emptyValue = { value = []; };
getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["*"]); getSubOptions = prefix: elemType.getSubOptions (prefix ++ ["*"]);
getSubModules = elemType.getSubModules; getSubModules = elemType.getSubModules;
substSubModules = m: listOf (elemType.substSubModules m); substSubModules = m: listOf (elemType.substSubModules m);
@ -402,7 +413,7 @@ rec {
let list = addCheck (types.listOf elemType) (l: l != []); let list = addCheck (types.listOf elemType) (l: l != []);
in list // { in list // {
description = "non-empty " + list.description; description = "non-empty " + list.description;
# Note: emptyValue is left as is, because another module may define an element. emptyValue = { }; # no .value attr, meaning unset
}; };
attrsOf = elemType: mkOptionType rec { attrsOf = elemType: mkOptionType rec {
@ -503,7 +514,7 @@ rec {
functionTo = elemType: mkOptionType { functionTo = elemType: mkOptionType {
name = "functionTo"; name = "functionTo";
description = "function that evaluates to a(n) ${elemType.name}"; description = "function that evaluates to a(n) ${elemType.description}";
check = isFunction; check = isFunction;
merge = loc: defs: merge = loc: defs:
fnArgs: (mergeDefinitions (loc ++ [ "[function body]" ]) elemType (map (fn: { inherit (fn) file; value = fn.value fnArgs; }) defs)).mergedValue; fnArgs: (mergeDefinitions (loc ++ [ "[function body]" ]) elemType (map (fn: { inherit (fn) file; value = fn.value fnArgs; }) defs)).mergedValue;
@ -518,6 +529,31 @@ rec {
modules = toList modules; modules = toList modules;
}; };
# The type of a type!
optionType = mkOptionType {
name = "optionType";
description = "optionType";
check = value: value._type or null == "option-type";
merge = loc: defs:
let
# Prepares the type definitions for mergeOptionDecls, which
# annotates submodules types with file locations
optionModules = map ({ value, file }:
{
_file = file;
# There's no way to merge types directly from the module system,
# but we can cheat a bit by just declaring an option with the type
options = lib.mkOption {
type = value;
};
}
) defs;
# Merges all the types into a single one, including submodule merging.
# This also propagates file information to all submodules
mergedOption = fixupOptionType loc (mergeOptionDecls loc optionModules);
in mergedOption.type;
};
submoduleWith = submoduleWith =
{ modules { modules
, specialArgs ? {} , specialArgs ? {}

View file

@ -2418,6 +2418,23 @@
githubId = 5510514; githubId = 5510514;
name = "Conrad Mearns"; name = "Conrad Mearns";
}; };
corbanr = {
email = "corban@raunco.co";
github = "CorbanR";
githubId = 1918683;
matrix = "@corbansolo:matrix.org";
name = "Corban Raun";
keys = [
{
longkeyid = "rsa4096/0xA697A56F1F151189";
fingerprint = "6607 0B24 8CE5 64ED 22CE 0950 A697 A56F 1F15 1189";
}
{
longkeyid = "ed25519/0x230F4AC153F90F29";
fingerprint = "D8CB 816A B678 A4E6 1EC7 5325 230F 4AC1 53F9 0F29";
}
];
};
couchemar = { couchemar = {
email = "couchemar@yandex.ru"; email = "couchemar@yandex.ru";
github = "couchemar"; github = "couchemar";
@ -2993,6 +3010,12 @@
githubId = 8404455; githubId = 8404455;
name = "Diego Lelis"; name = "Diego Lelis";
}; };
DieracDelta = {
email = "justin@restivo.me";
github = "DieracDelta";
githubId = 13730968;
name = "Justin Restivo";
};
diffumist = { diffumist = {
email = "git@diffumist.me"; email = "git@diffumist.me";
github = "diffumist"; github = "diffumist";
@ -6327,6 +6350,12 @@
githubId = 37185887; githubId = 37185887;
name = "Calvin Kim"; name = "Calvin Kim";
}; };
keldu = {
email = "mail@keldu.de";
github = "keldu";
githubId = 15373888;
name = "Claudius Holeksa";
};
kennyballou = { kennyballou = {
email = "kb@devnulllabs.io"; email = "kb@devnulllabs.io";
github = "kennyballou"; github = "kennyballou";
@ -6524,7 +6553,7 @@
githubId = 18447310; githubId = 18447310;
}; };
kloenk = { kloenk = {
email = "me@kloenk.de"; email = "me@kloenk.dev";
matrix = "@kloenk:petabyte.dev"; matrix = "@kloenk:petabyte.dev";
name = "Finn Behrens"; name = "Finn Behrens";
github = "kloenk"; github = "kloenk";
@ -7898,12 +7927,6 @@
github = "kira-bruneau"; github = "kira-bruneau";
githubId = 382041; githubId = 382041;
}; };
meutraa = {
email = "paul+nixpkgs@lost.host";
name = "Paul Meredith";
github = "meutraa";
githubId = 68550871;
};
mephistophiles = { mephistophiles = {
email = "mussitantesmortem@gmail.com"; email = "mussitantesmortem@gmail.com";
name = "Maxim Zhukov"; name = "Maxim Zhukov";
@ -7946,6 +7969,12 @@
githubId = 668926; githubId = 668926;
name = "Maximilian Güntner"; name = "Maximilian Güntner";
}; };
mh = {
email = "68288772+markus-heinrich@users.noreply.github.com";
github = "markus-heinrich";
githubId = 68288772;
name = "Markus Heinrich";
};
mhaselsteiner = { mhaselsteiner = {
email = "magdalena.haselsteiner@gmx.at"; email = "magdalena.haselsteiner@gmx.at";
github = "mhaselsteiner"; github = "mhaselsteiner";
@ -8540,6 +8569,12 @@
githubId = 9636071; githubId = 9636071;
name = "Myrl Hex"; name = "Myrl Hex";
}; };
n0emis = {
email = "nixpkgs@n0emis.network";
github = "n0emis";
githubId = 22817873;
name = "Ember Keske";
};
nadrieril = { nadrieril = {
email = "nadrieril@gmail.com"; email = "nadrieril@gmail.com";
github = "nadrieril"; github = "nadrieril";
@ -9253,6 +9288,12 @@
githubId = 15930073; githubId = 15930073;
name = "Moritz Scheuren"; name = "Moritz Scheuren";
}; };
ozkutuk = {
email = "ozkutuk@protonmail.com";
github = "ozkutuk";
githubId = 5948762;
name = "Berk Özkütük";
};
pablovsky = { pablovsky = {
email = "dealberapablo07@gmail.com"; email = "dealberapablo07@gmail.com";
github = "pablo1107"; github = "pablo1107";
@ -10264,6 +10305,13 @@
githubId = 6047658; githubId = 6047658;
name = "Ryan Horiguchi"; name = "Ryan Horiguchi";
}; };
rhysmdnz = {
email = "rhys@memes.nz";
matrix = "@rhys:memes.nz";
github = "rhysmdnz";
githubId = 2162021;
name = "Rhys Davies";
};
ribose-jeffreylau = { ribose-jeffreylau = {
name = "Jeffrey Lau"; name = "Jeffrey Lau";
email = "jeffrey.lau@ribose.com"; email = "jeffrey.lau@ribose.com";
@ -10940,6 +10988,12 @@
githubId = 19472270; githubId = 19472270;
name = "Sebastian"; name = "Sebastian";
}; };
sebastianblunt = {
name = "Sebastian Blunt";
email = "nix@sebastianblunt.com";
github = "sebastianblunt";
githubId = 47431204;
};
sebbadk = { sebbadk = {
email = "sebastian@sebba.dk"; email = "sebastian@sebba.dk";
github = "SEbbaDK"; github = "SEbbaDK";
@ -11547,6 +11601,12 @@
githubId = 1699155; githubId = 1699155;
name = "Steve Elliott"; name = "Steve Elliott";
}; };
stehessel = {
email = "stephan@stehessel.de";
github = "stehessel";
githubId = 55607356;
name = "Stephan Heßelmann";
};
stelcodes = { stelcodes = {
email = "stel@stel.codes"; email = "stel@stel.codes";
github = "stelcodes"; github = "stelcodes";
@ -12792,9 +12852,9 @@
githubId = 5837359; githubId = 5837359;
name = "Adrian Pistol"; name = "Adrian Pistol";
}; };
vika_nezrimaya = { vikanezrimaya = {
email = "vika@fireburn.ru"; email = "vika@fireburn.ru";
github = "kisik21"; github = "vikanezrimaya";
githubId = 7953163; githubId = 7953163;
name = "Vika Shleina"; name = "Vika Shleina";
keys = [{ keys = [{
@ -12818,6 +12878,12 @@
githubId = 118959; githubId = 118959;
name = "VinyMeuh"; name = "VinyMeuh";
}; };
viraptor = {
email = "nix@viraptor.info";
github = "viraptor";
githubId = 188063;
name = "Stanisław Pitucha";
};
viric = { viric = {
email = "viric@viric.name"; email = "viric@viric.name";
github = "viric"; github = "viric";
@ -13164,7 +13230,7 @@
name = "Wayne Scott"; name = "Wayne Scott";
}; };
wucke13 = { wucke13 = {
email = "info@wucke13.de"; email = "wucke13@gmail.com";
github = "wucke13"; github = "wucke13";
githubId = 20400405; githubId = 20400405;
name = "Wucke"; name = "Wucke";

View file

@ -1,4 +1,4 @@
# Used by pkgs/misc/vim-plugins/update.py and pkgs/applications/editors/kakoune/plugins/update.py # Used by pkgs/applications/editors/vim/plugins/update.py and pkgs/applications/editors/kakoune/plugins/update.py
# format: # format:
# $ nix run nixpkgs.python3Packages.black -c black update.py # $ nix run nixpkgs.python3Packages.black -c black update.py
@ -73,9 +73,13 @@ def retry(ExceptionToCheck: Any, tries: int = 4, delay: float = 3, backoff: floa
return deco_retry return deco_retry
@dataclass
class FetchConfig:
proc: int
github_token: str
def make_request(url: str) -> urllib.request.Request:
token = os.getenv("GITHUB_API_TOKEN") def make_request(url: str, token=None) -> urllib.request.Request:
headers = {} headers = {}
if token is not None: if token is not None:
headers["Authorization"] = f"token {token}" headers["Authorization"] = f"token {token}"
@ -90,6 +94,7 @@ class Repo:
self.branch = branch self.branch = branch
self.alias = alias self.alias = alias
self.redirect: Dict[str, str] = {} self.redirect: Dict[str, str] = {}
self.token = "dummy_token"
@property @property
def name(self): def name(self):
@ -136,6 +141,7 @@ class RepoGitHub(Repo):
) -> None: ) -> None:
self.owner = owner self.owner = owner
self.repo = repo self.repo = repo
self.token = None
'''Url to the repo''' '''Url to the repo'''
super().__init__(self.url(""), branch, alias) super().__init__(self.url(""), branch, alias)
log.debug("Instantiating github repo %s/%s", self.owner, self.repo) log.debug("Instantiating github repo %s/%s", self.owner, self.repo)
@ -150,7 +156,7 @@ class RepoGitHub(Repo):
@retry(urllib.error.URLError, tries=4, delay=3, backoff=2) @retry(urllib.error.URLError, tries=4, delay=3, backoff=2)
def has_submodules(self) -> bool: def has_submodules(self) -> bool:
try: try:
req = make_request(self.url(f"blob/{self.branch}/.gitmodules")) req = make_request(self.url(f"blob/{self.branch}/.gitmodules"), self.token)
urllib.request.urlopen(req, timeout=10).close() urllib.request.urlopen(req, timeout=10).close()
except urllib.error.HTTPError as e: except urllib.error.HTTPError as e:
if e.code == 404: if e.code == 404:
@ -162,7 +168,7 @@ class RepoGitHub(Repo):
@retry(urllib.error.URLError, tries=4, delay=3, backoff=2) @retry(urllib.error.URLError, tries=4, delay=3, backoff=2)
def latest_commit(self) -> Tuple[str, datetime]: def latest_commit(self) -> Tuple[str, datetime]:
commit_url = self.url(f"commits/{self.branch}.atom") commit_url = self.url(f"commits/{self.branch}.atom")
commit_req = make_request(commit_url) commit_req = make_request(commit_url, self.token)
with urllib.request.urlopen(commit_req, timeout=10) as req: with urllib.request.urlopen(commit_req, timeout=10) as req:
self._check_for_redirect(commit_url, req) self._check_for_redirect(commit_url, req)
xml = req.read() xml = req.read()
@ -291,15 +297,41 @@ class Editor:
"""To fill the cache""" """To fill the cache"""
return get_current_plugins(self) return get_current_plugins(self)
def load_plugin_spec(self, plugin_file) -> List[PluginDesc]: def load_plugin_spec(self, config: FetchConfig, plugin_file) -> List[PluginDesc]:
return load_plugin_spec(plugin_file) plugins = []
with open(plugin_file) as f:
for line in f:
if line.startswith("#"):
continue
plugin = parse_plugin_line(config, line)
plugins.append(plugin)
return plugins
def generate_nix(self, plugins, outfile: str): def generate_nix(self, plugins, outfile: str):
'''Returns nothing for now, writes directly to outfile''' '''Returns nothing for now, writes directly to outfile'''
raise NotImplementedError() raise NotImplementedError()
def get_update(self, input_file: str, outfile: str, proc: int): def get_update(self, input_file: str, outfile: str, config: FetchConfig):
return get_update(input_file, outfile, proc, editor=self) cache: Cache = Cache(self.get_current_plugins(), self.cache_file)
_prefetch = functools.partial(prefetch, cache=cache)
def update() -> dict:
plugin_names = self.load_plugin_spec(config, input_file)
try:
pool = Pool(processes=config.proc)
results = pool.map(_prefetch, plugin_names)
finally:
cache.store()
plugins, redirects = check_results(results)
self.generate_nix(plugins, outfile)
return redirects
return update
@property @property
def attr_path(self): def attr_path(self):
@ -345,7 +377,15 @@ class Editor:
dest="proc", dest="proc",
type=int, type=int,
default=30, default=30,
help="Number of concurrent processes to spawn. Export GITHUB_API_TOKEN allows higher values.", help="Number of concurrent processes to spawn. Setting --github-token allows higher values.",
)
parser.add_argument(
"--github-token",
"-t",
type=str,
default=os.getenv("GITHUB_API_TOKEN"),
help="""Allows to set --proc to higher values.
Uses GITHUB_API_TOKEN environment variables as the default value.""",
) )
parser.add_argument( parser.add_argument(
"--no-commit", "-n", action="store_true", default=False, "--no-commit", "-n", action="store_true", default=False,
@ -414,8 +454,8 @@ def prefetch_plugin(
) )
def fetch_plugin_from_pluginline(plugin_line: str) -> Plugin: def fetch_plugin_from_pluginline(config: FetchConfig, plugin_line: str) -> Plugin:
plugin, _ = prefetch_plugin(parse_plugin_line(plugin_line)) plugin, _ = prefetch_plugin(parse_plugin_line(config, plugin_line))
return plugin return plugin
@ -465,7 +505,7 @@ def make_repo(uri, branch, alias) -> Repo:
repo = Repo(uri.strip(), branch, alias) repo = Repo(uri.strip(), branch, alias)
return repo return repo
def parse_plugin_line(line: str) -> PluginDesc: def parse_plugin_line(config: FetchConfig, line: str) -> PluginDesc:
branch = "HEAD" branch = "HEAD"
alias = None alias = None
uri = line uri = line
@ -476,21 +516,11 @@ def parse_plugin_line(line: str) -> PluginDesc:
uri, branch = uri.split("@") uri, branch = uri.split("@")
repo = make_repo(uri.strip(), branch.strip(), alias) repo = make_repo(uri.strip(), branch.strip(), alias)
repo.token = config.github_token
return PluginDesc(repo, branch.strip(), alias) return PluginDesc(repo, branch.strip(), alias)
def load_plugin_spec(plugin_file: str) -> List[PluginDesc]:
plugins = []
with open(plugin_file) as f:
for line in f:
if line.startswith("#"):
continue
plugin = parse_plugin_line(line)
plugins.append(plugin)
return plugins
def get_cache_path(cache_file_name: str) -> Optional[Path]: def get_cache_path(cache_file_name: str) -> Optional[Path]:
xdg_cache = os.environ.get("XDG_CACHE_HOME", None) xdg_cache = os.environ.get("XDG_CACHE_HOME", None)
if xdg_cache is None: if xdg_cache is None:
@ -556,6 +586,7 @@ def prefetch(
def rewrite_input( def rewrite_input(
config: FetchConfig,
input_file: Path, input_file: Path,
deprecated: Path, deprecated: Path,
redirects: Dict[str, str] = None, redirects: Dict[str, str] = None,
@ -573,8 +604,8 @@ def rewrite_input(
with open(deprecated, "r") as f: with open(deprecated, "r") as f:
deprecations = json.load(f) deprecations = json.load(f)
for old, new in redirects.items(): for old, new in redirects.items():
old_plugin = fetch_plugin_from_pluginline(old) old_plugin = fetch_plugin_from_pluginline(config, old)
new_plugin = fetch_plugin_from_pluginline(new) new_plugin = fetch_plugin_from_pluginline(config, new)
if old_plugin.normalized_name != new_plugin.normalized_name: if old_plugin.normalized_name != new_plugin.normalized_name:
deprecations[old_plugin.normalized_name] = { deprecations[old_plugin.normalized_name] = {
"new": new_plugin.normalized_name, "new": new_plugin.normalized_name,
@ -600,40 +631,21 @@ def commit(repo: git.Repo, message: str, files: List[Path]) -> None:
print("no changes in working tree to commit") print("no changes in working tree to commit")
def get_update(input_file: str, outfile: str, proc: int, editor: Editor):
cache: Cache = Cache(editor.get_current_plugins(), editor.cache_file)
_prefetch = functools.partial(prefetch, cache=cache)
def update() -> dict:
plugin_names = editor.load_plugin_spec(input_file)
try:
pool = Pool(processes=proc)
results = pool.map(_prefetch, plugin_names)
finally:
cache.store()
plugins, redirects = check_results(results)
editor.generate_nix(plugins, outfile)
return redirects
return update
def update_plugins(editor: Editor, args): def update_plugins(editor: Editor, args):
"""The main entry function of this module. All input arguments are grouped in the `Editor`.""" """The main entry function of this module. All input arguments are grouped in the `Editor`."""
log.setLevel(LOG_LEVELS[args.debug]) log.setLevel(LOG_LEVELS[args.debug])
log.info("Start updating plugins") log.info("Start updating plugins")
update = editor.get_update(args.input_file, args.outfile, args.proc) fetch_config = FetchConfig(args.proc, args.github_token)
update = editor.get_update(args.input_file, args.outfile, fetch_config)
redirects = update() redirects = update()
editor.rewrite_input(args.input_file, editor.deprecated, redirects) editor.rewrite_input(fetch_config, args.input_file, editor.deprecated, redirects)
autocommit = not args.no_commit autocommit = not args.no_commit
nixpkgs_repo = None
if autocommit: if autocommit:
nixpkgs_repo = git.Repo(editor.root, search_parent_directories=True) nixpkgs_repo = git.Repo(editor.root, search_parent_directories=True)
commit(nixpkgs_repo, f"{editor.attr_path}: update", [args.outfile]) commit(nixpkgs_repo, f"{editor.attr_path}: update", [args.outfile])
@ -648,9 +660,9 @@ def update_plugins(editor: Editor, args):
) )
for plugin_line in args.add_plugins: for plugin_line in args.add_plugins:
editor.rewrite_input(args.input_file, editor.deprecated, append=(plugin_line + "\n",)) editor.rewrite_input(fetch_config, args.input_file, editor.deprecated, append=(plugin_line + "\n",))
update() update()
plugin = fetch_plugin_from_pluginline(plugin_line) plugin = fetch_plugin_from_pluginline(fetch_config, plugin_line)
if autocommit: if autocommit:
commit( commit(
nixpkgs_repo, nixpkgs_repo,

View file

@ -0,0 +1,202 @@
#!/usr/bin/env nix-shell
#!nix-shell -i python3 -p "python3.withPackages(ps: with ps; [ ])" nix
"""
A program to remove old aliases or convert old aliases to throws
Example usage:
./maintainers/scripts/remove-old-aliases.py --year 2018 --file ./pkgs/top-level/aliases.nix
Check this file with mypy after every change!
$ mypy --strict maintainers/scripts/remove-old-aliases.py
"""
import argparse
import shutil
import subprocess
from datetime import date as datetimedate
from datetime import datetime
from pathlib import Path
def process_args() -> argparse.Namespace:
"""process args"""
arg_parser = argparse.ArgumentParser()
arg_parser.add_argument(
"--year", required=True, type=int, help="operate on aliases older than $year"
)
arg_parser.add_argument(
"--month",
type=int,
default=1,
help="operate on aliases older than $year-$month",
)
arg_parser.add_argument("--file", required=True, type=Path, help="alias file")
arg_parser.add_argument(
"--dry-run", action="store_true", help="don't modify files, only print results"
)
return arg_parser.parse_args()
def get_date_lists(
txt: list[str], cutoffdate: datetimedate
) -> tuple[list[str], list[str], list[str]]:
"""get a list of lines in which the date is older than $cutoffdate"""
date_older_list: list[str] = []
date_older_throw_list: list[str] = []
date_sep_line_list: list[str] = []
for lineno, line in enumerate(txt, start=1):
line = line.rstrip()
my_date = None
for string in line.split():
string = string.strip(":")
try:
# strip ':' incase there is a string like 2019-11-01:
my_date = datetime.strptime(string, "%Y-%m-%d").date()
except ValueError:
try:
my_date = datetime.strptime(string, "%Y-%m").date()
except ValueError:
continue
if my_date is None or my_date > cutoffdate:
continue
if "=" not in line:
date_sep_line_list.append(f"{lineno} {line}")
# 'if' lines could be complicated
elif "if " in line and "if =" not in line:
print(f"RESOLVE MANUALLY {line}")
elif "throw" in line:
date_older_throw_list.append(line)
else:
date_older_list.append(line)
return (
date_older_list,
date_sep_line_list,
date_older_throw_list,
)
def convert_to_throw(date_older_list: list[str]) -> list[tuple[str, str]]:
"""convert a list of lines to throws"""
converted_list = []
for line in date_older_list.copy():
indent: str = " " * (len(line) - len(line.lstrip()))
before_equal = ""
after_equal = ""
try:
before_equal, after_equal = (x.strip() for x in line.split("=", maxsplit=2))
except ValueError as err:
print(err, line, "\n")
date_older_list.remove(line)
continue
alias = before_equal.strip()
after_equal_list = [x.strip(";:") for x in after_equal.split()]
converted = (
f"{indent}{alias} = throw \"'{alias}' has been renamed to/replaced by"
f" '{after_equal_list.pop(0)}'\";"
f' # Converted to throw {datetime.today().strftime("%Y-%m-%d")}'
)
converted_list.append((line, converted))
return converted_list
def generate_text_to_write(
txt: list[str],
date_older_list: list[str],
converted_to_throw: list[tuple[str, str]],
date_older_throw_list: list[str],
) -> list[str]:
"""generate a list of text to be written to the aliasfile"""
text_to_write: list[str] = []
for line in txt:
text_to_append: str = ""
if converted_to_throw:
for tupl in converted_to_throw:
if line == tupl[0]:
text_to_append = f"{tupl[1]}\n"
if line not in date_older_list and line not in date_older_throw_list:
text_to_append = f"{line}\n"
if text_to_append:
text_to_write.append(text_to_append)
return text_to_write
def write_file(
aliasfile: Path,
text_to_write: list[str],
) -> None:
"""write file"""
temp_aliasfile = Path(f"{aliasfile}.raliases")
with open(temp_aliasfile, "w", encoding="utf-8") as far:
for line in text_to_write:
far.write(line)
print("\nChecking the syntax of the new aliasfile")
try:
subprocess.run(
["nix-instantiate", "--eval", temp_aliasfile],
check=True,
stdout=subprocess.DEVNULL,
)
except subprocess.CalledProcessError:
print(
"\nSyntax check failed,",
"there may have been a line which only has\n"
'aliasname = "reason why";\n'
"when it should have been\n"
'aliasname = throw "reason why";',
)
temp_aliasfile.unlink()
return
shutil.move(f"{aliasfile}.raliases", aliasfile)
print(f"{aliasfile} modified! please verify with 'git diff'.")
def main() -> None:
"""main"""
args = process_args()
aliasfile = Path(args.file).absolute()
cutoffdate = (datetime.strptime(f"{args.year}-{args.month}-01", "%Y-%m-%d")).date()
txt: list[str] = (aliasfile.read_text(encoding="utf-8")).splitlines()
date_older_list: list[str] = []
date_sep_line_list: list[str] = []
date_older_throw_list: list[str] = []
date_older_list, date_sep_line_list, date_older_throw_list = get_date_lists(
txt, cutoffdate
)
converted_to_throw: list[tuple[str, str]] = []
converted_to_throw = convert_to_throw(date_older_list)
if date_older_list:
print(" Will be converted to throws. ".center(100, "-"))
for l_n in date_older_list:
print(l_n)
if date_older_throw_list:
print(" Will be removed. ".center(100, "-"))
for l_n in date_older_throw_list:
print(l_n)
if date_sep_line_list:
print(" On separate line, resolve manually. ".center(100, "-"))
for l_n in date_sep_line_list:
print(l_n)
if not args.dry_run:
text_to_write = generate_text_to_write(
txt, date_older_list, converted_to_throw, date_older_throw_list
)
write_file(aliasfile, text_to_write)
if __name__ == "__main__":
main()

View file

@ -147,7 +147,7 @@ let
to run update script for specific package, or to run update script for specific package, or
% nix-shell maintainers/scripts/update.nix --arg predicate '(path: pkg: builtins.isList pkg.updateScript && builtins.length pkg.updateScript >= 1 && (let script = builtins.head pkg.updateScript; in builtins.isAttrs script && script.name == "gnome-update-script"))' % nix-shell maintainers/scripts/update.nix --arg predicate '(path: pkg: pkg.updateScript.name or null == "gnome-update-script")'
to run update script for all packages matching given predicate, or to run update script for all packages matching given predicate, or

View file

@ -88,6 +88,10 @@ async def commit_changes(name: str, merge_lock: asyncio.Lock, worktree: str, bra
async with merge_lock: async with merge_lock:
await check_subprocess('git', 'add', *change['files'], cwd=worktree) await check_subprocess('git', 'add', *change['files'], cwd=worktree)
commit_message = '{attrPath}: {oldVersion}{newVersion}'.format(**change) commit_message = '{attrPath}: {oldVersion}{newVersion}'.format(**change)
if 'commitMessage' in change:
commit_message = change['commitMessage']
elif 'commitBody' in change:
commit_message = commit_message + '\n\n' + change['commitBody']
await check_subprocess('git', 'commit', '--quiet', '-m', commit_message, cwd=worktree) await check_subprocess('git', 'commit', '--quiet', '-m', commit_message, cwd=worktree)
await check_subprocess('git', 'cherry-pick', branch) await check_subprocess('git', 'cherry-pick', branch)

View file

@ -50,6 +50,7 @@ with lib.maintainers; {
DianaOlympos DianaOlympos
gleber gleber
happysalada happysalada
minijackson
yurrriq yurrriq
]; ];
scope = "Maintain BEAM-related packages and modules."; scope = "Maintain BEAM-related packages and modules.";

View file

@ -145,26 +145,26 @@ As an example, we will take the case of display managers. There is a
central display manager module for generic display manager options and a central display manager module for generic display manager options and a
module file per display manager backend (sddm, gdm \...). module file per display manager backend (sddm, gdm \...).
There are two approach to this module structure: There are two approaches we could take with this module structure:
- Managing the display managers independently by adding an enable - Configuring the display managers independently by adding an enable
option to every display manager module backend. (NixOS) option to every display manager module backend. (NixOS)
- Managing the display managers in the central module by adding an - Configuring the display managers in the central module by adding
option to select which display manager backend to use. an option to select which display manager backend to use.
Both approaches have problems. Both approaches have problems.
Making backends independent can quickly become hard to manage. For Making backends independent can quickly become hard to manage. For
display managers, there can be only one enabled at a time, but the type display managers, there can only be one enabled at a time, but the
system can not enforce this restriction as there is no relation between type system cannot enforce this restriction as there is no relation
each backend `enable` option. As a result, this restriction has to be between each backend's `enable` option. As a result, this restriction
done explicitely by adding assertions in each display manager backend has to be done explicitly by adding assertions in each display manager
module. backend module.
On the other hand, managing the display managers backends in the central On the other hand, managing the display manager backends in the
module will require to change the central module option every time a new central module will require changing the central module option every
backend is added or removed. time a new backend is added or removed.
By using extensible option types, it is possible to create a placeholder By using extensible option types, it is possible to create a placeholder
option in the central module option in the central module
@ -175,7 +175,7 @@ and to extend it in each backend module
As a result, `displayManager.enable` option values can be added without As a result, `displayManager.enable` option values can be added without
changing the main service module file and the type system automatically changing the main service module file and the type system automatically
enforce that there can only be a single display manager enabled. enforces that there can only be a single display manager enabled.
::: {#ex-option-declaration-eot-service .example} ::: {#ex-option-declaration-eot-service .example}
::: {.title} ::: {.title}

View file

@ -16,9 +16,9 @@ merging is handled.
`types.path` `types.path`
: A filesystem path, defined as anything that when coerced to a string : A filesystem path is anything that starts with a slash when
starts with a slash. Even if derivations can be considered as path, coerced to a string. Even if derivations can be considered as
the more specific `types.package` should be preferred. paths, the more specific `types.package` should be preferred.
`types.package` `types.package`
@ -63,6 +63,24 @@ merging is handled.
``` ```
::: :::
`types.raw`
: A type which doesn't do any checking, merging or nested evaluation. It
accepts a single arbitrary value that is not recursed into, making it
useful for values coming from outside the module system, such as package
sets or arbitrary data. Options of this type are still evaluated according
to priorities and conditionals, so `mkForce`, `mkIf` and co. still work on
the option value itself, but not for any value nested within it. This type
should only be used when checking, merging and nested evaluation are not
desirable.
`types.optionType`
: The type of an option's type. Its merging operation ensures that nested
options have the correct file location annotated, and that if possible,
multiple option definitions are correctly merged together. The main use
case is as the type of the `_module.freeformType` option.
`types.attrs` `types.attrs`
: A free-form attribute set. : A free-form attribute set.

View file

@ -66,6 +66,45 @@ have a predefined type and string generator already declared under
and returning a set with TOML-specific attributes `type` and and returning a set with TOML-specific attributes `type` and
`generate` as specified [below](#pkgs-formats-result). `generate` as specified [below](#pkgs-formats-result).
`pkgs.formats.elixirConf { elixir ? pkgs.elixir }`
: A function taking an attribute set with values
`elixir`
: The Elixir package which will be used to format the generated output
It returns a set with Elixir-Config-specific attributes `type`, `lib`, and
`generate` as specified [below](#pkgs-formats-result).
The `lib` attribute contains functions to be used in settings, for
generating special Elixir values:
`mkRaw elixirCode`
: Outputs the given string as raw Elixir code
`mkGetEnv { envVariable, fallback ? null }`
: Makes the configuration fetch an environment variable at runtime
`mkAtom atom`
: Outputs the given string as an Elixir atom, instead of the default
Elixir binary string. Note: lowercase atoms still needs to be prefixed
with `:`
`mkTuple array`
: Outputs the given array as an Elixir tuple, instead of the default
Elixir list
`mkMap attrset`
: Outputs the given attribute set as an Elixir map, instead of the
default Elixir keyword list
::: {#pkgs-formats-result} ::: {#pkgs-formats-result}
These functions all return an attribute set with these values: These functions all return an attribute set with these values:
::: :::
@ -74,6 +113,12 @@ These functions all return an attribute set with these values:
: A module system type representing a value of the format : A module system type representing a value of the format
`lib`
: Utility functions for convenience, or special interactions with the format.
This attribute is optional. It may contain inside a `types` attribute
containing types specific to this format.
`generate` *`filename jsonValue`* `generate` *`filename jsonValue`*
: A function that can render a value of the format to a file. Returns : A function that can render a value of the format to a file. Returns

View file

@ -41,17 +41,18 @@ checks:
`RefuseManualStop` in the `[Unit]` section, and `X-OnlyManualStart` in the `RefuseManualStop` in the `[Unit]` section, and `X-OnlyManualStart` in the
`[Unit]` section. `[Unit]` section.
- The rest of the behavior is decided whether the unit has `X-StopIfChanged` - Further behavior depends on the unit having `X-StopIfChanged` in the
in the `[Service]` section set (exposed via `[Service]` section set to `true` (exposed via
[systemd.services.\<name\>.stopIfChanged](#opt-systemd.services)). This is [systemd.services.\<name\>.stopIfChanged](#opt-systemd.services)). This is
set to `true` by default and must be explicitly turned off if not wanted. set to `true` by default and must be explicitly turned off if not wanted.
If the flag is enabled, the unit is **stop**ped and then **start**ed. If If the flag is enabled, the unit is **stop**ped and then **start**ed. If
not, the unit is **restart**ed. The goal of the flag is to make sure that not, the unit is **restart**ed. The goal of the flag is to make sure that
the new unit never runs in the old environment which is still in place the new unit never runs in the old environment which is still in place
before the activation script is run. before the activation script is run. This behavior is different when the
service is socket-activated, as outlined in the following steps.
- The last thing that is taken into account is whether the unit is a service - The last thing that is taken into account is whether the unit is a service
and socket-activated. Due to a bug, this is currently only done when and socket-activated. If `X-StopIfChanged` is **not** set, the service
`X-StopIfChanged` is set. If the unit is socket-activated, the socket is is **restart**ed with the others. If it is set, both the service and the
stopped and started, and the service is stopped and to be started by socket socket are **stop**ped and the socket is **start**ed, leaving socket
activation. activation to start the service when it's needed.

View file

@ -215,21 +215,22 @@ lib.mkOption {
manager backend (sddm, gdm ...). manager backend (sddm, gdm ...).
</para> </para>
<para> <para>
There are two approach to this module structure: There are two approaches we could take with this module
structure:
</para> </para>
<itemizedlist> <itemizedlist>
<listitem> <listitem>
<para> <para>
Managing the display managers independently by adding an Configuring the display managers independently by adding
enable option to every display manager module backend. an enable option to every display manager module
(NixOS) backend. (NixOS)
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
Managing the display managers in the central module by Configuring the display managers in the central module
adding an option to select which display manager backend by adding an option to select which display manager
to use. backend to use.
</para> </para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>
@ -238,16 +239,16 @@ lib.mkOption {
</para> </para>
<para> <para>
Making backends independent can quickly become hard to Making backends independent can quickly become hard to
manage. For display managers, there can be only one enabled manage. For display managers, there can only be one enabled
at a time, but the type system can not enforce this at a time, but the type system cannot enforce this
restriction as there is no relation between each backend restriction as there is no relation between each backends
<literal>enable</literal> option. As a result, this <literal>enable</literal> option. As a result, this
restriction has to be done explicitely by adding assertions restriction has to be done explicitly by adding assertions
in each display manager backend module. in each display manager backend module.
</para> </para>
<para> <para>
On the other hand, managing the display managers backends in On the other hand, managing the display manager backends in
the central module will require to change the central module the central module will require changing the central module
option every time a new backend is added or removed. option every time a new backend is added or removed.
</para> </para>
<para> <para>
@ -268,7 +269,7 @@ lib.mkOption {
<para> <para>
As a result, <literal>displayManager.enable</literal> option As a result, <literal>displayManager.enable</literal> option
values can be added without changing the main service module values can be added without changing the main service module
file and the type system automatically enforce that there file and the type system automatically enforces that there
can only be a single display manager enabled. can only be a single display manager enabled.
</para> </para>
<anchor xml:id="ex-option-declaration-eot-service" /> <anchor xml:id="ex-option-declaration-eot-service" />

View file

@ -30,10 +30,10 @@
</term> </term>
<listitem> <listitem>
<para> <para>
A filesystem path, defined as anything that when coerced to A filesystem path is anything that starts with a slash when
a string starts with a slash. Even if derivations can be coerced to a string. Even if derivations can be considered
considered as path, the more specific as paths, the more specific <literal>types.package</literal>
<literal>types.package</literal> should be preferred. should be preferred.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -92,6 +92,39 @@
</programlisting> </programlisting>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>
<literal>types.raw</literal>
</term>
<listitem>
<para>
A type which doesnt do any checking, merging or nested
evaluation. It accepts a single arbitrary value that is not
recursed into, making it useful for values coming from
outside the module system, such as package sets or arbitrary
data. Options of this type are still evaluated according to
priorities and conditionals, so <literal>mkForce</literal>,
<literal>mkIf</literal> and co. still work on the option
value itself, but not for any value nested within it. This
type should only be used when checking, merging and nested
evaluation are not desirable.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>types.optionType</literal>
</term>
<listitem>
<para>
The type of an options type. Its merging operation ensures
that nested options have the correct file location
annotated, and that if possible, multiple option definitions
are correctly merged together. The main use case is as the
type of the <literal>_module.freeformType</literal> option.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term> <term>
<literal>types.attrs</literal> <literal>types.attrs</literal>

View file

@ -137,6 +137,97 @@
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>
<literal>pkgs.formats.elixirConf { elixir ? pkgs.elixir }</literal>
</term>
<listitem>
<para>
A function taking an attribute set with values
</para>
<variablelist>
<varlistentry>
<term>
<literal>elixir</literal>
</term>
<listitem>
<para>
The Elixir package which will be used to format the
generated output
</para>
</listitem>
</varlistentry>
</variablelist>
<para>
It returns a set with Elixir-Config-specific attributes
<literal>type</literal>, <literal>lib</literal>, and
<literal>generate</literal> as specified
<link linkend="pkgs-formats-result">below</link>.
</para>
<para>
The <literal>lib</literal> attribute contains functions to
be used in settings, for generating special Elixir values:
</para>
<variablelist>
<varlistentry>
<term>
<literal>mkRaw elixirCode</literal>
</term>
<listitem>
<para>
Outputs the given string as raw Elixir code
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>mkGetEnv { envVariable, fallback ? null }</literal>
</term>
<listitem>
<para>
Makes the configuration fetch an environment variable
at runtime
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>mkAtom atom</literal>
</term>
<listitem>
<para>
Outputs the given string as an Elixir atom, instead of
the default Elixir binary string. Note: lowercase
atoms still needs to be prefixed with
<literal>:</literal>
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>mkTuple array</literal>
</term>
<listitem>
<para>
Outputs the given array as an Elixir tuple, instead of
the default Elixir list
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<literal>mkMap attrset</literal>
</term>
<listitem>
<para>
Outputs the given attribute set as an Elixir map,
instead of the default Elixir keyword list
</para>
</listitem>
</varlistentry>
</variablelist>
</listitem>
</varlistentry>
</variablelist> </variablelist>
<para xml:id="pkgs-formats-result"> <para xml:id="pkgs-formats-result">
These functions all return an attribute set with these values: These functions all return an attribute set with these values:
@ -152,6 +243,19 @@
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>
<literal>lib</literal>
</term>
<listitem>
<para>
Utility functions for convenience, or special interactions
with the format. This attribute is optional. It may contain
inside a <literal>types</literal> attribute containing types
specific to this format.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term> <term>
<literal>generate</literal> <literal>generate</literal>

View file

@ -88,9 +88,10 @@
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
The rest of the behavior is decided whether the unit has Further behavior depends on the unit having
<literal>X-StopIfChanged</literal> in the <literal>X-StopIfChanged</literal> in the
<literal>[Service]</literal> section set (exposed via <literal>[Service]</literal> section set to
<literal>true</literal> (exposed via
<link linkend="opt-systemd.services">systemd.services.&lt;name&gt;.stopIfChanged</link>). <link linkend="opt-systemd.services">systemd.services.&lt;name&gt;.stopIfChanged</link>).
This is set to <literal>true</literal> by default and must This is set to <literal>true</literal> by default and must
be explicitly turned off if not wanted. If the flag is be explicitly turned off if not wanted. If the flag is
@ -100,17 +101,22 @@
is <emphasis role="strong">restart</emphasis>ed. The goal of is <emphasis role="strong">restart</emphasis>ed. The goal of
the flag is to make sure that the new unit never runs in the the flag is to make sure that the new unit never runs in the
old environment which is still in place before the old environment which is still in place before the
activation script is run. activation script is run. This behavior is different when
the service is socket-activated, as outlined in the
following steps.
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
The last thing that is taken into account is whether the The last thing that is taken into account is whether the
unit is a service and socket-activated. Due to a bug, this unit is a service and socket-activated. If
is currently only done when <literal>X-StopIfChanged</literal> is
<literal>X-StopIfChanged</literal> is set. If the unit is <emphasis role="strong">not</emphasis> set, the service is
socket-activated, the socket is stopped and started, and the <emphasis role="strong">restart</emphasis>ed with the
service is stopped and to be started by socket activation. others. If it is set, both the service and the socket are
<emphasis role="strong">stop</emphasis>ped and the socket is
<emphasis role="strong">start</emphasis>ed, leaving socket
activation to start the service when its needed.
</para> </para>
</listitem> </listitem>
</itemizedlist> </itemizedlist>

View file

@ -26,8 +26,26 @@
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
<literal>iptables</literal> now uses <literal>iptables</literal> is now using
<literal>nf_tables</literal> backend. <literal>nf_tables</literal> under the hood, by using
<literal>iptables-nft</literal>, similar to
<link xlink:href="https://wiki.debian.org/nftables#Current_status">Debian</link>
and
<link xlink:href="https://fedoraproject.org/wiki/Changes/iptables-nft-default">Fedora</link>.
This means, <literal>ip[6]tables</literal>,
<literal>arptables</literal> and <literal>ebtables</literal>
commands will actually show rules from some specific tables in
the <literal>nf_tables</literal> kernel subsystem.
</para>
</listitem>
<listitem>
<para>
systemd got an <literal>nftables</literal> backend, and
configures (networkd) rules in their own
<literal>io.systemd.*</literal> tables. Check
<literal>nft list ruleset</literal> to see these rules, not
<literal>iptables-save</literal> (which only shows
<literal>iptables</literal>-created rules.
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
@ -1429,6 +1447,17 @@ Superuser created successfully.
knob. knob.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
<literal>/usr</literal> will always be included in the initial
ramdisk. See the
<literal>fileSystems.&lt;name&gt;.neededForBoot</literal>
option. If any files exist under <literal>/usr</literal>
(which is not typical for NixOS), they will be included in the
initial ramdisk, increasing its size to a possibly problematic
extent.
</para>
</listitem>
</itemizedlist> </itemizedlist>
</section> </section>
<section xml:id="sec-release-21.11-notable-changes"> <section xml:id="sec-release-21.11-notable-changes">

View file

@ -50,6 +50,18 @@
granular distinction between reloads and restarts. granular distinction between reloads and restarts.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
<link xlink:href="https://kops.sigs.k8s.io"><literal>kops</literal></link>
defaults to 1.22.4, which will enable
<link xlink:href="https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html">Instance
Metadata Service Version 2</link> and require tokens on new
clusters with Kubernetes 1.22. This will increase security by
default, but may break some types of workloads. See the
<link xlink:href="https://kops.sigs.k8s.io/releases/1.22-notes/">release
notes</link> for details.
</para>
</listitem>
</itemizedlist> </itemizedlist>
</section> </section>
<section xml:id="sec-release-22.05-new-services"> <section xml:id="sec-release-22.05-new-services">
@ -98,7 +110,7 @@
<link xlink:href="https://frrouting.org/">FRRouting</link>, a <link xlink:href="https://frrouting.org/">FRRouting</link>, a
popular suite of Internet routing protocol daemons (BGP, BFD, popular suite of Internet routing protocol daemons (BGP, BFD,
OSPF, IS-IS, VVRP and others). Available as OSPF, IS-IS, VVRP and others). Available as
<link linkend="opt-services.ffr.babel.enable">services.frr</link> <link linkend="opt-services.frr.babel.enable">services.frr</link>
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
@ -108,6 +120,13 @@
<link xlink:href="options.html#opt-services.heisenbridge.enable">services.heisenbridge</link>. <link xlink:href="options.html#opt-services.heisenbridge.enable">services.heisenbridge</link>.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
<link xlink:href="https://snowflake.torproject.org/">snowflake-proxy</link>,
a system to defeat internet censorship. Available as
<link xlink:href="options.html#opt-services.snowflake-proxy.enable">services.snowflake-proxy</link>.
</para>
</listitem>
<listitem> <listitem>
<para> <para>
<link xlink:href="https://ergo.chat">ergochat</link>, a modern <link xlink:href="https://ergo.chat">ergochat</link>, a modern
@ -122,6 +141,13 @@
<link xlink:href="options.html#opt-services.powerdns-admin.enable">services.powerdns-admin</link>. <link xlink:href="options.html#opt-services.powerdns-admin.enable">services.powerdns-admin</link>.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
<link xlink:href="https://github.com/postgres/pgadmin4">pgadmin4</link>,
an admin interface for the PostgreSQL database. Available at
<link xlink:href="options.html#opt-services.pgadmin.enable">services.pgadmin</link>.
</para>
</listitem>
<listitem> <listitem>
<para> <para>
<link xlink:href="https://github.com/sezanzeb/input-remapper">input-remapper</link>, <link xlink:href="https://github.com/sezanzeb/input-remapper">input-remapper</link>,
@ -145,6 +171,15 @@
<link xlink:href="options.html#opt-services.maddy.enable">services.maddy</link>. <link xlink:href="options.html#opt-services.maddy.enable">services.maddy</link>.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
<link xlink:href="https://www.scorchworks.com/K40whisperer/k40whisperer.html">K40-Whisperer</link>,
a program to control cheap Chinese laser cutters. Available as
<link xlink:href="options.html#opt-programs.k4-whisperer.enable">programs.k40-whisperer.enable</link>.
Users must add themselves to the <literal>k40</literal> group
to be able to access the device.
</para>
</listitem>
<listitem> <listitem>
<para> <para>
<link xlink:href="https://github.com/mgumz/mtr-exporter">mtr-exporter</link>, <link xlink:href="https://github.com/mgumz/mtr-exporter">mtr-exporter</link>,
@ -196,7 +231,7 @@
<para> <para>
<link xlink:href="https://moosefs.com">moosefs</link>, fault <link xlink:href="https://moosefs.com">moosefs</link>, fault
tolerant petabyte distributed file system. Available as tolerant petabyte distributed file system. Available as
<link linkend="opt-services.moosefs">moosefs</link>. <link linkend="opt-services.moosefs.client.enable">moosefs</link>.
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
@ -353,6 +388,116 @@
its reliance on python2. its reliance on python2.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
The <literal>matrix-synapse</literal> service
(<literal>services.matrix-synapse</literal>) has been
converted to use the <literal>settings</literal> option
defined in RFC42. This means that options that are part of
your <literal>homeserver.yaml</literal> configuration, and
that were specified at the top-level of the module
(<literal>services.matrix-synapse</literal>) now need to be
moved into
<literal>services.matrix-synapse.settings</literal>. And while
not all options you may use are defined in there, they are
still supported, because you can set arbitrary values in this
freeform type.
</para>
<para>
An example to make the required migration clearer:
</para>
<para>
Before:
</para>
<programlisting language="bash">
{
services.matrix-synapse = {
enable = true;
server_name = &quot;example.com&quot;;
public_baseurl = &quot;https://example.com:8448&quot;;
enable_registration = false;
registration_shared_secret = &quot;xohshaeyui8jic7uutuDogahkee3aehuaf6ei3Xouz4iicie5thie6nohNahceut&quot;;
macaroon_secret_key = &quot;xoo8eder9seivukaiPh1cheikohquuw8Yooreid0The4aifahth3Ou0aiShaiz4l&quot;;
tls_certificate_path = &quot;/var/lib/acme/example.com/fullchain.pem&quot;;
tls_certificate_path = &quot;/var/lib/acme/example.com/fullchain.pem&quot;;
listeners = [ {
port = 8448;
bind_address = &quot;&quot;;
type = &quot;http&quot;;
tls = true;
resources = [ {
names = [ &quot;client&quot; ];
compress = true;
} {
names = [ &quot;federation&quot; ];
compress = false;
} ];
} ];
};
}
</programlisting>
<para>
After:
</para>
<programlisting language="bash">
{
services.matrix-synapse = {
enable = true;
# this attribute set holds all values that go into your homeserver.yaml configuration
# See https://github.com/matrix-org/synapse/blob/develop/docs/sample_config.yaml for
# possible values.
settings = {
server_name = &quot;example.com&quot;;
public_baseurl = &quot;https://example.com:8448&quot;;
enable_registration = false;
# pass `registration_shared_secret` and `macaroon_secret_key` via `extraConfigFiles` instead
tls_certificate_path = &quot;/var/lib/acme/example.com/fullchain.pem&quot;;
tls_certificate_path = &quot;/var/lib/acme/example.com/fullchain.pem&quot;;
listeners = [ {
port = 8448;
bind_address = [
&quot;::&quot;
&quot;0.0.0.0&quot;
];
type = &quot;http&quot;;
tls = true;
resources = [ {
names = [ &quot;client&quot; ];
compress = true;
} {
names = [ &quot;federation&quot; ];
compress = false;
} ];
} ];
};
extraConfigFiles = [
/run/keys/matrix-synapse/secrets.yaml
];
};
}
</programlisting>
<para>
The secrets in your original config should be migrated into a
YAML file that is included via
<literal>extraConfigFiles</literal>.
</para>
<para>
Additionally a few option defaults have been synced up with
upstream default values, for example the
<literal>max_upload_size</literal> grew from
<literal>10M</literal> to <literal>50M</literal>.
</para>
</listitem>
<listitem> <listitem>
<para> <para>
The MoinMoin wiki engine The MoinMoin wiki engine
@ -444,6 +589,13 @@
support due to python2 deprecation in nixpkgs support due to python2 deprecation in nixpkgs
</para> </para>
</listitem> </listitem>
<listitem>
<para>
<literal>services.miniflux.adminCredentialFiles</literal> is
now required, instead of defaulting to
<literal>admin</literal> and <literal>password</literal>.
</para>
</listitem>
<listitem> <listitem>
<para> <para>
The <literal>autorestic</literal> package has been upgraded The <literal>autorestic</literal> package has been upgraded
@ -530,6 +682,21 @@
<literal>tilp2</literal> was removed together with its module <literal>tilp2</literal> was removed together with its module
</para> </para>
</listitem> </listitem>
<listitem>
<para>
The F-PROT antivirus (<literal>fprot</literal> package) and
its service module were removed because it reached
<link xlink:href="https://kb.cyren.com/av-support/index.php?/Knowledgebase/Article/View/434/0/end-of-sale--end-of-life-for-f-prot-and-csam">end-of-life</link>.
</para>
</listitem>
<listitem>
<para>
<literal>bird1</literal> and its modules
<literal>services.bird</literal> as well as
<literal>services.bird6</literal> have been removed. Upgrade
to <literal>services.bird2</literal>.
</para>
</listitem>
<listitem> <listitem>
<para> <para>
The options The options
@ -558,6 +725,15 @@
<literal>~/.local/share/polymc/polymc.cfg</literal>. <literal>~/.local/share/polymc/polymc.cfg</literal>.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
<literal>systemd-nspawn@.service</literal> settings have been
reverted to the default systemd behaviour. User namespaces are
now activated by default. If you want to keep running nspawn
containers without user namespaces you need to set
<literal>systemd.nspawn.&lt;name&gt;.execConfig.PrivateUsers = false</literal>
</para>
</listitem>
<listitem> <listitem>
<para> <para>
The terraform 0.12 compatibility has been removed and the The terraform 0.12 compatibility has been removed and the
@ -590,6 +766,13 @@
<literal>otelcorecol</literal> and enjoy a 7x smaller binary. <literal>otelcorecol</literal> and enjoy a 7x smaller binary.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
<literal>pkgs.pgadmin</literal> now refers to
<literal>pkgs.pgadmin4</literal>. If you still need pgadmin3,
use <literal>pkgs.pgadmin3</literal>.
</para>
</listitem>
<listitem> <listitem>
<para> <para>
<literal>pkgs.noto-fonts-cjk</literal> is now deprecated in <literal>pkgs.noto-fonts-cjk</literal> is now deprecated in
@ -700,6 +883,83 @@
<link xlink:href="https://github.com/olimorris/onedarkpro.nvim">olimorris/onedarkpro.nvim</link>). <link xlink:href="https://github.com/olimorris/onedarkpro.nvim">olimorris/onedarkpro.nvim</link>).
</para> </para>
</listitem> </listitem>
<listitem>
<para>
<literal>services.pipewire.enable</literal> will default to
enabling the WirePlumber session manager instead of
pipewire-media-session. pipewire-media-session is deprecated
by upstream and not recommended, but can still be manually
enabled by setting
<literal>services.pipewire.media-session.enable</literal> to
<literal>true</literal> and
<literal>services.pipewire.wireplumber.enable</literal> to
<literal>false</literal>.
</para>
</listitem>
<listitem>
<para>
<literal>pkgs.makeDesktopItem</literal> has been refactored to
provide a more idiomatic API. Specifically:
</para>
<itemizedlist spacing="compact">
<listitem>
<para>
All valid options as of FDO Desktop Entry specification
version 1.4 can now be passed in as explicit arguments
</para>
</listitem>
<listitem>
<para>
<literal>exec</literal> can now be null, for entries that
are not of type Application
</para>
</listitem>
<listitem>
<para>
<literal>mimeType</literal> argument is renamed to
<literal>mimeTypes</literal> for consistency
</para>
</listitem>
<listitem>
<para>
<literal>mimeTypes</literal>,
<literal>categories</literal>,
<literal>implements</literal>,
<literal>keywords</literal>, <literal>onlyShowIn</literal>
and <literal>notShowIn</literal> take lists of strings
instead of one string with semicolon separators
</para>
</listitem>
<listitem>
<para>
<literal>extraDesktopEntries</literal> renamed to
<literal>extraConfig</literal> for consistency
</para>
</listitem>
<listitem>
<para>
Actions should now be provided as an attrset
<literal>actions</literal>, the <literal>Actions</literal>
line will be autogenerated.
</para>
</listitem>
<listitem>
<para>
<literal>extraEntries</literal> is removed.
</para>
</listitem>
<listitem>
<para>
Additional validation is added both at eval time and at
build time.
</para>
</listitem>
</itemizedlist>
<para>
See the <literal>vscode</literal> package for a more detailed
example.
</para>
</listitem>
</itemizedlist> </itemizedlist>
</section> </section>
<section xml:id="sec-release-22.05-notable-changes"> <section xml:id="sec-release-22.05-notable-changes">
@ -901,6 +1161,16 @@
<literal>true</literal>. <literal>true</literal>.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
The <literal>element-desktop</literal> package now has an
<literal>useKeytar</literal> option (defaults to
<literal>true</literal>), which allows disabling
<literal>keytar</literal> and in turn
<literal>libsecret</literal> usage (which binds to native
credential managers / keychain libraries).
</para>
</listitem>
<listitem> <listitem>
<para> <para>
The option <literal>services.thelounge.plugins</literal> has The option <literal>services.thelounge.plugins</literal> has
@ -916,6 +1186,14 @@
renamed to <literal>linux-firmware</literal>. renamed to <literal>linux-firmware</literal>.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
It is now possible to specify wordlists to include as handy to
access environment variables using the
<literal>config.environment.wordlist</literal> configuration
options.
</para>
</listitem>
<listitem> <listitem>
<para> <para>
The <literal>services.mbpfan</literal> module was converted to The <literal>services.mbpfan</literal> module was converted to
@ -954,6 +1232,13 @@
Plugins are automatically repackaged using autoPatchelf. Plugins are automatically repackaged using autoPatchelf.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
<literal>services.logrotate.enable</literal> now defaults to
true if any rotate path has been defined, and some paths have
been added by default.
</para>
</listitem>
<listitem> <listitem>
<para> <para>
The <literal>zrepl</literal> package has been updated from The <literal>zrepl</literal> package has been updated from
@ -990,10 +1275,20 @@
warning. warning.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
The <literal>pomerium-cli</literal> command has been moved out
of the <literal>pomerium</literal> package into the
<literal>pomerium-cli</literal> package, following upstreams
repository split. If you are using the
<literal>pomerium-cli</literal> command, you should now
install the <literal>pomerium-cli</literal> package.
</para>
</listitem>
<listitem> <listitem>
<para> <para>
The option The option
<link linkend="opt-services.networking.networkmanager.enableFccUnlock">services.networking.networkmanager.enableFccUnlock</link> <link linkend="opt-networking.networkmanager.enableFccUnlock">services.networking.networkmanager.enableFccUnlock</link>
was added to support FCC unlock procedures. Since release was added to support FCC unlock procedures. Since release
1.18.4, the ModemManager daemon no longer automatically 1.18.4, the ModemManager daemon no longer automatically
performs the FCC unlock procedure by default. See performs the FCC unlock procedure by default. See
@ -1010,6 +1305,14 @@
<literal>tmux</literal>. <literal>tmux</literal>.
</para> </para>
</listitem> </listitem>
<listitem>
<para>
The polkit service, available at
<literal>security.polkit.enable</literal>, is now disabled by
default. It will automatically be enabled through services and
desktop environments as needed.
</para>
</listitem>
</itemizedlist> </itemizedlist>
</section> </section>
</section> </section>

View file

@ -8,6 +8,7 @@
This section lists the release notes for each stable version of NixOS and This section lists the release notes for each stable version of NixOS and
current unstable revision. current unstable revision.
</para> </para>
<xi:include href="../from_md/release-notes/rl-2205.section.xml" />
<xi:include href="../from_md/release-notes/rl-2111.section.xml" /> <xi:include href="../from_md/release-notes/rl-2111.section.xml" />
<xi:include href="../from_md/release-notes/rl-2105.section.xml" /> <xi:include href="../from_md/release-notes/rl-2105.section.xml" />
<xi:include href="../from_md/release-notes/rl-2009.section.xml" /> <xi:include href="../from_md/release-notes/rl-2009.section.xml" />

View file

@ -8,7 +8,15 @@ In addition to numerous new and upgraded packages, this release has the followin
- Nix has been updated to version 2.4, reference its [release notes](https://discourse.nixos.org/t/nix-2-4-released/15822) for more information on what has changed. The previous version of Nix, 2.3.16, remains available for the time being in the `nix_2_3` package. - Nix has been updated to version 2.4, reference its [release notes](https://discourse.nixos.org/t/nix-2-4-released/15822) for more information on what has changed. The previous version of Nix, 2.3.16, remains available for the time being in the `nix_2_3` package.
- `iptables` now uses `nf_tables` backend. - `iptables` is now using `nf_tables` under the hood, by using `iptables-nft`,
similar to [Debian](https://wiki.debian.org/nftables#Current_status) and
[Fedora](https://fedoraproject.org/wiki/Changes/iptables-nft-default).
This means, `ip[6]tables`, `arptables` and `ebtables` commands will actually
show rules from some specific tables in the `nf_tables` kernel subsystem.
- systemd got an `nftables` backend, and configures (networkd) rules in their
own `io.systemd.*` tables. Check `nft list ruleset` to see these rules, not
`iptables-save` (which only shows `iptables`-created rules.
- PHP now defaults to PHP 8.0, updated from 7.4. - PHP now defaults to PHP 8.0, updated from 7.4.
@ -419,6 +427,9 @@ In addition to numerous new and upgraded packages, this release has the followin
- The Linux kernel for security reasons now restricts access to BPF syscalls via `BPF_UNPRIV_DEFAULT_OFF=y`. Unprivileged access can be reenabled via the `kernel.unprivileged_bpf_disabled` sysctl knob. - The Linux kernel for security reasons now restricts access to BPF syscalls via `BPF_UNPRIV_DEFAULT_OFF=y`. Unprivileged access can be reenabled via the `kernel.unprivileged_bpf_disabled` sysctl knob.
- `/usr` will always be included in the initial ramdisk. See the `fileSystems.<name>.neededForBoot` option.
If any files exist under `/usr` (which is not typical for NixOS), they will be included in the initial ramdisk, increasing its size to a possibly problematic extent.
## Other Notable Changes {#sec-release-21.11-notable-changes} ## Other Notable Changes {#sec-release-21.11-notable-changes}

View file

@ -19,6 +19,8 @@ In addition to numerous new and upgraded packages, this release has the followin
- systemd services can now set [systemd.services.\<name\>.reloadTriggers](#opt-systemd.services) instead of `reloadIfChanged` for a more granular distinction between reloads and restarts. - systemd services can now set [systemd.services.\<name\>.reloadTriggers](#opt-systemd.services) instead of `reloadIfChanged` for a more granular distinction between reloads and restarts.
- [`kops`](https://kops.sigs.k8s.io) defaults to 1.22.4, which will enable [Instance Metadata Service Version 2](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html) and require tokens on new clusters with Kubernetes 1.22. This will increase security by default, but may break some types of workloads. See the [release notes](https://kops.sigs.k8s.io/releases/1.22-notes/) for details.
## New Services {#sec-release-22.05-new-services} ## New Services {#sec-release-22.05-new-services}
- [aesmd](https://github.com/intel/linux-sgx#install-the-intelr-sgx-psw), the Intel SGX Architectural Enclave Service Manager. Available as [services.aesmd](#opt-services.aesmd.enable). - [aesmd](https://github.com/intel/linux-sgx#install-the-intelr-sgx-psw), the Intel SGX Architectural Enclave Service Manager. Available as [services.aesmd](#opt-services.aesmd.enable).
@ -31,20 +33,26 @@ In addition to numerous new and upgraded packages, this release has the followin
- [apfs](https://github.com/linux-apfs/linux-apfs-rw), a kernel module for mounting the Apple File System (APFS). - [apfs](https://github.com/linux-apfs/linux-apfs-rw), a kernel module for mounting the Apple File System (APFS).
- [FRRouting](https://frrouting.org/), a popular suite of Internet routing protocol daemons (BGP, BFD, OSPF, IS-IS, VVRP and others). Available as [services.frr](#opt-services.ffr.babel.enable) - [FRRouting](https://frrouting.org/), a popular suite of Internet routing protocol daemons (BGP, BFD, OSPF, IS-IS, VVRP and others). Available as [services.frr](#opt-services.frr.babel.enable)
- [heisenbridge](https://github.com/hifi/heisenbridge), a bouncer-style Matrix IRC bridge. Available as [services.heisenbridge](options.html#opt-services.heisenbridge.enable). - [heisenbridge](https://github.com/hifi/heisenbridge), a bouncer-style Matrix IRC bridge. Available as [services.heisenbridge](options.html#opt-services.heisenbridge.enable).
- [snowflake-proxy](https://snowflake.torproject.org/), a system to defeat internet censorship. Available as [services.snowflake-proxy](options.html#opt-services.snowflake-proxy.enable).
- [ergochat](https://ergo.chat), a modern IRC with IRCv3 features. Available as [services.ergochat](options.html#opt-services.ergochat.enable). - [ergochat](https://ergo.chat), a modern IRC with IRCv3 features. Available as [services.ergochat](options.html#opt-services.ergochat.enable).
- [PowerDNS-Admin](https://github.com/ngoduykhanh/PowerDNS-Admin), a web interface for the PowerDNS server. Available at [services.powerdns-admin](options.html#opt-services.powerdns-admin.enable). - [PowerDNS-Admin](https://github.com/ngoduykhanh/PowerDNS-Admin), a web interface for the PowerDNS server. Available at [services.powerdns-admin](options.html#opt-services.powerdns-admin.enable).
- [pgadmin4](https://github.com/postgres/pgadmin4), an admin interface for the PostgreSQL database. Available at [services.pgadmin](options.html#opt-services.pgadmin.enable).
- [input-remapper](https://github.com/sezanzeb/input-remapper), an easy to use tool to change the mapping of your input device buttons. Available at [services.input-remapper](options.html#opt-services.input-remapper.enable). - [input-remapper](https://github.com/sezanzeb/input-remapper), an easy to use tool to change the mapping of your input device buttons. Available at [services.input-remapper](options.html#opt-services.input-remapper.enable).
- [InvoicePlane](https://invoiceplane.com), web application for managing and creating invoices. Available at [services.invoiceplane](options.html#opt-services.invoiceplane.enable). - [InvoicePlane](https://invoiceplane.com), web application for managing and creating invoices. Available at [services.invoiceplane](options.html#opt-services.invoiceplane.enable).
- [maddy](https://maddy.email), a composable all-in-one mail server. Available as [services.maddy](options.html#opt-services.maddy.enable). - [maddy](https://maddy.email), a composable all-in-one mail server. Available as [services.maddy](options.html#opt-services.maddy.enable).
- [K40-Whisperer](https://www.scorchworks.com/K40whisperer/k40whisperer.html), a program to control cheap Chinese laser cutters. Available as [programs.k40-whisperer.enable](options.html#opt-programs.k4-whisperer.enable). Users must add themselves to the `k40` group to be able to access the device.
- [mtr-exporter](https://github.com/mgumz/mtr-exporter), a Prometheus exporter for mtr metrics. Available as [services.mtr-exporter](options.html#opt-services.mtr-exporter.enable). - [mtr-exporter](https://github.com/mgumz/mtr-exporter), a Prometheus exporter for mtr metrics. Available as [services.mtr-exporter](options.html#opt-services.mtr-exporter.enable).
- [tetrd](https://tetrd.app), share your internet connection from your device to your PC and vice versa through a USB cable. Available at [services.tetrd](#opt-services.tetrd.enable). - [tetrd](https://tetrd.app), share your internet connection from your device to your PC and vice versa through a USB cable. Available at [services.tetrd](#opt-services.tetrd.enable).
@ -58,7 +66,7 @@ In addition to numerous new and upgraded packages, this release has the followin
- [BaGet](https://loic-sharma.github.io/BaGet/), a lightweight NuGet and symbol server. Available at [services.baget](#opt-services.baget.enable). - [BaGet](https://loic-sharma.github.io/BaGet/), a lightweight NuGet and symbol server. Available at [services.baget](#opt-services.baget.enable).
- [moosefs](https://moosefs.com), fault tolerant petabyte distributed file system. - [moosefs](https://moosefs.com), fault tolerant petabyte distributed file system.
Available as [moosefs](#opt-services.moosefs). Available as [moosefs](#opt-services.moosefs.client.enable).
- [prosody-filer](https://github.com/ThomasLeister/prosody-filer), a server for handling XMPP HTTP Upload requests. Available at [services.prosody-filer](#opt-services.prosody-filer.enable). - [prosody-filer](https://github.com/ThomasLeister/prosody-filer), a server for handling XMPP HTTP Upload requests. Available at [services.prosody-filer](#opt-services.prosody-filer.enable).
@ -120,6 +128,95 @@ In addition to numerous new and upgraded packages, this release has the followin
- The `mailpile` email webclient (`services.mailpile`) has been removed due to its reliance on python2. - The `mailpile` email webclient (`services.mailpile`) has been removed due to its reliance on python2.
- The `matrix-synapse` service (`services.matrix-synapse`) has been converted to use the `settings` option defined in RFC42.
This means that options that are part of your `homeserver.yaml` configuration, and that were specified at the top-level of the
module (`services.matrix-synapse`) now need to be moved into `services.matrix-synapse.settings`. And while not all options you
may use are defined in there, they are still supported, because you can set arbitrary values in this freeform type.
An example to make the required migration clearer:
Before:
```nix
{
services.matrix-synapse = {
enable = true;
server_name = "example.com";
public_baseurl = "https://example.com:8448";
enable_registration = false;
registration_shared_secret = "xohshaeyui8jic7uutuDogahkee3aehuaf6ei3Xouz4iicie5thie6nohNahceut";
macaroon_secret_key = "xoo8eder9seivukaiPh1cheikohquuw8Yooreid0The4aifahth3Ou0aiShaiz4l";
tls_certificate_path = "/var/lib/acme/example.com/fullchain.pem";
tls_certificate_path = "/var/lib/acme/example.com/fullchain.pem";
listeners = [ {
port = 8448;
bind_address = "";
type = "http";
tls = true;
resources = [ {
names = [ "client" ];
compress = true;
} {
names = [ "federation" ];
compress = false;
} ];
} ];
};
}
```
After:
```nix
{
services.matrix-synapse = {
enable = true;
# this attribute set holds all values that go into your homeserver.yaml configuration
# See https://github.com/matrix-org/synapse/blob/develop/docs/sample_config.yaml for
# possible values.
settings = {
server_name = "example.com";
public_baseurl = "https://example.com:8448";
enable_registration = false;
# pass `registration_shared_secret` and `macaroon_secret_key` via `extraConfigFiles` instead
tls_certificate_path = "/var/lib/acme/example.com/fullchain.pem";
tls_certificate_path = "/var/lib/acme/example.com/fullchain.pem";
listeners = [ {
port = 8448;
bind_address = [
"::"
"0.0.0.0"
];
type = "http";
tls = true;
resources = [ {
names = [ "client" ];
compress = true;
} {
names = [ "federation" ];
compress = false;
} ];
} ];
};
extraConfigFiles = [
/run/keys/matrix-synapse/secrets.yaml
];
};
}
```
The secrets in your original config should be migrated into a YAML file that is included via `extraConfigFiles`.
Additionally a few option defaults have been synced up with upstream default values, for example the `max_upload_size` grew from `10M` to `50M`.
- The MoinMoin wiki engine (`services.moinmoin`) has been removed, because Python 2 is being retired from nixpkgs. - The MoinMoin wiki engine (`services.moinmoin`) has been removed, because Python 2 is being retired from nixpkgs.
- The `wafHook` hook now honors `NIX_BUILD_CORES` when `enableParallelBuilding` is not set explicitly. Packages can restore the old behaviour by setting `enableParallelBuilding=false`. - The `wafHook` hook now honors `NIX_BUILD_CORES` when `enableParallelBuilding` is not set explicitly. Packages can restore the old behaviour by setting `enableParallelBuilding=false`.
@ -147,6 +244,8 @@ In addition to numerous new and upgraded packages, this release has the followin
- opensmtpd-extras is no longer build with python2 scripting support due to python2 deprecation in nixpkgs - opensmtpd-extras is no longer build with python2 scripting support due to python2 deprecation in nixpkgs
- `services.miniflux.adminCredentialFiles` is now required, instead of defaulting to `admin` and `password`.
- The `autorestic` package has been upgraded from 1.3.0 to 1.5.0 which introduces breaking changes in config file, check [their migration guide](https://autorestic.vercel.app/migration/1.4_1.5) for more details. - The `autorestic` package has been upgraded from 1.3.0 to 1.5.0 which introduces breaking changes in config file, check [their migration guide](https://autorestic.vercel.app/migration/1.4_1.5) for more details.
- For `pkgs.python3.pkgs.ipython`, its direct dependency `pkgs.python3.pkgs.matplotlib-inline` - For `pkgs.python3.pkgs.ipython`, its direct dependency `pkgs.python3.pkgs.matplotlib-inline`
@ -174,10 +273,16 @@ In addition to numerous new and upgraded packages, this release has the followin
- `tilp2` was removed together with its module - `tilp2` was removed together with its module
- The F-PROT antivirus (`fprot` package) and its service module were removed because it
reached [end-of-life](https://kb.cyren.com/av-support/index.php?/Knowledgebase/Article/View/434/0/end-of-sale--end-of-life-for-f-prot-and-csam).
- `bird1` and its modules `services.bird` as well as `services.bird6` have been removed. Upgrade to `services.bird2`.
- The options `networking.interfaces.<name>.ipv4.routes` and `networking.interfaces.<name>.ipv6.routes` are no longer ignored when using networkd instead of the default scripted network backend by setting `networking.useNetworkd` to `true`. - The options `networking.interfaces.<name>.ipv4.routes` and `networking.interfaces.<name>.ipv6.routes` are no longer ignored when using networkd instead of the default scripted network backend by setting `networking.useNetworkd` to `true`.
- MultiMC has been replaced with the fork PolyMC due to upstream developers being hostile to 3rd party package maintainers. PolyMC removes all MultiMC branding and is aimed at providing proper 3rd party packages like the one contained in Nixpkgs. This change affects the data folder where game instances and other save and configuration files are stored. Users with existing installations should rename `~/.local/share/multimc` to `~/.local/share/polymc`. The main config file's path has also moved from `~/.local/share/multimc/multimc.cfg` to `~/.local/share/polymc/polymc.cfg`. - MultiMC has been replaced with the fork PolyMC due to upstream developers being hostile to 3rd party package maintainers. PolyMC removes all MultiMC branding and is aimed at providing proper 3rd party packages like the one contained in Nixpkgs. This change affects the data folder where game instances and other save and configuration files are stored. Users with existing installations should rename `~/.local/share/multimc` to `~/.local/share/polymc`. The main config file's path has also moved from `~/.local/share/multimc/multimc.cfg` to `~/.local/share/polymc/polymc.cfg`.
- `systemd-nspawn@.service` settings have been reverted to the default systemd behaviour. User namespaces are now activated by default. If you want to keep running nspawn containers without user namespaces you need to set `systemd.nspawn.<name>.execConfig.PrivateUsers = false`
- The terraform 0.12 compatibility has been removed and the `terraform.withPlugins` and `terraform-providers.mkProvider` implementations simplified. Providers now need to be stored under - The terraform 0.12 compatibility has been removed and the `terraform.withPlugins` and `terraform-providers.mkProvider` implementations simplified. Providers now need to be stored under
`$out/libexec/terraform-providers/<registry>/<owner>/<name>/<version>/<os>_<arch>/terraform-provider-<name>_v<version>` (which mkProvider does). `$out/libexec/terraform-providers/<registry>/<owner>/<name>/<version>/<os>_<arch>/terraform-provider-<name>_v<version>` (which mkProvider does).
@ -191,6 +296,8 @@ In addition to numerous new and upgraded packages, this release has the followin
you should change the package you refer to. If you don't need them update your you should change the package you refer to. If you don't need them update your
commands from `otelcontribcol` to `otelcorecol` and enjoy a 7x smaller binary. commands from `otelcontribcol` to `otelcorecol` and enjoy a 7x smaller binary.
- `pkgs.pgadmin` now refers to `pkgs.pgadmin4`.
If you still need pgadmin3, use `pkgs.pgadmin3`.
- `pkgs.noto-fonts-cjk` is now deprecated in favor of `pkgs.noto-fonts-cjk-sans` - `pkgs.noto-fonts-cjk` is now deprecated in favor of `pkgs.noto-fonts-cjk-sans`
and `pkgs.noto-fonts-cjk-serif` because they each have different release and `pkgs.noto-fonts-cjk-serif` because they each have different release
@ -220,6 +327,22 @@ In addition to numerous new and upgraded packages, this release has the followin
- `pkgs.vimPlugins.onedark-nvim` now refers to [navarasu/onedark.nvim](https://github.com/navarasu/onedark.nvim) - `pkgs.vimPlugins.onedark-nvim` now refers to [navarasu/onedark.nvim](https://github.com/navarasu/onedark.nvim)
(formerly refers to [olimorris/onedarkpro.nvim](https://github.com/olimorris/onedarkpro.nvim)). (formerly refers to [olimorris/onedarkpro.nvim](https://github.com/olimorris/onedarkpro.nvim)).
- `services.pipewire.enable` will default to enabling the WirePlumber session manager instead of pipewire-media-session.
pipewire-media-session is deprecated by upstream and not recommended, but can still be manually enabled by setting
`services.pipewire.media-session.enable` to `true` and `services.pipewire.wireplumber.enable` to `false`.
- `pkgs.makeDesktopItem` has been refactored to provide a more idiomatic API. Specifically:
- All valid options as of FDO Desktop Entry specification version 1.4 can now be passed in as explicit arguments
- `exec` can now be null, for entries that are not of type Application
- `mimeType` argument is renamed to `mimeTypes` for consistency
- `mimeTypes`, `categories`, `implements`, `keywords`, `onlyShowIn` and `notShowIn` take lists of strings instead of one string with semicolon separators
- `extraDesktopEntries` renamed to `extraConfig` for consistency
- Actions should now be provided as an attrset `actions`, the `Actions` line will be autogenerated.
- `extraEntries` is removed.
- Additional validation is added both at eval time and at build time.
See the `vscode` package for a more detailed example.
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. --> <!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
## Other Notable Changes {#sec-release-22.05-notable-changes} ## Other Notable Changes {#sec-release-22.05-notable-changes}
@ -304,10 +427,16 @@ In addition to numerous new and upgraded packages, this release has the followin
using `fetchgit` or `fetchhg` if the argument `fetchSubmodules` using `fetchgit` or `fetchhg` if the argument `fetchSubmodules`
is set to `true`. is set to `true`.
- The `element-desktop` package now has an `useKeytar` option (defaults to `true`),
which allows disabling `keytar` and in turn `libsecret` usage
(which binds to native credential managers / keychain libraries).
- The option `services.thelounge.plugins` has been added to allow installing plugins for The Lounge. Plugins can be found in `pkgs.theLoungePlugins.plugins` and `pkgs.theLoungePlugins.themes`. - The option `services.thelounge.plugins` has been added to allow installing plugins for The Lounge. Plugins can be found in `pkgs.theLoungePlugins.plugins` and `pkgs.theLoungePlugins.themes`.
- The `firmwareLinuxNonfree` package has been renamed to `linux-firmware`. - The `firmwareLinuxNonfree` package has been renamed to `linux-firmware`.
- It is now possible to specify wordlists to include as handy to access environment variables using the `config.environment.wordlist` configuration options.
- The `services.mbpfan` module was converted to a [RFC 0042](https://github.com/NixOS/rfcs/blob/master/rfcs/0042-config-option.md) configuration. - The `services.mbpfan` module was converted to a [RFC 0042](https://github.com/NixOS/rfcs/blob/master/rfcs/0042-config-option.md) configuration.
- The default value for `programs.spacefm.settings.graphical_su` got unset. It previously pointed to `gksu` which has been removed. - The default value for `programs.spacefm.settings.graphical_su` got unset. It previously pointed to `gksu` which has been removed.
@ -320,6 +449,9 @@ In addition to numerous new and upgraded packages, this release has the followin
- `services.mattermost.plugins` has been added to allow the declarative installation of Mattermost plugins. - `services.mattermost.plugins` has been added to allow the declarative installation of Mattermost plugins.
Plugins are automatically repackaged using autoPatchelf. Plugins are automatically repackaged using autoPatchelf.
- `services.logrotate.enable` now defaults to true if any rotate path has
been defined, and some paths have been added by default.
- The `zrepl` package has been updated from 0.4.0 to 0.5: - The `zrepl` package has been updated from 0.4.0 to 0.5:
- The RPC protocol version was bumped; all zrepl daemons in a setup must be updated and restarted before replication can resume. - The RPC protocol version was bumped; all zrepl daemons in a setup must be updated and restarted before replication can resume.
@ -329,12 +461,19 @@ In addition to numerous new and upgraded packages, this release has the followin
Reason is that the old name has been deprecated upstream. Reason is that the old name has been deprecated upstream.
Using the old option name will still work, but produce a warning. Using the old option name will still work, but produce a warning.
- The `pomerium-cli` command has been moved out of the `pomerium` package into
the `pomerium-cli` package, following upstream's repository split. If you are
using the `pomerium-cli` command, you should now install the `pomerium-cli`
package.
- The option - The option
[services.networking.networkmanager.enableFccUnlock](#opt-services.networking.networkmanager.enableFccUnlock) [services.networking.networkmanager.enableFccUnlock](#opt-networking.networkmanager.enableFccUnlock)
was added to support FCC unlock procedures. Since release 1.18.4, the ModemManager was added to support FCC unlock procedures. Since release 1.18.4, the ModemManager
daemon no longer automatically performs the FCC unlock procedure by default. See daemon no longer automatically performs the FCC unlock procedure by default. See
[the docs](https://modemmanager.org/docs/modemmanager/fcc-unlock/) for more details. [the docs](https://modemmanager.org/docs/modemmanager/fcc-unlock/) for more details.
- `programs.tmux` has a new option `plugins` that accepts a list of packages from the `tmuxPlugins` group. The specified packages are added to the system and loaded by `tmux`. - `programs.tmux` has a new option `plugins` that accepts a list of packages from the `tmuxPlugins` group. The specified packages are added to the system and loaded by `tmux`.
- The polkit service, available at `security.polkit.enable`, is now disabled by default. It will automatically be enabled through services and desktop environments as needed.
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. --> <!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->

View file

@ -150,7 +150,8 @@ rec {
rm '${output}' rm '${output}'
fi fi
inherit_errexit_restore=$(shopt -p inherit_errexit) inherit_errexit_enabled=0
shopt -pq inherit_errexit && inherit_errexit_enabled=1
shopt -s inherit_errexit shopt -s inherit_errexit
'' ''
+ concatStringsSep + concatStringsSep
@ -170,7 +171,7 @@ rec {
' <<'EOF' ' <<'EOF'
${builtins.toJSON set} ${builtins.toJSON set}
EOF EOF
$inherit_errexit_restore (( ! $inherit_errexit_enabled )) && shopt -u inherit_errexit
''; '';
systemdUtils = { systemdUtils = {

View file

@ -83,6 +83,7 @@ in {
b43Firmware_5_1_138 b43Firmware_5_1_138
b43Firmware_6_30_163_46 b43Firmware_6_30_163_46
b43FirmwareCutter b43FirmwareCutter
xow_dongle-firmware
] ++ optional pkgs.stdenv.hostPlatform.isx86 facetimehd-firmware; ] ++ optional pkgs.stdenv.hostPlatform.isx86 facetimehd-firmware;
}) })
(mkIf cfg.wirelessRegulatoryDatabase { (mkIf cfg.wirelessRegulatoryDatabase {

View file

@ -0,0 +1,23 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.hardware.xone;
in
{
options.hardware.xone = {
enable = mkEnableOption "the xone driver for Xbox One and Xbobx Series X|S accessories";
};
config = mkIf cfg.enable {
boot = {
blacklistedKernelModules = [ "xpad" "mt76x2u" ];
extraModulePackages = with config.boot.kernelPackages; [ xone ];
};
hardware.firmware = [ pkgs.xow_dongle-firmware ];
};
meta = {
maintainers = with maintainers; [ rhysmdnz ];
};
}

View file

@ -24,6 +24,9 @@
[pi3] [pi3]
kernel=u-boot-rpi3.bin kernel=u-boot-rpi3.bin
[pi02]
kernel=u-boot-rpi3.bin
[pi4] [pi4]
kernel=u-boot-rpi4.bin kernel=u-boot-rpi4.bin
enable_gic=1 enable_gic=1
@ -33,6 +36,9 @@
# what the pi3 firmware does by default. # what the pi3 firmware does by default.
disable_overscan=1 disable_overscan=1
# Supported in newer board revisions
arm_boost=1
[all] [all]
# Boot in 64-bit mode. # Boot in 64-bit mode.
arm_64bit=1 arm_64bit=1

View file

@ -129,7 +129,7 @@ let
genericName = "View NixOS documentation in a web browser"; genericName = "View NixOS documentation in a web browser";
icon = "nix-snowflake"; icon = "nix-snowflake";
exec = "nixos-help"; exec = "nixos-help";
categories = "System"; categories = ["System"];
}; };
in pkgs.symlinkJoin { in pkgs.symlinkJoin {

View file

@ -82,14 +82,14 @@ in
git = 41; git = 41;
#fourstore = 42; # dropped in 20.03 #fourstore = 42; # dropped in 20.03
#fourstorehttp = 43; # dropped in 20.03 #fourstorehttp = 43; # dropped in 20.03
virtuoso = 44; #virtuoso = 44; dropped module
#rtkit = 45; # dynamically allocated 2021-09-03 #rtkit = 45; # dynamically allocated 2021-09-03
dovecot2 = 46; dovecot2 = 46;
dovenull2 = 47; dovenull2 = 47;
prayer = 49; prayer = 49;
mpd = 50; mpd = 50;
clamav = 51; clamav = 51;
fprot = 52; #fprot = 52; # unused
# bind = 53; #dynamically allocated as of 2021-09-03 # bind = 53; #dynamically allocated as of 2021-09-03
wwwrun = 54; wwwrun = 54;
#adm = 55; # unused #adm = 55; # unused
@ -412,7 +412,7 @@ in
prayer = 49; prayer = 49;
mpd = 50; mpd = 50;
clamav = 51; clamav = 51;
fprot = 52; #fprot = 52; # unused
#bind = 53; # unused #bind = 53; # unused
wwwrun = 54; wwwrun = 54;
adm = 55; adm = 55;

View file

@ -1,12 +1,17 @@
{ config, lib, options, pkgs, ... }: { config, lib, options, pkgs, ... }:
with lib;
let let
cfg = config.system.nixos; cfg = config.system.nixos;
opt = options.system.nixos; opt = options.system.nixos;
in
inherit (lib)
concatStringsSep mapAttrsToList toLower
literalExpression mkRenamedOptionModule mkDefault mkOption trivial types;
attrsToText = attrs:
concatStringsSep "\n" (mapAttrsToList (n: v: ''${n}="${toString v}"'') attrs);
in
{ {
imports = [ imports = [
(mkRenamedOptionModule [ "system" "nixosVersion" ] [ "system" "nixos" "version" ]) (mkRenamedOptionModule [ "system" "nixosVersion" ] [ "system" "nixos" "version" ])
@ -101,22 +106,30 @@ in
# Generate /etc/os-release. See # Generate /etc/os-release. See
# https://www.freedesktop.org/software/systemd/man/os-release.html for the # https://www.freedesktop.org/software/systemd/man/os-release.html for the
# format. # format.
environment.etc.os-release.text = environment.etc = {
'' "lsb-release".text = attrsToText {
NAME=NixOS LSB_VERSION = "${cfg.release} (${cfg.codeName})";
ID=nixos DISTRIB_ID = "nixos";
VERSION="${cfg.release} (${cfg.codeName})" DISTRIB_RELEASE = cfg.release;
VERSION_CODENAME=${toLower cfg.codeName} DISTRIB_CODENAME = toLower cfg.codeName;
VERSION_ID="${cfg.release}" DISTRIB_DESCRIPTION = "NixOS ${cfg.release} (${cfg.codeName})";
BUILD_ID="${cfg.version}" };
PRETTY_NAME="NixOS ${cfg.release} (${cfg.codeName})"
LOGO="nix-snowflake"
HOME_URL="https://nixos.org/"
DOCUMENTATION_URL="https://nixos.org/learn.html"
SUPPORT_URL="https://nixos.org/community.html"
BUG_REPORT_URL="https://github.com/NixOS/nixpkgs/issues"
'';
"os-release".text = attrsToText {
NAME = "NixOS";
ID = "nixos";
VERSION = "${cfg.release} (${cfg.codeName})";
VERSION_CODENAME = toLower cfg.codeName;
VERSION_ID = cfg.release;
BUILD_ID = cfg.version;
PRETTY_NAME = "NixOS ${cfg.release} (${cfg.codeName})";
LOGO = "nix-snowflake";
HOME_URL = "https://nixos.org/";
DOCUMENTATION_URL = "https://nixos.org/learn.html";
SUPPORT_URL = "https://nixos.org/community.html";
BUG_REPORT_URL = "https://github.com/NixOS/nixpkgs/issues";
};
};
}; };
# uses version info nixpkgs, which requires a full nixpkgs path # uses version info nixpkgs, which requires a full nixpkgs path

View file

@ -0,0 +1,59 @@
{ config, lib, pkgs, ... }:
with lib;
let
concatAndSort = name: files: pkgs.runCommand name {} ''
awk 1 ${lib.escapeShellArgs files} | sed '{ /^\s*$/d; s/^\s\+//; s/\s\+$// }' | sort | uniq > $out
'';
in
{
options = {
environment.wordlist = {
enable = mkEnableOption "environment variables for lists of words";
lists = mkOption {
type = types.attrsOf (types.nonEmptyListOf types.path);
default = {
WORDLIST = [ "${pkgs.scowl}/share/dict/words.txt" ];
};
defaultText = literalExpression ''
{
WORDLIST = [ "''${pkgs.scowl}/share/dict/words.txt" ];
}
'';
description = ''
A set with the key names being the environment variable you'd like to
set and the values being a list of paths to text documents containing
lists of words. The various files will be merged, sorted, duplicates
removed, and extraneous spacing removed.
If you have a handful of words that you want to add to an already
existing wordlist, you may find `builtins.toFile` useful for this
task.
'';
example = literalExpression ''
{
WORDLIST = [ "''${pkgs.scowl}/share/dict/words.txt" ];
AUGMENTED_WORDLIST = [
"''${pkgs.scowl}/share/dict/words.txt"
"''${pkgs.scowl}/share/dict/words.variants.txt"
(builtins.toFile "extra-words" '''
desynchonization
oobleck''')
];
}
'';
};
};
};
config = mkIf config.environment.wordlist.enable {
environment.variables =
lib.mapAttrs
(name: value: "${concatAndSort "wordlist-${name}" value}")
config.environment.wordlist.lists;
};
}

View file

@ -91,6 +91,7 @@
./hardware/video/switcheroo-control.nix ./hardware/video/switcheroo-control.nix
./hardware/video/uvcvideo/default.nix ./hardware/video/uvcvideo/default.nix
./hardware/video/webcam/facetimehd.nix ./hardware/video/webcam/facetimehd.nix
./hardware/xone.nix
./hardware/xpadneo.nix ./hardware/xpadneo.nix
./i18n/input-method/default.nix ./i18n/input-method/default.nix
./i18n/input-method/fcitx.nix ./i18n/input-method/fcitx.nix
@ -115,6 +116,7 @@
./misc/nixpkgs.nix ./misc/nixpkgs.nix
./misc/passthru.nix ./misc/passthru.nix
./misc/version.nix ./misc/version.nix
./misc/wordlist.nix
./misc/nixops-autoluks.nix ./misc/nixops-autoluks.nix
./programs/adb.nix ./programs/adb.nix
./programs/appgate-sdp.nix ./programs/appgate-sdp.nix
@ -166,6 +168,7 @@
./programs/iftop.nix ./programs/iftop.nix
./programs/iotop.nix ./programs/iotop.nix
./programs/java.nix ./programs/java.nix
./programs/k40-whisperer.nix
./programs/kdeconnect.nix ./programs/kdeconnect.nix
./programs/kbdlight.nix ./programs/kbdlight.nix
./programs/less.nix ./programs/less.nix
@ -252,6 +255,7 @@
./security/tpm2.nix ./security/tpm2.nix
./services/admin/meshcentral.nix ./services/admin/meshcentral.nix
./services/admin/oxidized.nix ./services/admin/oxidized.nix
./services/admin/pgadmin.nix
./services/admin/salt/master.nix ./services/admin/salt/master.nix
./services/admin/salt/minion.nix ./services/admin/salt/minion.nix
./services/amqp/activemq/default.nix ./services/amqp/activemq/default.nix
@ -349,7 +353,6 @@
./services/databases/redis.nix ./services/databases/redis.nix
./services/databases/riak.nix ./services/databases/riak.nix
./services/databases/victoriametrics.nix ./services/databases/victoriametrics.nix
./services/databases/virtuoso.nix
./services/desktops/accountsservice.nix ./services/desktops/accountsservice.nix
./services/desktops/bamf.nix ./services/desktops/bamf.nix
./services/desktops/blueman.nix ./services/desktops/blueman.nix
@ -394,6 +397,7 @@
./services/development/jupyterhub/default.nix ./services/development/jupyterhub/default.nix
./services/development/rstudio-server/default.nix ./services/development/rstudio-server/default.nix
./services/development/lorri.nix ./services/development/lorri.nix
./services/development/zammad.nix
./services/display-managers/greetd.nix ./services/display-managers/greetd.nix
./services/editors/emacs.nix ./services/editors/emacs.nix
./services/editors/infinoted.nix ./services/editors/infinoted.nix
@ -451,6 +455,7 @@
./services/hardware/vdr.nix ./services/hardware/vdr.nix
./services/hardware/xow.nix ./services/hardware/xow.nix
./services/home-automation/home-assistant.nix ./services/home-automation/home-assistant.nix
./services/home-automation/zigbee2mqtt.nix
./services/logging/SystemdJournal2Gelf.nix ./services/logging/SystemdJournal2Gelf.nix
./services/logging/awstats.nix ./services/logging/awstats.nix
./services/logging/filebeat.nix ./services/logging/filebeat.nix
@ -495,6 +500,7 @@
./services/mail/roundcube.nix ./services/mail/roundcube.nix
./services/mail/sympa.nix ./services/mail/sympa.nix
./services/mail/nullmailer.nix ./services/mail/nullmailer.nix
./services/matrix/matrix-synapse.nix
./services/matrix/mjolnir.nix ./services/matrix/mjolnir.nix
./services/matrix/pantalaimon.nix ./services/matrix/pantalaimon.nix
./services/misc/ananicy.nix ./services/misc/ananicy.nix
@ -561,7 +567,6 @@
./services/misc/matrix-appservice-discord.nix ./services/misc/matrix-appservice-discord.nix
./services/misc/matrix-appservice-irc.nix ./services/misc/matrix-appservice-irc.nix
./services/misc/matrix-conduit.nix ./services/misc/matrix-conduit.nix
./services/misc/matrix-synapse.nix
./services/misc/mautrix-facebook.nix ./services/misc/mautrix-facebook.nix
./services/misc/mautrix-telegram.nix ./services/misc/mautrix-telegram.nix
./services/misc/mbpfan.nix ./services/misc/mbpfan.nix
@ -622,7 +627,6 @@
./services/misc/weechat.nix ./services/misc/weechat.nix
./services/misc/xmr-stak.nix ./services/misc/xmr-stak.nix
./services/misc/xmrig.nix ./services/misc/xmrig.nix
./services/misc/zigbee2mqtt.nix
./services/misc/zoneminder.nix ./services/misc/zoneminder.nix
./services/misc/zookeeper.nix ./services/misc/zookeeper.nix
./services/monitoring/alerta.nix ./services/monitoring/alerta.nix
@ -873,6 +877,7 @@
./services/networking/shorewall6.nix ./services/networking/shorewall6.nix
./services/networking/shout.nix ./services/networking/shout.nix
./services/networking/sniproxy.nix ./services/networking/sniproxy.nix
./services/networking/snowflake-proxy.nix
./services/networking/smartdns.nix ./services/networking/smartdns.nix
./services/networking/smokeping.nix ./services/networking/smokeping.nix
./services/networking/softether.nix ./services/networking/softether.nix
@ -897,6 +902,7 @@
./services/networking/tcpcrypt.nix ./services/networking/tcpcrypt.nix
./services/networking/teamspeak3.nix ./services/networking/teamspeak3.nix
./services/networking/tedicross.nix ./services/networking/tedicross.nix
./services/networking/tetrd.nix
./services/networking/teleport.nix ./services/networking/teleport.nix
./services/networking/thelounge.nix ./services/networking/thelounge.nix
./services/networking/tinc.nix ./services/networking/tinc.nix
@ -946,7 +952,6 @@
./services/security/clamav.nix ./services/security/clamav.nix
./services/security/fail2ban.nix ./services/security/fail2ban.nix
./services/security/fprintd.nix ./services/security/fprintd.nix
./services/security/fprot.nix
./services/security/haka.nix ./services/security/haka.nix
./services/security/haveged.nix ./services/security/haveged.nix
./services/security/hockeypuck.nix ./services/security/hockeypuck.nix

View file

@ -17,8 +17,8 @@ let
then value then value
else { executable = value; profile = null; extraArgs = []; }; else { executable = value; profile = null; extraArgs = []; };
args = lib.escapeShellArgs ( args = lib.escapeShellArgs (
(optional (opts.profile != null) "--profile=${toString opts.profile}") opts.extraArgs
++ opts.extraArgs ++ (optional (opts.profile != null) "--profile=${toString opts.profile}")
); );
in in
'' ''

View file

@ -0,0 +1,40 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.programs.k40-whisperer;
pkg = cfg.package.override {
udevGroup = cfg.group;
};
in
{
options.programs.k40-whisperer = {
enable = mkEnableOption "K40-Whisperer";
group = mkOption {
type = types.str;
description = ''
Group assigned to the device when connected.
'';
default = "k40";
};
package = mkOption {
type = types.package;
default = pkgs.k40-whisperer;
defaultText = literalExpression "pkgs.k40-whisperer";
example = literalExpression "pkgs.k40-whisperer";
description = ''
K40 Whisperer package to use.
'';
};
};
config = mkIf cfg.enable {
users.groups.${cfg.group} = {};
environment.systemPackages = [ pkg ];
services.udev.packages = [ pkg ];
};
}

View file

@ -8,18 +8,17 @@ let
# Based on https://source.puri.sm/Librem5/librem5-base/-/blob/4596c1056dd75ac7f043aede07887990fd46f572/default/sm.puri.OSK0.desktop # Based on https://source.puri.sm/Librem5/librem5-base/-/blob/4596c1056dd75ac7f043aede07887990fd46f572/default/sm.puri.OSK0.desktop
oskItem = pkgs.makeDesktopItem { oskItem = pkgs.makeDesktopItem {
name = "sm.puri.OSK0"; name = "sm.puri.OSK0";
type = "Application";
desktopName = "On-screen keyboard"; desktopName = "On-screen keyboard";
exec = "${pkgs.squeekboard}/bin/squeekboard"; exec = "${pkgs.squeekboard}/bin/squeekboard";
categories = "GNOME;Core;"; categories = [ "GNOME" "Core" ];
extraEntries = '' onlyShowIn = [ "GNOME" ];
OnlyShowIn=GNOME; noDisplay = true;
NoDisplay=true extraConfig = {
X-GNOME-Autostart-Phase=Panel X-GNOME-Autostart-Phase = "Panel";
X-GNOME-Provides=inputmethod X-GNOME-Provides = "inputmethod";
X-GNOME-Autostart-Notify=true X-GNOME-Autostart-Notify = "true";
X-GNOME-AutoRestart=true X-GNOME-AutoRestart = "true";
''; };
}; };
phocConfigType = types.submodule { phocConfigType = types.submodule {

View file

@ -134,6 +134,7 @@ in {
''; '';
}; };
}; };
security.polkit.enable = true;
security.pam.services.swaylock = {}; security.pam.services.swaylock = {};
hardware.opengl.enable = mkDefault true; hardware.opengl.enable = mkDefault true;
fonts.enableDefaultFonts = mkDefault true; fonts.enableDefaultFonts = mkDefault true;

View file

@ -50,6 +50,7 @@ with lib;
(mkRemovedOptionModule [ "services" "flashpolicyd" ] "The flashpolicyd module has been removed. Adobe Flash Player is deprecated.") (mkRemovedOptionModule [ "services" "flashpolicyd" ] "The flashpolicyd module has been removed. Adobe Flash Player is deprecated.")
(mkRemovedOptionModule [ "services" "fourStore" ] "The fourStore module has been removed") (mkRemovedOptionModule [ "services" "fourStore" ] "The fourStore module has been removed")
(mkRemovedOptionModule [ "services" "fourStoreEndpoint" ] "The fourStoreEndpoint module has been removed") (mkRemovedOptionModule [ "services" "fourStoreEndpoint" ] "The fourStoreEndpoint module has been removed")
(mkRemovedOptionModule [ "services" "fprot" ] "The corresponding package was removed from nixpkgs.")
(mkRemovedOptionModule [ "services" "frab" ] "The frab module has been removed") (mkRemovedOptionModule [ "services" "frab" ] "The frab module has been removed")
(mkRemovedOptionModule [ "services" "kippo" ] "The corresponding package was removed from nixpkgs.") (mkRemovedOptionModule [ "services" "kippo" ] "The corresponding package was removed from nixpkgs.")
(mkRemovedOptionModule [ "services" "mailpile" ] "The corresponding package was removed from nixpkgs.") (mkRemovedOptionModule [ "services" "mailpile" ] "The corresponding package was removed from nixpkgs.")
@ -87,10 +88,9 @@ with lib;
(mkRemovedOptionModule [ "services" "racoon" ] '' (mkRemovedOptionModule [ "services" "racoon" ] ''
The racoon module has been removed, because the software project was abandoned upstream. The racoon module has been removed, because the software project was abandoned upstream.
'') '')
(mkRemovedOptionModule [ "services" "shellinabox" ] "The corresponding package was removed from nixpkgs.") (mkRemovedOptionModule [ "services" "shellinabox" ] "The corresponding package was removed from nixpkgs.")
(mkRemovedOptionModule [ "services" "gogoclient" ] "The corresponding package was removed from nixpkgs.") (mkRemovedOptionModule [ "services" "gogoclient" ] "The corresponding package was removed from nixpkgs.")
(mkRemovedOptionModule [ "services" "virtuoso" ] "The corresponding package was removed from nixpkgs.")
# Do NOT add any option renames here, see top of the file # Do NOT add any option renames here, see top of the file
]; ];

View file

@ -518,7 +518,7 @@ let
auth optional ${pkgs.pam_gnupg}/lib/security/pam_gnupg.so ${optionalString cfg.gnupg.storeOnly " store-only"} auth optional ${pkgs.pam_gnupg}/lib/security/pam_gnupg.so ${optionalString cfg.gnupg.storeOnly " store-only"}
'' + '' +
optionalString cfg.googleAuthenticator.enable '' optionalString cfg.googleAuthenticator.enable ''
auth required ${pkgs.googleAuthenticator}/lib/security/pam_google_authenticator.so no_increment_hotp auth required ${pkgs.google-authenticator}/lib/security/pam_google_authenticator.so no_increment_hotp
'' + '' +
optionalString cfg.duoSecurity.enable '' optionalString cfg.duoSecurity.enable ''
auth required ${pkgs.duo-unix}/lib/security/pam_duo.so auth required ${pkgs.duo-unix}/lib/security/pam_duo.so

View file

@ -12,11 +12,7 @@ in
options = { options = {
security.polkit.enable = mkOption { security.polkit.enable = mkEnableOption "polkit";
type = types.bool;
default = true;
description = "Whether to enable PolKit.";
};
security.polkit.extraConfig = mkOption { security.polkit.extraConfig = mkOption {
type = types.lines; type = types.lines;

View file

@ -175,8 +175,8 @@ in {
serviceName = "${name}.service"; serviceName = "${name}.service";
excludedPath = rootPaths; excludedPath = rootPaths;
} '' } ''
mkdir -p "$out/lib/systemd/system" mkdir -p "$out/lib/systemd/system/$serviceName.d"
serviceFile="$out/lib/systemd/system/$serviceName" serviceFile="$out/lib/systemd/system/$serviceName.d/confinement.conf"
echo '[Service]' > "$serviceFile" echo '[Service]' > "$serviceFile"

View file

@ -0,0 +1,127 @@
{ config, lib, pkgs, ... }:
with lib;
let
pkg = pkgs.pgadmin4;
cfg = config.services.pgadmin;
_base = with types; [ int bool str ];
base = with types; oneOf ([ (listOf (oneOf _base)) (attrsOf (oneOf _base)) ] ++ _base);
formatAttrset = attr:
"{${concatStringsSep "\n" (mapAttrsToList (key: value: "${builtins.toJSON key}: ${formatPyValue value},") attr)}}";
formatPyValue = value:
if builtins.isString value then builtins.toJSON value
else if value ? _expr then value._expr
else if builtins.isInt value then toString value
else if builtins.isBool value then (if value then "True" else "False")
else if builtins.isAttrs value then (formatAttrset value)
else if builtins.isList value then "[${concatStringsSep "\n" (map (v: "${formatPyValue v},") value)}]"
else throw "Unrecognized type";
formatPy = attrs:
concatStringsSep "\n" (mapAttrsToList (key: value: "${key} = ${formatPyValue value}") attrs);
pyType = with types; attrsOf (oneOf [ (attrsOf base) (listOf base) base ]);
in
{
options.services.pgadmin = {
enable = mkEnableOption "PostgreSQL Admin 4";
port = mkOption {
description = "Port for pgadmin4 to run on";
type = types.port;
default = 5050;
};
initialEmail = mkOption {
description = "Initial email for the pgAdmin account.";
type = types.str;
};
initialPasswordFile = mkOption {
description = ''
Initial password file for the pgAdmin account.
NOTE: Should be string not a store path, to prevent the password from being world readable.
'';
type = types.path;
};
openFirewall = mkEnableOption "firewall passthrough for pgadmin4";
settings = mkOption {
description = ''
Settings for pgadmin4.
<link xlink:href="https://www.pgadmin.org/docs/pgadmin4/development/config_py.html">Documentation</link>.
'';
type = pyType;
default= {};
};
};
config = mkIf (cfg.enable) {
networking.firewall.allowedTCPPorts = mkIf (cfg.openFirewall) [ cfg.port ];
services.pgadmin.settings = {
DEFAULT_SERVER_PORT = cfg.port;
SERVER_MODE = true;
} // (optionalAttrs cfg.openFirewall {
DEFAULT_SERVER = mkDefault "::";
});
systemd.services.pgadmin = {
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ];
requires = [ "network.target" ];
# we're adding this optionally so just in case there's any race it'll be caught
# in case postgres doesn't start, pgadmin will just start normally
wants = [ "postgresql.service" ];
path = [ config.services.postgresql.package pkgs.coreutils pkgs.bash ];
preStart = ''
# NOTE: this is idempotent (aka running it twice has no effect)
(
# Email address:
echo ${escapeShellArg cfg.initialEmail}
# file might not contain newline. echo hack fixes that.
PW=$(cat ${escapeShellArg cfg.initialPasswordFile})
# Password:
echo "$PW"
# Retype password:
echo "$PW"
) | ${pkg}/bin/pgadmin4-setup
'';
restartTriggers = [
"/etc/pgadmin/config_system.py"
];
serviceConfig = {
User = "pgadmin";
DynamicUser = true;
LogsDirectory = "pgadmin";
StateDirectory = "pgadmin";
ExecStart = "${pkg}/bin/pgadmin4";
};
};
users.users.pgadmin = {
isSystemUser = true;
group = "pgadmin";
};
users.groups.pgadmin = {};
environment.etc."pgadmin/config_system.py" = {
text = formatPy cfg.settings;
mode = "0600";
user = "pgadmin";
group = "pgadmin";
};
};
}

View file

@ -44,24 +44,24 @@ let
optionString = concatStringsSep " " (mapAttrsToList streamToOption cfg.streams optionString = concatStringsSep " " (mapAttrsToList streamToOption cfg.streams
# global options # global options
++ [ "--stream.bind_to_address ${cfg.listenAddress}" ] ++ [ "--stream.bind_to_address=${cfg.listenAddress}" ]
++ [ "--stream.port ${toString cfg.port}" ] ++ [ "--stream.port=${toString cfg.port}" ]
++ optionalNull cfg.sampleFormat "--stream.sampleformat ${cfg.sampleFormat}" ++ optionalNull cfg.sampleFormat "--stream.sampleformat=${cfg.sampleFormat}"
++ optionalNull cfg.codec "--stream.codec ${cfg.codec}" ++ optionalNull cfg.codec "--stream.codec=${cfg.codec}"
++ optionalNull cfg.streamBuffer "--stream.stream_buffer ${toString cfg.streamBuffer}" ++ optionalNull cfg.streamBuffer "--stream.stream_buffer=${toString cfg.streamBuffer}"
++ optionalNull cfg.buffer "--stream.buffer ${toString cfg.buffer}" ++ optionalNull cfg.buffer "--stream.buffer=${toString cfg.buffer}"
++ optional cfg.sendToMuted "--stream.send_to_muted" ++ optional cfg.sendToMuted "--stream.send_to_muted"
# tcp json rpc # tcp json rpc
++ [ "--tcp.enabled ${toString cfg.tcp.enable}" ] ++ [ "--tcp.enabled=${toString cfg.tcp.enable}" ]
++ optionals cfg.tcp.enable [ ++ optionals cfg.tcp.enable [
"--tcp.bind_to_address ${cfg.tcp.listenAddress}" "--tcp.bind_to_address=${cfg.tcp.listenAddress}"
"--tcp.port ${toString cfg.tcp.port}" ] "--tcp.port=${toString cfg.tcp.port}" ]
# http json rpc # http json rpc
++ [ "--http.enabled ${toString cfg.http.enable}" ] ++ [ "--http.enabled=${toString cfg.http.enable}" ]
++ optionals cfg.http.enable [ ++ optionals cfg.http.enable [
"--http.bind_to_address ${cfg.http.listenAddress}" "--http.bind_to_address=${cfg.http.listenAddress}"
"--http.port ${toString cfg.http.port}" "--http.port=${toString cfg.http.port}"
] ++ optional (cfg.http.docRoot != null) "--http.doc_root \"${toString cfg.http.docRoot}\""); ] ++ optional (cfg.http.docRoot != null) "--http.doc_root=\"${toString cfg.http.docRoot}\"");
in { in {
imports = [ imports = [

View file

@ -266,7 +266,7 @@ in
in in
'' ''
export KUBECONFIG=${clusterAdminKubeconfig} export KUBECONFIG=${clusterAdminKubeconfig}
${kubectl}/bin/kubectl apply -f ${concatStringsSep " \\\n -f " files} ${kubernetes}/bin/kubectl apply -f ${concatStringsSep " \\\n -f " files}
''; '';
})]); })]);

View file

@ -1,99 +0,0 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.virtuoso;
virtuosoUser = "virtuoso";
stateDir = "/var/lib/virtuoso";
in
with lib;
{
###### interface
options = {
services.virtuoso = {
enable = mkEnableOption "Virtuoso Opensource database server";
config = mkOption {
type = types.lines;
default = "";
description = "Extra options to put into Virtuoso configuration file.";
};
parameters = mkOption {
type = types.lines;
default = "";
description = "Extra options to put into [Parameters] section of Virtuoso configuration file.";
};
listenAddress = mkOption {
type = types.str;
default = "1111";
example = "myserver:1323";
description = "ip:port or port to listen on.";
};
httpListenAddress = mkOption {
type = types.nullOr types.str;
default = null;
example = "myserver:8080";
description = "ip:port or port for Virtuoso HTTP server to listen on.";
};
dirsAllowed = mkOption {
type = types.nullOr types.str; # XXX Maybe use a list in the future?
default = null;
example = "/www, /home/";
description = "A list of directories Virtuoso is allowed to access";
};
};
};
###### implementation
config = mkIf cfg.enable {
users.users.${virtuosoUser} =
{ uid = config.ids.uids.virtuoso;
description = "virtuoso user";
home = stateDir;
};
systemd.services.virtuoso = {
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
preStart = ''
mkdir -p ${stateDir}
chown ${virtuosoUser} ${stateDir}
'';
script = ''
cd ${stateDir}
${pkgs.virtuoso}/bin/virtuoso-t +foreground +configfile ${pkgs.writeText "virtuoso.ini" cfg.config}
'';
};
services.virtuoso.config = ''
[Database]
DatabaseFile=${stateDir}/x-virtuoso.db
TransactionFile=${stateDir}/x-virtuoso.trx
ErrorLogFile=${stateDir}/x-virtuoso.log
xa_persistent_file=${stateDir}/x-virtuoso.pxa
[Parameters]
ServerPort=${cfg.listenAddress}
RunAs=${virtuosoUser}
${optionalString (cfg.dirsAllowed != null) "DirsAllowed=${cfg.dirsAllowed}"}
${cfg.parameters}
[HTTPServer]
${optionalString (cfg.httpListenAddress != null) "ServerPort=${cfg.httpListenAddress}"}
'';
};
}

View file

@ -30,6 +30,8 @@ in {
environment.systemPackages = [ pkgs.flatpak ]; environment.systemPackages = [ pkgs.flatpak ];
security.polkit.enable = true;
services.dbus.packages = [ pkgs.flatpak ]; services.dbus.packages = [ pkgs.flatpak ];
systemd.packages = [ pkgs.flatpak ]; systemd.packages = [ pkgs.flatpak ];

View file

@ -8,7 +8,7 @@
}, },
"context.modules": [ "context.modules": [
{ {
"name": "libpipewire-module-rtkit", "name": "libpipewire-module-rt",
"args": {}, "args": {},
"flags": [ "flags": [
"ifexists", "ifexists",

View file

@ -0,0 +1,118 @@
{
"context.properties": {
"link.max-buffers": 16,
"core.daemon": true,
"core.name": "pipewire-0",
"settings.check-quantum": true,
"settings.check-rate": true,
"vm.overrides": {
"default.clock.min-quantum": 1024
}
},
"context.spa-libs": {
"audio.convert.*": "audioconvert/libspa-audioconvert",
"api.alsa.*": "alsa/libspa-alsa",
"support.*": "support/libspa-support"
},
"context.modules": [
{
"name": "libpipewire-module-rt",
"args": {
"nice.level": -11
},
"flags": [
"ifexists",
"nofail"
]
},
{
"name": "libpipewire-module-protocol-native"
},
{
"name": "libpipewire-module-profiler"
},
{
"name": "libpipewire-module-metadata"
},
{
"name": "libpipewire-module-spa-node-factory"
},
{
"name": "libpipewire-module-client-node"
},
{
"name": "libpipewire-module-access",
"args": {}
},
{
"name": "libpipewire-module-adapter"
},
{
"name": "libpipewire-module-link-factory"
}
],
"context.objects": [
{
"factory": "metadata",
"args": {
"metadata.name": "default"
}
},
{
"factory": "spa-node-factory",
"args": {
"factory.name": "support.node.driver",
"node.name": "Dummy-Driver",
"node.group": "pipewire.dummy",
"priority.driver": 20000
}
},
{
"factory": "spa-node-factory",
"args": {
"factory.name": "support.node.driver",
"node.name": "Freewheel-Driver",
"priority.driver": 19000,
"node.group": "pipewire.freewheel",
"node.freewheel": true
}
},
{
"factory": "adapter",
"args": {
"factory.name": "api.alsa.pcm.source",
"node.name": "system",
"node.description": "system",
"media.class": "Audio/Source",
"api.alsa.path": "hw:0",
"node.suspend-on-idle": true,
"resample.disable": true,
"channelmix.disable": true,
"adapter.auto-port-config": {
"mode": "dsp",
"monitor": false,
"position": "unknown"
}
}
},
{
"factory": "adapter",
"args": {
"factory.name": "api.alsa.pcm.sink",
"node.name": "system",
"node.description": "system",
"media.class": "Audio/Sink",
"api.alsa.path": "hw:0",
"node.suspend-on-idle": true,
"resample.disable": true,
"channelmix.disable": true,
"adapter.auto-port-config": {
"mode": "dsp",
"monitor": false,
"position": "unknown"
}
}
}
],
"context.exec": []
}

View file

@ -6,8 +6,10 @@
}, },
"context.modules": [ "context.modules": [
{ {
"name": "libpipewire-module-rtkit", "name": "libpipewire-module-rt",
"args": {}, "args": {
"nice.level": -11
},
"flags": [ "flags": [
"ifexists", "ifexists",
"nofail" "nofail"
@ -37,6 +39,61 @@
} }
} }
], ],
"context.exec": [], "context.exec": [
"stream.properties": {} {
"path": "pactl",
"args": "load-module module-always-sink"
}
],
"stream.properties": {},
"pulse.rules": [
{
"matches": [
{}
],
"actions": {
"update-props": {}
}
},
{
"matches": [
{
"application.process.binary": "teams"
},
{
"application.process.binary": "skypeforlinux"
}
],
"actions": {
"quirks": [
"force-s16-info"
]
}
},
{
"matches": [
{
"application.process.binary": "firefox"
}
],
"actions": {
"quirks": [
"remove-capture-dont-move"
]
}
},
{
"matches": [
{
"application.name": "~speech-dispatcher*"
}
],
"actions": {
"update-props": {
"pulse.min.req": "1024/48000",
"pulse.min.quantum": "1024/48000"
}
}
}
]
} }

View file

@ -3,6 +3,7 @@
"link.max-buffers": 16, "link.max-buffers": 16,
"core.daemon": true, "core.daemon": true,
"core.name": "pipewire-0", "core.name": "pipewire-0",
"default.clock.min-quantum": 16,
"vm.overrides": { "vm.overrides": {
"default.clock.min-quantum": 1024 "default.clock.min-quantum": 1024
} }
@ -19,8 +20,10 @@
}, },
"context.modules": [ "context.modules": [
{ {
"name": "libpipewire-module-rtkit", "name": "libpipewire-module-rt",
"args": {}, "args": {
"nice.level": -11
},
"flags": [ "flags": [
"ifexists", "ifexists",
"nofail" "nofail"

View file

@ -38,9 +38,8 @@ in {
services.pipewire.media-session = { services.pipewire.media-session = {
enable = mkOption { enable = mkOption {
type = types.bool; type = types.bool;
default = config.services.pipewire.enable; default = false;
defaultText = literalExpression "config.services.pipewire.enable"; description = "Whether to enable the deprecated example Pipewire session manager";
description = "Example pipewire session manager";
}; };
package = mkOption { package = mkOption {

View file

@ -25,15 +25,18 @@ let
client = lib.importJSON ./daemon/client.conf.json; client = lib.importJSON ./daemon/client.conf.json;
client-rt = lib.importJSON ./daemon/client-rt.conf.json; client-rt = lib.importJSON ./daemon/client-rt.conf.json;
jack = lib.importJSON ./daemon/jack.conf.json; jack = lib.importJSON ./daemon/jack.conf.json;
minimal = lib.importJSON ./daemon/minimal.conf.json;
pipewire = lib.importJSON ./daemon/pipewire.conf.json; pipewire = lib.importJSON ./daemon/pipewire.conf.json;
pipewire-pulse = lib.importJSON ./daemon/pipewire-pulse.conf.json; pipewire-pulse = lib.importJSON ./daemon/pipewire-pulse.conf.json;
}; };
useSessionManager = cfg.wireplumber.enable || cfg.media-session.enable;
configs = { configs = {
client = recursiveUpdate defaults.client cfg.config.client; client = recursiveUpdate defaults.client cfg.config.client;
client-rt = recursiveUpdate defaults.client-rt cfg.config.client-rt; client-rt = recursiveUpdate defaults.client-rt cfg.config.client-rt;
jack = recursiveUpdate defaults.jack cfg.config.jack; jack = recursiveUpdate defaults.jack cfg.config.jack;
pipewire = recursiveUpdate defaults.pipewire cfg.config.pipewire; pipewire = recursiveUpdate (if useSessionManager then defaults.pipewire else defaults.minimal) cfg.config.pipewire;
pipewire-pulse = recursiveUpdate defaults.pipewire-pulse cfg.config.pipewire-pulse; pipewire-pulse = recursiveUpdate defaults.pipewire-pulse cfg.config.pipewire-pulse;
}; };
in { in {

View file

@ -8,15 +8,18 @@ in
options = { options = {
services.pipewire.wireplumber = { services.pipewire.wireplumber = {
enable = lib.mkEnableOption "A modular session / policy manager for PipeWire"; enable = lib.mkOption {
type = lib.types.bool;
default = config.services.pipewire.enable;
defaultText = lib.literalExpression "config.services.pipewire.enable";
description = "Whether to enable Wireplumber, a modular session / policy manager for PipeWire";
};
package = lib.mkOption { package = lib.mkOption {
type = lib.types.package; type = lib.types.package;
default = pkgs.wireplumber; default = pkgs.wireplumber;
defaultText = lib.literalExpression "pkgs.wireplumber"; defaultText = lib.literalExpression "pkgs.wireplumber";
description = '' description = "The wireplumber derivation to use.";
The wireplumber derivation to use.
'';
}; };
}; };
}; };

View file

@ -0,0 +1,323 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.zammad;
settingsFormat = pkgs.formats.yaml { };
filterNull = filterAttrs (_: v: v != null);
serviceConfig = {
Type = "simple";
Restart = "always";
User = "zammad";
Group = "zammad";
PrivateTmp = true;
StateDirectory = "zammad";
WorkingDirectory = cfg.dataDir;
};
environment = {
RAILS_ENV = "production";
NODE_ENV = "production";
RAILS_SERVE_STATIC_FILES = "true";
RAILS_LOG_TO_STDOUT = "true";
};
databaseConfig = settingsFormat.generate "database.yml" cfg.database.settings;
in
{
options = {
services.zammad = {
enable = mkEnableOption "Zammad, a web-based, open source user support/ticketing solution.";
package = mkOption {
type = types.package;
default = pkgs.zammad;
defaultText = literalExpression "pkgs.zammad";
description = "Zammad package to use.";
};
dataDir = mkOption {
type = types.path;
default = "/var/lib/zammad";
description = ''
Path to a folder that will contain Zammad working directory.
'';
};
host = mkOption {
type = types.str;
default = "127.0.0.1";
example = "192.168.23.42";
description = "Host address.";
};
openPorts = mkOption {
type = types.bool;
default = false;
description = "Whether to open firewall ports for Zammad";
};
port = mkOption {
type = types.port;
default = 3000;
description = "Web service port.";
};
websocketPort = mkOption {
type = types.port;
default = 6042;
description = "Websocket service port.";
};
database = {
type = mkOption {
type = types.enum [ "PostgreSQL" "MySQL" ];
default = "PostgreSQL";
example = "MySQL";
description = "Database engine to use.";
};
host = mkOption {
type = types.nullOr types.str;
default = {
PostgreSQL = "/run/postgresql";
MySQL = "localhost";
}.${cfg.database.type};
defaultText = literalExpression ''
{
PostgreSQL = "/run/postgresql";
MySQL = "localhost";
}.''${config.services.zammad.database.type};
'';
description = ''
Database host address.
'';
};
port = mkOption {
type = types.nullOr types.port;
default = null;
description = "Database port. Use <literal>null</literal> for default port.";
};
name = mkOption {
type = types.str;
default = "zammad";
description = ''
Database name.
'';
};
user = mkOption {
type = types.nullOr types.str;
default = "zammad";
description = "Database user.";
};
passwordFile = mkOption {
type = types.nullOr types.path;
default = null;
example = "/run/keys/zammad-dbpassword";
description = ''
A file containing the password for <option>services.zammad.database.user</option>.
'';
};
createLocally = mkOption {
type = types.bool;
default = true;
description = "Whether to create a local database automatically.";
};
settings = mkOption {
type = settingsFormat.type;
default = { };
example = literalExpression ''
{
}
'';
description = ''
The <filename>database.yml</filename> configuration file as key value set.
See <link xlink:href='TODO' />
for list of configuration parameters.
'';
};
};
secretKeyBaseFile = mkOption {
type = types.nullOr types.path;
default = null;
example = "/run/keys/secret_key_base";
description = ''
The path to a file containing the
<literal>secret_key_base</literal> secret.
Zammad uses <literal>secret_key_base</literal> to encrypt
the cookie store, which contains session data, and to digest
user auth tokens.
Needs to be a 64 byte long string of hexadecimal
characters. You can generate one by running
<screen>
<prompt>$ </prompt>openssl rand -hex 64 >/path/to/secret_key_base_file
</screen>
This should be a string, not a nix path, since nix paths are
copied into the world-readable nix store.
'';
};
};
};
config = mkIf cfg.enable {
services.zammad.database.settings = {
production = mapAttrs (_: v: mkDefault v) (filterNull {
adapter = {
PostgreSQL = "postgresql";
MySQL = "mysql2";
}.${cfg.database.type};
database = cfg.database.name;
pool = 50;
timeout = 5000;
encoding = "utf8";
username = cfg.database.user;
host = cfg.database.host;
port = cfg.database.port;
});
};
networking.firewall.allowedTCPPorts = mkIf cfg.openPorts [
config.services.zammad.port
config.services.zammad.websocketPort
];
users.users.zammad = {
isSystemUser = true;
home = cfg.dataDir;
group = "zammad";
};
users.groups.zammad = { };
assertions = [
{
assertion = cfg.database.createLocally -> cfg.database.user == "zammad";
message = "services.zammad.database.user must be set to \"zammad\" if services.zammad.database.createLocally is set to true";
}
{
assertion = cfg.database.createLocally -> cfg.database.passwordFile == null;
message = "a password cannot be specified if services.zammad.database.createLocally is set to true";
}
];
services.mysql = optionalAttrs (cfg.database.createLocally && cfg.database.type == "MySQL") {
enable = true;
package = mkDefault pkgs.mariadb;
ensureDatabases = [ cfg.database.name ];
ensureUsers = [
{
name = cfg.database.user;
ensurePermissions = { "${cfg.database.name}.*" = "ALL PRIVILEGES"; };
}
];
};
services.postgresql = optionalAttrs (cfg.database.createLocally && cfg.database.type == "PostgreSQL") {
enable = true;
ensureDatabases = [ cfg.database.name ];
ensureUsers = [
{
name = cfg.database.user;
ensurePermissions = { "DATABASE ${cfg.database.name}" = "ALL PRIVILEGES"; };
}
];
};
systemd.services.zammad-web = {
inherit environment;
serviceConfig = serviceConfig // {
# loading all the gems takes time
TimeoutStartSec = 1200;
};
after = [
"network.target"
"postgresql.service"
];
requires = [
"postgresql.service"
];
description = "Zammad web";
wantedBy = [ "multi-user.target" ];
preStart = ''
# Blindly copy the whole project here.
chmod -R +w .
rm -rf ./public/assets/*
rm -rf ./tmp/*
rm -rf ./log/*
cp -r --no-preserve=owner ${cfg.package}/* .
chmod -R +w .
# config file
cp ${databaseConfig} ./config/database.yml
chmod -R +w .
${optionalString (cfg.database.passwordFile != null) ''
{
echo -n " password: "
cat ${cfg.database.passwordFile}
} >> ./config/database.yml
''}
${optionalString (cfg.secretKeyBaseFile != null) ''
{
echo "production: "
echo -n " secret_key_base: "
cat ${cfg.secretKeyBaseFile}
} > ./config/secrets.yml
''}
if [ `${config.services.postgresql.package}/bin/psql \
--host ${cfg.database.host} \
${optionalString
(cfg.database.port != null)
"--port ${toString cfg.database.port}"} \
--username ${cfg.database.user} \
--dbname ${cfg.database.name} \
--command "SELECT COUNT(*) FROM pg_class c \
JOIN pg_namespace s ON s.oid = c.relnamespace \
WHERE s.nspname NOT IN ('pg_catalog', 'pg_toast', 'information_schema') \
AND s.nspname NOT LIKE 'pg_temp%';" | sed -n 3p` -eq 0 ]; then
echo "Initialize database"
./bin/rake --no-system db:migrate
./bin/rake --no-system db:seed
else
echo "Migrate database"
./bin/rake --no-system db:migrate
fi
echo "Done"
'';
script = "./script/rails server -b ${cfg.host} -p ${toString cfg.port}";
};
systemd.services.zammad-websocket = {
inherit serviceConfig environment;
after = [ "zammad-web.service" ];
requires = [ "zammad-web.service" ];
description = "Zammad websocket";
wantedBy = [ "multi-user.target" ];
script = "./script/websocket-server.rb -b ${cfg.host} -p ${toString cfg.websocketPort} start";
};
systemd.services.zammad-scheduler = {
inherit environment;
serviceConfig = serviceConfig // { Type = "forking"; };
after = [ "zammad-web.service" ];
requires = [ "zammad-web.service" ];
description = "Zammad scheduler";
wantedBy = [ "multi-user.target" ];
script = "./script/scheduler.rb start";
};
};
meta.maintainers = with lib.maintainers; [ garbas taeer ];
}

View file

@ -32,6 +32,8 @@ with lib;
environment.systemPackages = [ pkgs.udisks2 ]; environment.systemPackages = [ pkgs.udisks2 ];
security.polkit.enable = true;
services.dbus.packages = [ pkgs.udisks2 ]; services.dbus.packages = [ pkgs.udisks2 ];
systemd.tmpfiles.rules = [ "d /var/lib/udisks2 0755 root root -" ]; systemd.tmpfiles.rules = [ "d /var/lib/udisks2 0755 root root -" ];

View file

@ -135,7 +135,7 @@ in {
}; };
config = mkOption { config = mkOption {
type = types.submodule { type = types.nullOr (types.submodule {
freeformType = format.type; freeformType = format.type;
options = { options = {
# This is a partial selection of the most common options, so new users can quickly # This is a partial selection of the most common options, so new users can quickly
@ -244,7 +244,7 @@ in {
}; };
}; };
}; };
}; });
example = literalExpression '' example = literalExpression ''
{ {
homeassistant = { homeassistant = {
@ -349,10 +349,6 @@ in {
''; '';
description = '' description = ''
The Home Assistant package to use. The Home Assistant package to use.
Override <literal>extraPackages</literal> or <literal>extraComponents</literal> in order to add additional dependencies.
If you specify <option>config</option> and do not set <option>autoExtraComponents</option>
to <literal>false</literal>, overriding <literal>extraComponents</literal> will have no effect.
Avoid <literal>home-assistant.overridePythonAttrs</literal> if you use <literal>autoExtraComponents</literal>.
''; '';
}; };

View file

@ -4,7 +4,6 @@ with lib;
let let
cfg = config.services.logrotate; cfg = config.services.logrotate;
inherit (config.users) groups;
pathOpts = { name, ... }: { pathOpts = { name, ... }: {
options = { options = {
@ -85,10 +84,6 @@ let
}; };
config.name = name; config.name = name;
config.extraConfig = ''
missingok
notifempty
'';
}; };
mkConf = pathOpts: '' mkConf = pathOpts: ''
@ -102,7 +97,11 @@ let
''; '';
paths = sortProperties (attrValues (filterAttrs (_: pathOpts: pathOpts.enable) cfg.paths)); paths = sortProperties (attrValues (filterAttrs (_: pathOpts: pathOpts.enable) cfg.paths));
configFile = pkgs.writeText "logrotate.conf" (concatStringsSep "\n" ((map mkConf paths) ++ [ cfg.extraConfig ])); configFile = pkgs.writeText "logrotate.conf" (
concatStringsSep "\n" (
[ "missingok" "notifempty" cfg.extraConfig ] ++ (map mkConf paths)
)
);
in in
{ {
@ -112,7 +111,10 @@ in
options = { options = {
services.logrotate = { services.logrotate = {
enable = mkEnableOption "the logrotate systemd service"; enable = mkEnableOption "the logrotate systemd service" // {
default = foldr (n: a: a || n.enable) false (attrValues cfg.paths);
defaultText = literalExpression "cfg.paths != {}";
};
paths = mkOption { paths = mkOption {
type = with types; attrsOf (submodule pathOpts); type = with types; attrsOf (submodule pathOpts);
@ -163,28 +165,8 @@ in
} }
) cfg.paths; ) cfg.paths;
services.logrotate = {
paths = {
"/var/log/btmp" = {
frequency = mkDefault "monthly";
keep = mkDefault 1;
extraConfig = ''
create 0660 root ${groups.utmp.name}
'';
};
"/var/log/wtmp" = {
frequency = mkDefault "monthly";
keep = mkDefault 1;
extraConfig = ''
create 0664 root ${groups.utmp.name}
'';
};
};
};
systemd.services.logrotate = { systemd.services.logrotate = {
description = "Logrotate Service"; description = "Logrotate Service";
wantedBy = [ "multi-user.target" ];
startAt = "hourly"; startAt = "hourly";
serviceConfig = { serviceConfig = {

View file

@ -0,0 +1,773 @@
{ config, lib, options, pkgs, ... }:
with lib;
let
cfg = config.services.matrix-synapse;
format = pkgs.formats.yaml {};
# remove null values from the final configuration
finalSettings = lib.filterAttrsRecursive (_: v: v != null) cfg.settings;
configFile = format.generate "homeserver.yaml" finalSettings;
logConfigFile = format.generate "log_config.yaml" cfg.logConfig;
pluginsEnv = cfg.package.python.buildEnv.override {
extraLibs = cfg.plugins;
};
usePostgresql = cfg.settings.database.name == "psycopg2";
hasLocalPostgresDB = let args = cfg.settings.database.args; in
usePostgresql && (!(args ? host) || (elem args.host [ "localhost" "127.0.0.1" "::1" ]));
registerNewMatrixUser =
let
isIpv6 = x: lib.length (lib.splitString ":" x) > 1;
listener =
lib.findFirst (
listener: lib.any (
resource: lib.any (
name: name == "client"
) resource.names
) listener.resources
) (lib.last cfg.settings.listeners) cfg.settings.listeners;
# FIXME: Handle cases with missing client listener properly,
# don't rely on lib.last, this will not work.
# add a tail, so that without any bind_addresses we still have a useable address
bindAddress = head (listener.bind_addresses ++ [ "127.0.0.1" ]);
listenerProtocol = if listener.tls
then "https"
else "http";
in
pkgs.writeShellScriptBin "matrix-synapse-register_new_matrix_user" ''
exec ${cfg.package}/bin/register_new_matrix_user \
$@ \
${lib.concatMapStringsSep " " (x: "-c ${x}") ([ configFile ] ++ cfg.extraConfigFiles)} \
"${listenerProtocol}://${
if (isIpv6 bindAddress) then
"[${bindAddress}]"
else
"${bindAddress}"
}:${builtins.toString listener.port}/"
'';
in {
imports = [
(mkRemovedOptionModule [ "services" "matrix-synapse" "trusted_third_party_id_servers" ] ''
The `trusted_third_party_id_servers` option as been removed in `matrix-synapse` v1.4.0
as the behavior is now obsolete.
'')
(mkRemovedOptionModule [ "services" "matrix-synapse" "create_local_database" ] ''
Database configuration must be done manually. An exemplary setup is demonstrated in
<nixpkgs/nixos/tests/matrix-synapse.nix>
'')
(mkRemovedOptionModule [ "services" "matrix-synapse" "web_client" ] "")
(mkRemovedOptionModule [ "services" "matrix-synapse" "room_invite_state_types" ] ''
You may add additional event types via
`services.matrix-synapse.room_prejoin_state.additional_event_types` and
disable the default events via
`services.matrix-synapse.room_prejoin_state.disable_default_event_types`.
'')
# options that don't exist in synapse anymore
(mkRemovedOptionModule [ "services" "matrix-synapse" "bind_host" ] "Use listener settings instead." )
(mkRemovedOptionModule [ "services" "matrix-synapse" "bind_port" ] "Use listener settings instead." )
(mkRemovedOptionModule [ "services" "matrix-synapse" "expire_access_tokens" ] "" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "no_tls" ] "It is no longer supported by synapse." )
(mkRemovedOptionModule [ "services" "matrix-synapse" "tls_dh_param_path" ] "It was removed from synapse." )
(mkRemovedOptionModule [ "services" "matrix-synapse" "unsecure_port" ] "Use settings.listeners instead." )
(mkRemovedOptionModule [ "services" "matrix-synapse" "user_creation_max_duration" ] "It is no longer supported by synapse." )
(mkRemovedOptionModule [ "services" "matrix-synapse" "verbose" ] "Use a log config instead." )
# options that were moved into rfc42 style settigns
(mkRemovedOptionModule [ "services" "matrix-synapse" "app_service_config_files" ] "Use settings.app_service_config_Files instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "database_args" ] "Use settings.database.args instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "database_name" ] "Use settings.database.args.database instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "database_type" ] "Use settings.database.name instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "database_user" ] "Use settings.database.args.user instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "dynamic_thumbnails" ] "Use settings.dynamic_thumbnails instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "enable_metrics" ] "Use settings.enable_metrics instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "enable_registration" ] "Use settings.enable_registration instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "extraConfig" ] "Use settings instead." )
(mkRemovedOptionModule [ "services" "matrix-synapse" "listeners" ] "Use settings.listeners instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "logConfig" ] "Use settings.log_config instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "max_image_pixels" ] "Use settings.max_image_pixels instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "max_upload_size" ] "Use settings.max_upload_size instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "presence" "enabled" ] "Use settings.presence.enabled instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "public_baseurl" ] "Use settings.public_baseurl instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "report_stats" ] "Use settings.report_stats instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "server_name" ] "Use settings.server_name instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "servers" ] "Use settings.trusted_key_servers instead." )
(mkRemovedOptionModule [ "services" "matrix-synapse" "tls_certificate_path" ] "Use settings.tls_certificate_path instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "tls_private_key_path" ] "Use settings.tls_private_key_path instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "turn_shared_secret" ] "Use settings.turn_shared_secret instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "turn_uris" ] "Use settings.turn_uris instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "turn_user_lifetime" ] "Use settings.turn_user_lifetime instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "url_preview_enabled" ] "Use settings.url_preview_enabled instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "url_preview_ip_range_blacklist" ] "Use settings.url_preview_ip_range_blacklist instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "url_preview_ip_range_whitelist" ] "Use settings.url_preview_ip_range_whitelist instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "url_preview_url_blacklist" ] "Use settings.url_preview_url_blacklist instead" )
# options that are too specific to mention them explicitly in settings
(mkRemovedOptionModule [ "services" "matrix-synapse" "account_threepid_delegates" "email" ] "Use settings.account_threepid_delegates.email instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "account_threepid_delegates" "msisdn" ] "Use settings.account_threepid_delegates.msisdn instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "allow_guest_access" ] "Use settings.allow_guest_access instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "bcrypt_rounds" ] "Use settings.bcrypt_rounds instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "enable_registration_captcha" ] "Use settings.enable_registration_captcha instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "event_cache_size" ] "Use settings.event_cache_size instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "federation_rc_concurrent" ] "Use settings.rc_federation.concurrent instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "federation_rc_reject_limit" ] "Use settings.rc_federation.reject_limit instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "federation_rc_sleep_delay" ] "Use settings.rc_federation.sleep_delay instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "federation_rc_sleep_limit" ] "Use settings.rc_federation.sleep_limit instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "federation_rc_window_size" ] "Use settings.rc_federation.window_size instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "key_refresh_interval" ] "Use settings.key_refresh_interval instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "rc_messages_burst_count" ] "Use settings.rc_messages.burst_count instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "rc_messages_per_second" ] "Use settings.rc_messages.per_second instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "recaptcha_private_key" ] "Use settings.recaptcha_private_key instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "recaptcha_public_key" ] "Use settings.recaptcha_public_key instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "redaction_retention_period" ] "Use settings.redaction_retention_period instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "room_prejoin_state" "additional_event_types" ] "Use settings.room_prejoin_state.additional_event_types instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "room_prejoin_state" "disable_default_event_types" ] "Use settings.room_prejoin-state.disable_default_event_types instead" )
# Options that should be passed via extraConfigFiles, so they are not persisted into the nix store
(mkRemovedOptionModule [ "services" "matrix-synapse" "macaroon_secret_key" ] "Pass this value via extraConfigFiles instead" )
(mkRemovedOptionModule [ "services" "matrix-synapse" "registration_shared_secret" ] "Pass this value via extraConfigFiles instead" )
];
options = {
services.matrix-synapse = {
enable = mkEnableOption "matrix.org synapse";
configFile = mkOption {
type = types.str;
readOnly = true;
description = ''
Path to the configuration file on the target system. Useful to configure e.g. workers
that also need this.
'';
};
package = mkOption {
type = types.package;
default = pkgs.matrix-synapse;
defaultText = literalExpression "pkgs.matrix-synapse";
description = ''
Overridable attribute of the matrix synapse server package to use.
'';
};
plugins = mkOption {
type = types.listOf types.package;
default = [ ];
example = literalExpression ''
with config.services.matrix-synapse.package.plugins; [
matrix-synapse-ldap3
matrix-synapse-pam
];
'';
description = ''
List of additional Matrix plugins to make available.
'';
};
withJemalloc = mkOption {
type = types.bool;
default = false;
description = ''
Whether to preload jemalloc to reduce memory fragmentation and overall usage.
'';
};
dataDir = mkOption {
type = types.str;
default = "/var/lib/matrix-synapse";
description = ''
The directory where matrix-synapse stores its stateful data such as
certificates, media and uploads.
'';
};
settings = mkOption {
default = {};
description = ''
The primary synapse configuration. See the
<link xlink:href="https://github.com/matrix-org/synapse/blob/v${cfg.package.version}/docs/sample_config.yaml">sample configuration</link>
for possible values.
Secrets should be passed in by using the <literal>extraConfigFiles</literal> option.
'';
type = with types; submodule {
freeformType = format.type;
options = {
# This is a reduced set of popular options and defaults
# Do not add every available option here, they can be specified
# by the user at their own discretion. This is a freeform type!
server_name = mkOption {
type = types.str;
example = "example.com";
default = config.networking.hostName;
defaultText = literalExpression "config.networking.hostName";
description = ''
The domain name of the server, with optional explicit port.
This is used by remote servers to look up the server address.
This is also the last part of your UserID.
The server_name cannot be changed later so it is important to configure this correctly before you start Synapse.
'';
};
enable_registration = mkOption {
type = types.bool;
default = false;
description = ''
Enable registration for new users.
'';
};
registration_shared_secret = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
If set, allows registration by anyone who also has the shared
secret, even if registration is otherwise disabled.
Secrets should be passed in via <literal>extraConfigFiles</literal>!
'';
};
macaroon_secret_key = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Secret key for authentication tokens. If none is specified,
the registration_shared_secret is used, if one is given; otherwise,
a secret key is derived from the signing key.
Secrets should be passed in via <literal>extraConfigFiles</literal>!
'';
};
enable_metrics = mkOption {
type = types.bool;
default = false;
description = ''
Enable collection and rendering of performance metrics
'';
};
report_stats = mkOption {
type = types.bool;
default = false;
description = ''
Whether or not to report anonymized homeserver usage statistics.
'';
};
signing_key_path = mkOption {
type = types.path;
default = "${cfg.dataDir}/homeserver.signing.key";
description = ''
Path to the signing key to sign messages with.
'';
};
pid_file = mkOption {
type = types.path;
default = "/run/matrix-synapse.pid";
readOnly = true;
description = ''
The file to store the PID in.
'';
};
log_config = mkOption {
type = types.path;
default = ./matrix-synapse-log_config.yaml;
description = ''
The file that holds the logging configuration.
'';
};
media_store_path = mkOption {
type = types.path;
default = if lib.versionAtLeast config.system.stateVersion "22.05"
then "${cfg.dataDir}/media_store"
else "${cfg.dataDir}/media";
description = ''
Directory where uploaded images and attachments are stored.
'';
};
public_baseurl = mkOption {
type = types.nullOr types.str;
default = null;
example = "https://example.com:8448/";
description = ''
The public-facing base URL for the client API (not including _matrix/...)
'';
};
tls_certificate_path = mkOption {
type = types.nullOr types.str;
default = null;
example = "/var/lib/acme/example.com/fullchain.pem";
description = ''
PEM encoded X509 certificate for TLS.
You can replace the self-signed certificate that synapse
autogenerates on launch with your own SSL certificate + key pair
if you like. Any required intermediary certificates can be
appended after the primary certificate in hierarchical order.
'';
};
tls_private_key_path = mkOption {
type = types.nullOr types.str;
default = null;
example = "/var/lib/acme/example.com/key.pem";
description = ''
PEM encoded private key for TLS. Specify null if synapse is not
speaking TLS directly.
'';
};
presence.enabled = mkOption {
type = types.bool;
default = true;
example = false;
description = ''
Whether to enable presence tracking.
Presence tracking allows users to see the state (e.g online/offline)
of other local and remote users.
'';
};
listeners = mkOption {
type = types.listOf (types.submodule {
options = {
port = mkOption {
type = types.port;
example = 8448;
description = ''
The port to listen for HTTP(S) requests on.
'';
};
bind_addresses = mkOption {
type = types.listOf types.str;
default = [
"::1"
"127.0.0.1"
];
example = literalExpression ''
[
"::"
"0.0.0.0"
]
'';
description = ''
IP addresses to bind the listener to.
'';
};
type = mkOption {
type = types.enum [
"http"
"manhole"
"metrics"
"replication"
];
default = "http";
example = "metrics";
description = ''
The type of the listener, usually http.
'';
};
tls = mkOption {
type = types.bool;
default = true;
example = false;
description = ''
Whether to enable TLS on the listener socket.
'';
};
x_forwarded = mkOption {
type = types.bool;
default = false;
example = true;
description = ''
Use the X-Forwarded-For (XFF) header as the client IP and not the
actual client IP.
'';
};
resources = mkOption {
type = types.listOf (types.submodule {
options = {
names = mkOption {
type = types.listOf (types.enum [
"client"
"consent"
"federation"
"keys"
"media"
"metrics"
"openid"
"replication"
"static"
]);
description = ''
List of resources to host on this listener.
'';
example = [
"client"
];
};
compress = mkOption {
type = types.bool;
description = ''
Should synapse compress HTTP responses to clients that support it?
This should be disabled if running synapse behind a load balancer
that can do automatic compression.
'';
};
};
});
description = ''
List of HTTP resources to serve on this listener.
'';
};
};
});
default = [ {
port = 8008;
bind_addresses = [ "127.0.0.1" ];
type = "http";
tls = false;
x_forwarded = true;
resources = [ {
names = [ "client" ];
compress = true;
} {
names = [ "federation" ];
compress = false;
} ];
} ];
description = ''
List of ports that Synapse should listen on, their purpose and their configuration.
'';
};
database.name = mkOption {
type = types.enum [
"sqlite3"
"psycopg2"
];
default = if versionAtLeast config.system.stateVersion "18.03"
then "psycopg2"
else "sqlite3";
defaultText = literalExpression ''
if versionAtLeast config.system.stateVersion "18.03"
then "psycopg2"
else "sqlite3"
'';
description = ''
The database engine name. Can be sqlite3 or psycopg2.
'';
};
database.args.database = mkOption {
type = types.str;
default = {
sqlite3 = "${cfg.dataDir}/homeserver.db";
psycopg2 = "matrix-synapse";
}.${cfg.settings.database.name};
defaultText = literalExpression ''
{
sqlite3 = "''${${options.services.matrix-synapse.dataDir}}/homeserver.db";
psycopg2 = "matrix-synapse";
}.''${${options.services.matrix-synapse.settings}.database.name};
'';
description = ''
Name of the database when using the psycopg2 backend,
path to the database location when using sqlite3.
'';
};
database.args.user = mkOption {
type = types.nullOr types.str;
default = {
sqlite3 = null;
psycopg2 = "matrix-synapse";
}.${cfg.settings.database.name};
description = ''
Username to connect with psycopg2, set to null
when using sqlite3.
'';
};
url_preview_enabled = mkOption {
type = types.bool;
default = true;
example = false;
description = ''
Is the preview URL API enabled? If enabled, you *must* specify an
explicit url_preview_ip_range_blacklist of IPs that the spider is
denied from accessing.
'';
};
url_preview_ip_range_blacklist = mkOption {
type = types.listOf types.str;
default = [
"10.0.0.0/8"
"100.64.0.0/10"
"127.0.0.0/8"
"169.254.0.0/16"
"172.16.0.0/12"
"192.0.0.0/24"
"192.0.2.0/24"
"192.168.0.0/16"
"192.88.99.0/24"
"198.18.0.0/15"
"198.51.100.0/24"
"2001:db8::/32"
"203.0.113.0/24"
"224.0.0.0/4"
"::1/128"
"fc00::/7"
"fe80::/10"
"fec0::/10"
"ff00::/8"
];
description = ''
List of IP address CIDR ranges that the URL preview spider is denied
from accessing.
'';
};
url_preview_ip_range_whitelist = mkOption {
type = types.listOf types.str;
default = [];
description = ''
List of IP address CIDR ranges that the URL preview spider is allowed
to access even if they are specified in url_preview_ip_range_blacklist.
'';
};
url_preview_url_blacklist = mkOption {
type = types.listOf types.str;
default = [];
description = ''
Optional list of URL matches that the URL preview spider is
denied from accessing.
'';
};
max_upload_size = mkOption {
type = types.str;
default = "50M";
example = "100M";
description = ''
The largest allowed upload size in bytes
'';
};
max_image_pixels = mkOption {
type = types.str;
default = "32M";
example = "64M";
description = ''
Maximum number of pixels that will be thumbnailed
'';
};
dynamic_thumbnails = mkOption {
type = types.bool;
default = false;
example = true;
description = ''
Whether to generate new thumbnails on the fly to precisely match
the resolution requested by the client. If true then whenever
a new resolution is requested by the client the server will
generate a new thumbnail. If false the server will pick a thumbnail
from a precalculated list.
'';
};
turn_uris = mkOption {
type = types.listOf types.str;
default = [];
example = [
"turn:turn.example.com:3487?transport=udp"
"turn:turn.example.com:3487?transport=tcp"
"turns:turn.example.com:5349?transport=udp"
"turns:turn.example.com:5349?transport=tcp"
];
description = ''
The public URIs of the TURN server to give to clients
'';
};
turn_shared_secret = mkOption {
type = types.str;
default = "";
example = literalExpression ''
config.services.coturn.static-auth-secret
'';
description = ''
The shared secret used to compute passwords for the TURN server.
Secrets should be passed in via <literal>extraConfigFiles</literal>!
'';
};
trusted_key_servers = mkOption {
type = types.listOf (types.submodule {
options = {
server_name = mkOption {
type = types.str;
example = "matrix.org";
description = ''
Hostname of the trusted server.
'';
};
verify_keys = mkOption {
type = types.nullOr (types.attrsOf types.str);
default = null;
example = literalExpression ''
{
"ed25519:auto" = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw";
}
'';
description = ''
Attribute set from key id to base64 encoded public key.
If specified synapse will check that the response is signed
by at least one of the given keys.
'';
};
};
});
default = [ {
server_name = "matrix.org";
verify_keys = {
"ed25519:auto" = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw";
};
} ];
description = ''
The trusted servers to download signing keys from.
'';
};
app_service_config_files = mkOption {
type = types.listOf types.path;
default = [ ];
description = ''
A list of application service config file to use
'';
};
};
};
};
extraConfigFiles = mkOption {
type = types.listOf types.path;
default = [];
description = ''
Extra config files to include.
The configuration files will be included based on the command line
argument --config-path. This allows to configure secrets without
having to go through the Nix store, e.g. based on deployment keys if
NixOps is in use.
'';
};
};
};
config = mkIf cfg.enable {
assertions = [
{ assertion = hasLocalPostgresDB -> config.services.postgresql.enable;
message = ''
Cannot deploy matrix-synapse with a configuration for a local postgresql database
and a missing postgresql service. Since 20.03 it's mandatory to manually configure the
database (please read the thread in https://github.com/NixOS/nixpkgs/pull/80447 for
further reference).
If you
- try to deploy a fresh synapse, you need to configure the database yourself. An example
for this can be found in <nixpkgs/nixos/tests/matrix-synapse.nix>
- update your existing matrix-synapse instance, you simply need to add `services.postgresql.enable = true`
to your configuration.
For further information about this update, please read the release-notes of 20.03 carefully.
'';
}
];
services.matrix-synapse.configFile = configFile;
users.users.matrix-synapse = {
group = "matrix-synapse";
home = cfg.dataDir;
createHome = true;
shell = "${pkgs.bash}/bin/bash";
uid = config.ids.uids.matrix-synapse;
};
users.groups.matrix-synapse = {
gid = config.ids.gids.matrix-synapse;
};
systemd.services.matrix-synapse = {
description = "Synapse Matrix homeserver";
after = [ "network.target" ] ++ optional hasLocalPostgresDB "postgresql.service";
wantedBy = [ "multi-user.target" ];
preStart = ''
${cfg.package}/bin/synapse_homeserver \
--config-path ${configFile} \
--keys-directory ${cfg.dataDir} \
--generate-keys
'';
environment = {
PYTHONPATH = makeSearchPathOutput "lib" cfg.package.python.sitePackages [ pluginsEnv ];
} // optionalAttrs (cfg.withJemalloc) {
LD_PRELOAD = "${pkgs.jemalloc}/lib/libjemalloc.so";
};
serviceConfig = {
Type = "notify";
User = "matrix-synapse";
Group = "matrix-synapse";
WorkingDirectory = cfg.dataDir;
ExecStartPre = [ ("+" + (pkgs.writeShellScript "matrix-synapse-fix-permissions" ''
chown matrix-synapse:matrix-synapse ${cfg.dataDir}/homeserver.signing.key
chmod 0600 ${cfg.dataDir}/homeserver.signing.key
'')) ];
ExecStart = ''
${cfg.package}/bin/synapse_homeserver \
${ concatMapStringsSep "\n " (x: "--config-path ${x} \\") ([ configFile ] ++ cfg.extraConfigFiles) }
--keys-directory ${cfg.dataDir}
'';
ExecReload = "${pkgs.util-linux}/bin/kill -HUP $MAINPID";
Restart = "on-failure";
UMask = "0077";
};
};
environment.systemPackages = [ registerNewMatrixUser ];
};
meta = {
buildDocsInSandbox = false;
doc = ./matrix-synapse.xml;
maintainers = teams.matrix.members;
};
}

View file

@ -115,20 +115,21 @@ in {
}; };
services.matrix-synapse = { services.matrix-synapse = {
<link linkend="opt-services.matrix-synapse.enable">enable</link> = true; <link linkend="opt-services.matrix-synapse.enable">enable</link> = true;
<link linkend="opt-services.matrix-synapse.server_name">server_name</link> = config.networking.domain; <link linkend="opt-services.matrix-synapse.settings.server_name">server_name</link> = config.networking.domain;
<link linkend="opt-services.matrix-synapse.listeners">listeners</link> = [ <link linkend="opt-services.matrix-synapse.settings.listeners">listeners</link> = [
{ {
<link linkend="opt-services.matrix-synapse.listeners._.port">port</link> = 8008; <link linkend="opt-services.matrix-synapse.settings.listeners._.port">port</link> = 8008;
<link linkend="opt-services.matrix-synapse.listeners._.bind_address">bind_address</link> = "::1"; <link linkend="opt-services.matrix-synapse.settings.listeners._.bind_addresses">bind_address</link> = [ "::1" ];
<link linkend="opt-services.matrix-synapse.listeners._.type">type</link> = "http"; <link linkend="opt-services.matrix-synapse.settings.listeners._.type">type</link> = "http";
<link linkend="opt-services.matrix-synapse.listeners._.tls">tls</link> = false; <link linkend="opt-services.matrix-synapse.settings.listeners._.tls">tls</link> = false;
<link linkend="opt-services.matrix-synapse.listeners._.x_forwarded">x_forwarded</link> = true; <link linkend="opt-services.matrix-synapse.settings.listeners._.x_forwarded">x_forwarded</link> = true;
<link linkend="opt-services.matrix-synapse.listeners._.resources">resources</link> = [ <link linkend="opt-services.matrix-synapse.settings.listeners._.resources">resources</link> = [ {
{ <link linkend="opt-services.matrix-synapse.settings.listeners._.resources._.names">names</link> = [ "client" ];
<link linkend="opt-services.matrix-synapse.listeners._.resources._.names">names</link> = [ "client" "federation" ]; <link linkend="opt-services.matrix-synapse.settings.listeners._.resources._.compress">compress</link> = true;
<link linkend="opt-services.matrix-synapse.listeners._.resources._.compress">compress</link> = false; } {
} <link linkend="opt-services.matrix-synapse.settings.listeners._.resources._.names">names</link> = [ "federation" ];
]; <link linkend="opt-services.matrix-synapse.settings.listeners._.resources._.compress">compress</link> = false;
} ];
} }
]; ];
}; };
@ -151,11 +152,11 @@ in {
<para> <para>
If you want to run a server with public registration by anybody, you can If you want to run a server with public registration by anybody, you can
then enable <literal><link linkend="opt-services.matrix-synapse.enable_registration">services.matrix-synapse.enable_registration</link> = then enable <literal><link linkend="opt-services.matrix-synapse.settings.enable_registration">services.matrix-synapse.enable_registration</link> =
true;</literal>. Otherwise, or you can generate a registration secret with true;</literal>. Otherwise, or you can generate a registration secret with
<command>pwgen -s 64 1</command> and set it with <command>pwgen -s 64 1</command> and set it with
<option><link linkend="opt-services.matrix-synapse.registration_shared_secret">services.matrix-synapse.registration_shared_secret</link></option>. To <option><link linkend="opt-services.matrix-synapse.settings.registration_shared_secret">services.matrix-synapse.registration_shared_secret</link></option>.
create a new user or admin, run the following after you have set the secret To create a new user or admin, run the following after you have set the secret
and have rebuilt NixOS: and have rebuilt NixOS:
<screen> <screen>
<prompt>$ </prompt>nix run nixpkgs.matrix-synapse <prompt>$ </prompt>nix run nixpkgs.matrix-synapse
@ -170,7 +171,7 @@ Success!
<literal>@your-username:example.org</literal>. Note that the registration <literal>@your-username:example.org</literal>. Note that the registration
secret ends up in the nix store and therefore is world-readable by any user secret ends up in the nix store and therefore is world-readable by any user
on your machine, so it makes sense to only temporarily activate the on your machine, so it makes sense to only temporarily activate the
<link linkend="opt-services.matrix-synapse.registration_shared_secret">registration_shared_secret</link> <link linkend="opt-services.matrix-synapse.settings.registration_shared_secret">registration_shared_secret</link>
option until a better solution for NixOS is in place. option until a better solution for NixOS is in place.
</para> </para>
</section> </section>

View file

@ -1,844 +0,0 @@
{ config, lib, options, pkgs, ... }:
with lib;
let
cfg = config.services.matrix-synapse;
opt = options.services.matrix-synapse;
pg = config.services.postgresql;
usePostgresql = cfg.database_type == "psycopg2";
logConfigFile = pkgs.writeText "log_config.yaml" cfg.logConfig;
mkResource = r: ''{names: ${builtins.toJSON r.names}, compress: ${boolToString r.compress}}'';
mkListener = l: ''{port: ${toString l.port}, bind_address: "${l.bind_address}", type: ${l.type}, tls: ${boolToString l.tls}, x_forwarded: ${boolToString l.x_forwarded}, resources: [${concatStringsSep "," (map mkResource l.resources)}]}'';
pluginsEnv = cfg.package.python.buildEnv.override {
extraLibs = cfg.plugins;
};
configFile = pkgs.writeText "homeserver.yaml" ''
${optionalString (cfg.tls_certificate_path != null) ''
tls_certificate_path: "${cfg.tls_certificate_path}"
''}
${optionalString (cfg.tls_private_key_path != null) ''
tls_private_key_path: "${cfg.tls_private_key_path}"
''}
${optionalString (cfg.tls_dh_params_path != null) ''
tls_dh_params_path: "${cfg.tls_dh_params_path}"
''}
no_tls: ${boolToString cfg.no_tls}
${optionalString (cfg.bind_port != null) ''
bind_port: ${toString cfg.bind_port}
''}
${optionalString (cfg.unsecure_port != null) ''
unsecure_port: ${toString cfg.unsecure_port}
''}
${optionalString (cfg.bind_host != null) ''
bind_host: "${cfg.bind_host}"
''}
server_name: "${cfg.server_name}"
pid_file: "/run/matrix-synapse.pid"
${optionalString (cfg.public_baseurl != null) ''
public_baseurl: "${cfg.public_baseurl}"
''}
listeners: [${concatStringsSep "," (map mkListener cfg.listeners)}]
database: {
name: "${cfg.database_type}",
args: {
${concatStringsSep ",\n " (
mapAttrsToList (n: v: "\"${n}\": ${builtins.toJSON v}") cfg.database_args
)}
}
}
event_cache_size: "${cfg.event_cache_size}"
verbose: ${cfg.verbose}
log_config: "${logConfigFile}"
rc_messages_per_second: ${cfg.rc_messages_per_second}
rc_message_burst_count: ${cfg.rc_message_burst_count}
federation_rc_window_size: ${cfg.federation_rc_window_size}
federation_rc_sleep_limit: ${cfg.federation_rc_sleep_limit}
federation_rc_sleep_delay: ${cfg.federation_rc_sleep_delay}
federation_rc_reject_limit: ${cfg.federation_rc_reject_limit}
federation_rc_concurrent: ${cfg.federation_rc_concurrent}
media_store_path: "${cfg.dataDir}/media"
uploads_path: "${cfg.dataDir}/uploads"
max_upload_size: "${cfg.max_upload_size}"
max_image_pixels: "${cfg.max_image_pixels}"
dynamic_thumbnails: ${boolToString cfg.dynamic_thumbnails}
url_preview_enabled: ${boolToString cfg.url_preview_enabled}
${optionalString (cfg.url_preview_enabled == true) ''
url_preview_ip_range_blacklist: ${builtins.toJSON cfg.url_preview_ip_range_blacklist}
url_preview_ip_range_whitelist: ${builtins.toJSON cfg.url_preview_ip_range_whitelist}
url_preview_url_blacklist: ${builtins.toJSON cfg.url_preview_url_blacklist}
''}
recaptcha_private_key: "${cfg.recaptcha_private_key}"
recaptcha_public_key: "${cfg.recaptcha_public_key}"
enable_registration_captcha: ${boolToString cfg.enable_registration_captcha}
turn_uris: ${builtins.toJSON cfg.turn_uris}
turn_shared_secret: "${cfg.turn_shared_secret}"
enable_registration: ${boolToString cfg.enable_registration}
${optionalString (cfg.registration_shared_secret != null) ''
registration_shared_secret: "${cfg.registration_shared_secret}"
''}
recaptcha_siteverify_api: "https://www.google.com/recaptcha/api/siteverify"
turn_user_lifetime: "${cfg.turn_user_lifetime}"
user_creation_max_duration: ${cfg.user_creation_max_duration}
bcrypt_rounds: ${cfg.bcrypt_rounds}
allow_guest_access: ${boolToString cfg.allow_guest_access}
account_threepid_delegates:
${optionalString (cfg.account_threepid_delegates.email != null) "email: ${cfg.account_threepid_delegates.email}"}
${optionalString (cfg.account_threepid_delegates.msisdn != null) "msisdn: ${cfg.account_threepid_delegates.msisdn}"}
room_prejoin_state:
disable_default_event_types: ${boolToString cfg.room_prejoin_state.disable_default_event_types}
additional_event_types: ${builtins.toJSON cfg.room_prejoin_state.additional_event_types}
${optionalString (cfg.macaroon_secret_key != null) ''
macaroon_secret_key: "${cfg.macaroon_secret_key}"
''}
expire_access_token: ${boolToString cfg.expire_access_token}
enable_metrics: ${boolToString cfg.enable_metrics}
report_stats: ${boolToString cfg.report_stats}
signing_key_path: "${cfg.dataDir}/homeserver.signing.key"
key_refresh_interval: "${cfg.key_refresh_interval}"
perspectives:
servers: {
${concatStringsSep "},\n" (mapAttrsToList (n: v: ''
"${n}": {
"verify_keys": {
${concatStringsSep "},\n" (mapAttrsToList (n: v: ''
"${n}": {
"key": "${v}"
}'') v)}
}
'') cfg.servers)}
}
}
redaction_retention_period: ${toString cfg.redaction_retention_period}
app_service_config_files: ${builtins.toJSON cfg.app_service_config_files}
${cfg.extraConfig}
'';
hasLocalPostgresDB = let args = cfg.database_args; in
usePostgresql && (!(args ? host) || (elem args.host [ "localhost" "127.0.0.1" "::1" ]));
registerNewMatrixUser =
let
isIpv6 = x: lib.length (lib.splitString ":" x) > 1;
listener =
lib.findFirst (
listener: lib.any (
resource: lib.any (
name: name == "client"
) resource.names
) listener.resources
) (lib.last cfg.listeners) cfg.listeners;
in
pkgs.writeShellScriptBin "matrix-synapse-register_new_matrix_user" ''
exec ${cfg.package}/bin/register_new_matrix_user \
$@ \
${lib.concatMapStringsSep " " (x: "-c ${x}") ([ configFile ] ++ cfg.extraConfigFiles)} \
"${listener.type}://${
if (isIpv6 listener.bind_address) then
"[${listener.bind_address}]"
else
"${listener.bind_address}"
}:${builtins.toString listener.port}/"
'';
in {
options = {
services.matrix-synapse = {
enable = mkEnableOption "matrix.org synapse";
configFile = mkOption {
type = types.str;
readOnly = true;
description = ''
Path to the configuration file on the target system. Useful to configure e.g. workers
that also need this.
'';
};
package = mkOption {
type = types.package;
default = pkgs.matrix-synapse;
defaultText = literalExpression "pkgs.matrix-synapse";
description = ''
Overridable attribute of the matrix synapse server package to use.
'';
};
plugins = mkOption {
type = types.listOf types.package;
default = [ ];
example = literalExpression ''
with config.services.matrix-synapse.package.plugins; [
matrix-synapse-ldap3
matrix-synapse-pam
];
'';
description = ''
List of additional Matrix plugins to make available.
'';
};
withJemalloc = mkOption {
type = types.bool;
default = false;
description = ''
Whether to preload jemalloc to reduce memory fragmentation and overall usage.
'';
};
no_tls = mkOption {
type = types.bool;
default = false;
description = ''
Don't bind to the https port
'';
};
bind_port = mkOption {
type = types.nullOr types.int;
default = null;
example = 8448;
description = ''
DEPRECATED: Use listeners instead.
The port to listen for HTTPS requests on.
For when matrix traffic is sent directly to synapse.
'';
};
unsecure_port = mkOption {
type = types.nullOr types.int;
default = null;
example = 8008;
description = ''
DEPRECATED: Use listeners instead.
The port to listen for HTTP requests on.
For when matrix traffic passes through loadbalancer that unwraps TLS.
'';
};
bind_host = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
DEPRECATED: Use listeners instead.
Local interface to listen on.
The empty string will cause synapse to listen on all interfaces.
'';
};
tls_certificate_path = mkOption {
type = types.nullOr types.str;
default = null;
example = "/var/lib/matrix-synapse/homeserver.tls.crt";
description = ''
PEM encoded X509 certificate for TLS.
You can replace the self-signed certificate that synapse
autogenerates on launch with your own SSL certificate + key pair
if you like. Any required intermediary certificates can be
appended after the primary certificate in hierarchical order.
'';
};
tls_private_key_path = mkOption {
type = types.nullOr types.str;
default = null;
example = "/var/lib/matrix-synapse/homeserver.tls.key";
description = ''
PEM encoded private key for TLS. Specify null if synapse is not
speaking TLS directly.
'';
};
tls_dh_params_path = mkOption {
type = types.nullOr types.str;
default = null;
example = "/var/lib/matrix-synapse/homeserver.tls.dh";
description = ''
PEM dh parameters for ephemeral keys
'';
};
server_name = mkOption {
type = types.str;
example = "example.com";
default = config.networking.hostName;
defaultText = literalExpression "config.networking.hostName";
description = ''
The domain name of the server, with optional explicit port.
This is used by remote servers to look up the server address.
This is also the last part of your UserID.
The server_name cannot be changed later so it is important to configure this correctly before you start Synapse.
'';
};
public_baseurl = mkOption {
type = types.nullOr types.str;
default = null;
example = "https://example.com:8448/";
description = ''
The public-facing base URL for the client API (not including _matrix/...)
'';
};
listeners = mkOption {
type = types.listOf (types.submodule {
options = {
port = mkOption {
type = types.port;
example = 8448;
description = ''
The port to listen for HTTP(S) requests on.
'';
};
bind_address = mkOption {
type = types.str;
default = "";
example = "203.0.113.42";
description = ''
Local interface to listen on.
The empty string will cause synapse to listen on all interfaces.
'';
};
type = mkOption {
type = types.str;
default = "http";
description = ''
Type of listener.
'';
};
tls = mkOption {
type = types.bool;
default = true;
description = ''
Whether to listen for HTTPS connections rather than HTTP.
'';
};
x_forwarded = mkOption {
type = types.bool;
default = false;
description = ''
Use the X-Forwarded-For (XFF) header as the client IP and not the
actual client IP.
'';
};
resources = mkOption {
type = types.listOf (types.submodule {
options = {
names = mkOption {
type = types.listOf types.str;
description = ''
List of resources to host on this listener.
'';
example = ["client" "federation"];
};
compress = mkOption {
type = types.bool;
description = ''
Should synapse compress HTTP responses to clients that support it?
This should be disabled if running synapse behind a load balancer
that can do automatic compression.
'';
};
};
});
description = ''
List of HTTP resources to serve on this listener.
'';
};
};
});
default = [{
port = 8448;
bind_address = "";
type = "http";
tls = true;
x_forwarded = false;
resources = [
{ names = ["client"]; compress = true; }
{ names = ["federation"]; compress = false; }
];
}];
description = ''
List of ports that Synapse should listen on, their purpose and their configuration.
'';
};
verbose = mkOption {
type = types.str;
default = "0";
description = "Logging verbosity level.";
};
rc_messages_per_second = mkOption {
type = types.str;
default = "0.2";
description = "Number of messages a client can send per second";
};
rc_message_burst_count = mkOption {
type = types.str;
default = "10.0";
description = "Number of message a client can send before being throttled";
};
federation_rc_window_size = mkOption {
type = types.str;
default = "1000";
description = "The federation window size in milliseconds";
};
federation_rc_sleep_limit = mkOption {
type = types.str;
default = "10";
description = ''
The number of federation requests from a single server in a window
before the server will delay processing the request.
'';
};
federation_rc_sleep_delay = mkOption {
type = types.str;
default = "500";
description = ''
The duration in milliseconds to delay processing events from
remote servers by if they go over the sleep limit.
'';
};
federation_rc_reject_limit = mkOption {
type = types.str;
default = "50";
description = ''
The maximum number of concurrent federation requests allowed
from a single server
'';
};
federation_rc_concurrent = mkOption {
type = types.str;
default = "3";
description = "The number of federation requests to concurrently process from a single server";
};
database_type = mkOption {
type = types.enum [ "sqlite3" "psycopg2" ];
default = if versionAtLeast config.system.stateVersion "18.03"
then "psycopg2"
else "sqlite3";
defaultText = literalExpression ''
if versionAtLeast config.system.stateVersion "18.03"
then "psycopg2"
else "sqlite3"
'';
description = ''
The database engine name. Can be sqlite or psycopg2.
'';
};
database_name = mkOption {
type = types.str;
default = "matrix-synapse";
description = "Database name.";
};
database_user = mkOption {
type = types.str;
default = "matrix-synapse";
description = "Database user name.";
};
database_args = mkOption {
type = types.attrs;
default = {
sqlite3 = { database = "${cfg.dataDir}/homeserver.db"; };
psycopg2 = {
user = cfg.database_user;
database = cfg.database_name;
};
}.${cfg.database_type};
defaultText = literalDocBook ''
<variablelist>
<varlistentry>
<term>using sqlite3</term>
<listitem>
<programlisting>
{ database = "''${config.${opt.dataDir}}/homeserver.db"; }
</programlisting>
</listitem>
</varlistentry>
<varlistentry>
<term>using psycopg2</term>
<listitem>
<programlisting>
psycopg2 = {
user = config.${opt.database_user};
database = config.${opt.database_name};
}
</programlisting>
</listitem>
</varlistentry>
</variablelist>
'';
description = ''
Arguments to pass to the engine.
'';
};
event_cache_size = mkOption {
type = types.str;
default = "10K";
description = "Number of events to cache in memory.";
};
url_preview_enabled = mkOption {
type = types.bool;
default = false;
description = ''
Is the preview URL API enabled? If enabled, you *must* specify an
explicit url_preview_ip_range_blacklist of IPs that the spider is
denied from accessing.
'';
};
url_preview_ip_range_blacklist = mkOption {
type = types.listOf types.str;
default = [
"127.0.0.0/8"
"10.0.0.0/8"
"172.16.0.0/12"
"192.168.0.0/16"
"100.64.0.0/10"
"169.254.0.0/16"
"::1/128"
"fe80::/64"
"fc00::/7"
];
description = ''
List of IP address CIDR ranges that the URL preview spider is denied
from accessing.
'';
};
url_preview_ip_range_whitelist = mkOption {
type = types.listOf types.str;
default = [];
description = ''
List of IP address CIDR ranges that the URL preview spider is allowed
to access even if they are specified in
url_preview_ip_range_blacklist.
'';
};
url_preview_url_blacklist = mkOption {
type = types.listOf types.str;
default = [];
description = ''
Optional list of URL matches that the URL preview spider is
denied from accessing.
'';
};
recaptcha_private_key = mkOption {
type = types.str;
default = "";
description = ''
This Home Server's ReCAPTCHA private key.
'';
};
recaptcha_public_key = mkOption {
type = types.str;
default = "";
description = ''
This Home Server's ReCAPTCHA public key.
'';
};
enable_registration_captcha = mkOption {
type = types.bool;
default = false;
description = ''
Enables ReCaptcha checks when registering, preventing signup
unless a captcha is answered. Requires a valid ReCaptcha
public/private key.
'';
};
turn_uris = mkOption {
type = types.listOf types.str;
default = [];
description = ''
The public URIs of the TURN server to give to clients
'';
};
turn_shared_secret = mkOption {
type = types.str;
default = "";
description = ''
The shared secret used to compute passwords for the TURN server
'';
};
turn_user_lifetime = mkOption {
type = types.str;
default = "1h";
description = "How long generated TURN credentials last";
};
enable_registration = mkOption {
type = types.bool;
default = false;
description = ''
Enable registration for new users.
'';
};
registration_shared_secret = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
If set, allows registration by anyone who also has the shared
secret, even if registration is otherwise disabled.
'';
};
enable_metrics = mkOption {
type = types.bool;
default = false;
description = ''
Enable collection and rendering of performance metrics
'';
};
report_stats = mkOption {
type = types.bool;
default = false;
description = "";
};
servers = mkOption {
type = types.attrsOf (types.attrsOf types.str);
default = {
"matrix.org" = {
"ed25519:auto" = "Noi6WqcDj0QmPxCNQqgezwTlBKrfqehY1u2FyWP9uYw";
};
};
description = ''
The trusted servers to download signing keys from.
'';
};
max_upload_size = mkOption {
type = types.str;
default = "10M";
description = "The largest allowed upload size in bytes";
};
max_image_pixels = mkOption {
type = types.str;
default = "32M";
description = "Maximum number of pixels that will be thumbnailed";
};
dynamic_thumbnails = mkOption {
type = types.bool;
default = false;
description = ''
Whether to generate new thumbnails on the fly to precisely match
the resolution requested by the client. If true then whenever
a new resolution is requested by the client the server will
generate a new thumbnail. If false the server will pick a thumbnail
from a precalculated list.
'';
};
user_creation_max_duration = mkOption {
type = types.str;
default = "1209600000";
description = ''
Sets the expiry for the short term user creation in
milliseconds. The default value is two weeks.
'';
};
bcrypt_rounds = mkOption {
type = types.str;
default = "12";
description = ''
Set the number of bcrypt rounds used to generate password hash.
Larger numbers increase the work factor needed to generate the hash.
'';
};
allow_guest_access = mkOption {
type = types.bool;
default = false;
description = ''
Allows users to register as guests without a password/email/etc, and
participate in rooms hosted on this server which have been made
accessible to anonymous users.
'';
};
account_threepid_delegates.email = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Delegate email sending to https://example.org
'';
};
account_threepid_delegates.msisdn = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Delegate SMS sending to this local process (https://localhost:8090)
'';
};
room_prejoin_state.additional_event_types = mkOption {
default = [];
type = types.listOf types.str;
description = ''
Additional events to share with users who received an invite.
'';
};
room_prejoin_state.disable_default_event_types = mkOption {
default = false;
type = types.bool;
description = ''
Whether to disable the default state-event types for users invited to a room.
These are:
<itemizedlist>
<listitem><para>m.room.join_rules</para></listitem>
<listitem><para>m.room.canonical_alias</para></listitem>
<listitem><para>m.room.avatar</para></listitem>
<listitem><para>m.room.encryption</para></listitem>
<listitem><para>m.room.name</para></listitem>
<listitem><para>m.room.create</para></listitem>
</itemizedlist>
'';
};
macaroon_secret_key = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Secret key for authentication tokens
'';
};
expire_access_token = mkOption {
type = types.bool;
default = false;
description = ''
Whether to enable access token expiration.
'';
};
key_refresh_interval = mkOption {
type = types.str;
default = "1d";
description = ''
How long key response published by this server is valid for.
Used to set the valid_until_ts in /key/v2 APIs.
Determines how quickly servers will query to check which keys
are still valid.
'';
};
app_service_config_files = mkOption {
type = types.listOf types.path;
default = [ ];
description = ''
A list of application service config file to use
'';
};
redaction_retention_period = mkOption {
type = types.int;
default = 7;
description = ''
How long to keep redacted events in unredacted form in the database.
'';
};
extraConfig = mkOption {
type = types.lines;
default = "";
description = ''
Extra config options for matrix-synapse.
'';
};
extraConfigFiles = mkOption {
type = types.listOf types.path;
default = [];
description = ''
Extra config files to include.
The configuration files will be included based on the command line
argument --config-path. This allows to configure secrets without
having to go through the Nix store, e.g. based on deployment keys if
NixOPS is in use.
'';
};
logConfig = mkOption {
type = types.lines;
default = readFile ./matrix-synapse-log_config.yaml;
description = ''
A yaml python logging config file
'';
};
dataDir = mkOption {
type = types.str;
default = "/var/lib/matrix-synapse";
description = ''
The directory where matrix-synapse stores its stateful data such as
certificates, media and uploads.
'';
};
};
};
config = mkIf cfg.enable {
assertions = [
{ assertion = hasLocalPostgresDB -> config.services.postgresql.enable;
message = ''
Cannot deploy matrix-synapse with a configuration for a local postgresql database
and a missing postgresql service. Since 20.03 it's mandatory to manually configure the
database (please read the thread in https://github.com/NixOS/nixpkgs/pull/80447 for
further reference).
If you
- try to deploy a fresh synapse, you need to configure the database yourself. An example
for this can be found in <nixpkgs/nixos/tests/matrix-synapse.nix>
- update your existing matrix-synapse instance, you simply need to add `services.postgresql.enable = true`
to your configuration.
For further information about this update, please read the release-notes of 20.03 carefully.
'';
}
];
services.matrix-synapse.configFile = "${configFile}";
users.users.matrix-synapse = {
group = "matrix-synapse";
home = cfg.dataDir;
createHome = true;
shell = "${pkgs.bash}/bin/bash";
uid = config.ids.uids.matrix-synapse;
};
users.groups.matrix-synapse = {
gid = config.ids.gids.matrix-synapse;
};
systemd.services.matrix-synapse = {
description = "Synapse Matrix homeserver";
after = [ "network.target" ] ++ optional hasLocalPostgresDB "postgresql.service";
wantedBy = [ "multi-user.target" ];
preStart = ''
${cfg.package}/bin/synapse_homeserver \
--config-path ${configFile} \
--keys-directory ${cfg.dataDir} \
--generate-keys
'';
environment = {
PYTHONPATH = makeSearchPathOutput "lib" cfg.package.python.sitePackages [ pluginsEnv ];
} // optionalAttrs (cfg.withJemalloc) {
LD_PRELOAD = "${pkgs.jemalloc}/lib/libjemalloc.so";
};
serviceConfig = {
Type = "notify";
User = "matrix-synapse";
Group = "matrix-synapse";
WorkingDirectory = cfg.dataDir;
ExecStartPre = [ ("+" + (pkgs.writeShellScript "matrix-synapse-fix-permissions" ''
chown matrix-synapse:matrix-synapse ${cfg.dataDir}/homeserver.signing.key
chmod 0600 ${cfg.dataDir}/homeserver.signing.key
'')) ];
ExecStart = ''
${cfg.package}/bin/synapse_homeserver \
${ concatMapStringsSep "\n " (x: "--config-path ${x} \\") ([ configFile ] ++ cfg.extraConfigFiles) }
--keys-directory ${cfg.dataDir}
'';
ExecReload = "${pkgs.util-linux}/bin/kill -HUP $MAINPID";
Restart = "on-failure";
UMask = "0077";
};
};
environment.systemPackages = [ registerNewMatrixUser ];
};
imports = [
(mkRemovedOptionModule [ "services" "matrix-synapse" "trusted_third_party_id_servers" ] ''
The `trusted_third_party_id_servers` option as been removed in `matrix-synapse` v1.4.0
as the behavior is now obsolete.
'')
(mkRemovedOptionModule [ "services" "matrix-synapse" "create_local_database" ] ''
Database configuration must be done manually. An exemplary setup is demonstrated in
<nixpkgs/nixos/tests/matrix-synapse.nix>
'')
(mkRemovedOptionModule [ "services" "matrix-synapse" "web_client" ] "")
(mkRemovedOptionModule [ "services" "matrix-synapse" "room_invite_state_types" ] ''
You may add additional event types via
`services.matrix-synapse.room_prejoin_state.additional_event_types` and
disable the default events via
`services.matrix-synapse.room_prejoin_state.disable_default_event_types`.
'')
];
meta.doc = ./matrix-synapse.xml;
meta.maintainers = teams.matrix.members;
}

View file

@ -730,6 +730,40 @@ in
}; };
restartTriggers = [ nixConf ]; restartTriggers = [ nixConf ];
# `stopIfChanged = false` changes to switch behavior
# from stop -> update units -> start
# to update units -> restart
#
# The `stopIfChanged` setting therefore controls a trade-off between a
# more predictable lifecycle, which runs the correct "version" of
# the `ExecStop` line, and on the other hand the availability of
# sockets during the switch, as the effectiveness of the stop operation
# depends on the socket being stopped as well.
#
# As `nix-daemon.service` does not make use of `ExecStop`, we prefer
# to keep the socket up and available. This is important for machines
# that run Nix-based services, such as automated build, test, and deploy
# services, that expect the daemon socket to be available at all times.
#
# Notably, the Nix client does not retry on failure to connect to the
# daemon socket, and the in-process RemoteStore instance will disable
# itself. This makes retries infeasible even for services that are
# aware of the issue. Failure to connect can affect not only new client
# processes, but also new RemoteStore instances in existing processes,
# as well as existing RemoteStore instances that have not saturated
# their connection pool.
#
# Also note that `stopIfChanged = true` does not kill existing
# connection handling daemons, as one might wish to happen before a
# breaking Nix upgrade (which is rare). The daemon forks that handle
# the individual connections split off into their own sessions, causing
# them not to be stopped by systemd.
# If a Nix upgrade does require all existing daemon processes to stop,
# nix-daemon must do so on its own accord, and only when the new version
# starts and detects that Nix's persistent state needs an upgrade.
stopIfChanged = false;
}; };
# Set up the environment variables for running Nix. # Set up the environment variables for running Nix.

View file

@ -55,6 +55,19 @@ in
symlinks in Plex's plugin directory will be cleared and this module symlinks in Plex's plugin directory will be cleared and this module
will symlink all of the paths specified here to that directory. will symlink all of the paths specified here to that directory.
''; '';
example = literalExpression ''
[
(builtins.path {
name = "Audnexus.bundle";
path = pkgs.fetchFromGitHub {
owner = "djdembeck";
repo = "Audnexus.bundle";
rev = "v0.2.8";
sha256 = "sha256-IWOSz3vYL7zhdHan468xNc6C/eQ2C2BukQlaJNLXh7E=";
};
})
]
'';
}; };
extraScanners = mkOption { extraScanners = mkOption {

View file

@ -259,7 +259,7 @@ in
ipfs --offline config Mounts.IPFS ${cfg.ipfsMountDir} ipfs --offline config Mounts.IPFS ${cfg.ipfsMountDir}
ipfs --offline config Mounts.IPNS ${cfg.ipnsMountDir} ipfs --offline config Mounts.IPNS ${cfg.ipnsMountDir}
'' + optionalString cfg.autoMigrate '' '' + optionalString cfg.autoMigrate ''
${pkgs.ipfs-migrator}/bin/fs-repo-migrations -y ${pkgs.ipfs-migrator}/bin/fs-repo-migrations -to '${cfg.package.repoVersion}' -y
'' + '' '' + ''
ipfs --offline config show \ ipfs --offline config show \
| ${pkgs.jq}/bin/jq '. * $extraConfig' --argjson extraConfig ${ | ${pkgs.jq}/bin/jq '. * $extraConfig' --argjson extraConfig ${

View file

@ -3,22 +3,14 @@
let let
inherit (lib) mkEnableOption mkIf mkOption optionalString types; inherit (lib) mkEnableOption mkIf mkOption optionalString types;
generic = variant: cfg = config.services.bird2;
let caps = [ "CAP_NET_ADMIN" "CAP_NET_BIND_SERVICE" "CAP_NET_RAW" ];
cfg = config.services.${variant}; in
pkg = pkgs.${variant}; {
birdBin = if variant == "bird6" then "bird6" else "bird";
birdc = if variant == "bird6" then "birdc6" else "birdc";
descr =
{ bird = "1.6.x with IPv4 support";
bird6 = "1.6.x with IPv6 support";
bird2 = "2.x";
}.${variant};
in {
###### interface ###### interface
options = { options = {
services.${variant} = { services.bird2 = {
enable = mkEnableOption "BIRD Internet Routing Daemon (${descr})"; enable = mkEnableOption "BIRD Internet Routing Daemon";
config = mkOption { config = mkOption {
type = types.lines; type = types.lines;
description = '' description = ''
@ -44,7 +36,7 @@ let
''; '';
description = '' description = ''
Commands to execute before the config file check. The file to be checked will be Commands to execute before the config file check. The file to be checked will be
available as <code>${variant}.conf</code> in the current directory. available as <code>bird2.conf</code> in the current directory.
Files created with this option will not be available at service runtime, only during Files created with this option will not be available at service runtime, only during
build time checking. build time checking.
@ -53,53 +45,59 @@ let
}; };
}; };
imports = [
(lib.mkRemovedOptionModule [ "services" "bird" ] "Use services.bird2 instead")
(lib.mkRemovedOptionModule [ "services" "bird6" ] "Use services.bird2 instead")
];
###### implementation ###### implementation
config = mkIf cfg.enable { config = mkIf cfg.enable {
environment.systemPackages = [ pkg ]; environment.systemPackages = [ pkgs.bird ];
environment.etc."bird/${variant}.conf".source = pkgs.writeTextFile { environment.etc."bird/bird2.conf".source = pkgs.writeTextFile {
name = "${variant}.conf"; name = "bird2";
text = cfg.config; text = cfg.config;
checkPhase = optionalString cfg.checkConfig '' checkPhase = optionalString cfg.checkConfig ''
ln -s $out ${variant}.conf ln -s $out bird2.conf
${cfg.preCheckConfig} ${cfg.preCheckConfig}
${pkg}/bin/${birdBin} -d -p -c ${variant}.conf ${pkgs.bird}/bin/bird -d -p -c bird2.conf
''; '';
}; };
systemd.services.${variant} = { systemd.services.bird2 = {
description = "BIRD Internet Routing Daemon (${descr})"; description = "BIRD Internet Routing Daemon";
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
reloadIfChanged = true; reloadIfChanged = true;
restartTriggers = [ config.environment.etc."bird/${variant}.conf".source ]; restartTriggers = [ config.environment.etc."bird/bird2.conf".source ];
serviceConfig = { serviceConfig = {
Type = "forking"; Type = "forking";
Restart = "on-failure"; Restart = "on-failure";
ExecStart = "${pkg}/bin/${birdBin} -c /etc/bird/${variant}.conf -u ${variant} -g ${variant}"; User = "bird2";
ExecReload = "/bin/sh -c '${pkg}/bin/${birdBin} -c /etc/bird/${variant}.conf -p && ${pkg}/bin/${birdc} configure'"; Group = "bird2";
ExecStop = "${pkg}/bin/${birdc} down"; ExecStart = "${pkgs.bird}/bin/bird -c /etc/bird/bird2.conf";
CapabilityBoundingSet = [ "CAP_CHOWN" "CAP_FOWNER" "CAP_DAC_OVERRIDE" "CAP_SETUID" "CAP_SETGID" ExecReload = "${pkgs.bird}/bin/birdc configure";
# see bird/sysdep/linux/syspriv.h ExecStop = "${pkgs.bird}/bin/birdc down";
"CAP_NET_BIND_SERVICE" "CAP_NET_BROADCAST" "CAP_NET_ADMIN" "CAP_NET_RAW" ]; RuntimeDirectory = "bird";
CapabilityBoundingSet = caps;
AmbientCapabilities = caps;
ProtectSystem = "full"; ProtectSystem = "full";
ProtectHome = "yes"; ProtectHome = "yes";
SystemCallFilter="~@cpu-emulation @debug @keyring @module @mount @obsolete @raw-io"; ProtectKernelTunables = true;
ProtectControlGroups = true;
PrivateTmp = true;
PrivateDevices = true;
SystemCallFilter = "~@cpu-emulation @debug @keyring @module @mount @obsolete @raw-io";
MemoryDenyWriteExecute = "yes"; MemoryDenyWriteExecute = "yes";
}; };
}; };
users = { users = {
users.${variant} = { users.bird2 = {
description = "BIRD Internet Routing Daemon user"; description = "BIRD Internet Routing Daemon user";
group = variant; group = "bird2";
isSystemUser = true; isSystemUser = true;
}; };
groups.${variant} = {}; groups.bird2 = { };
}; };
}; };
};
in
{
imports = map generic [ "bird" "bird6" "bird2" ];
} }

View file

@ -306,7 +306,7 @@ in
Type = if forking then "forking" else "simple"; Type = if forking then "forking" else "simple";
PIDFile = mkIf forking "/run/murmur/murmurd.pid"; PIDFile = mkIf forking "/run/murmur/murmurd.pid";
EnvironmentFile = mkIf (cfg.environmentFile != null) cfg.environmentFile; EnvironmentFile = mkIf (cfg.environmentFile != null) cfg.environmentFile;
ExecStart = "${cfg.package}/bin/murmurd -ini /run/murmur/murmurd.ini"; ExecStart = "${cfg.package}/bin/mumble-server -ini /run/murmur/murmurd.ini";
Restart = "always"; Restart = "always";
RuntimeDirectory = "murmur"; RuntimeDirectory = "murmur";
RuntimeDirectoryMode = "0700"; RuntimeDirectoryMode = "0700";

View file

@ -556,6 +556,7 @@ in {
boot.kernelModules = [ "ctr" ]; boot.kernelModules = [ "ctr" ];
security.polkit.enable = true;
security.polkit.extraConfig = polkitConf; security.polkit.extraConfig = polkitConf;
services.dbus.packages = cfg.packages services.dbus.packages = cfg.packages

View file

@ -0,0 +1,81 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.snowflake-proxy;
in
{
options = {
services.snowflake-proxy = {
enable = mkEnableOption "System to defeat internet censorship";
broker = mkOption {
description = "Broker URL (default \"https://snowflake-broker.torproject.net/\")";
type = with types; nullOr str;
default = null;
};
capacity = mkOption {
description = "Limits the amount of maximum concurrent clients allowed.";
type = with types; nullOr int;
default = null;
};
relay = mkOption {
description = "websocket relay URL (default \"wss://snowflake.bamsoftware.com/\")";
type = with types; nullOr str;
default = null;
};
stun = mkOption {
description = "STUN broker URL (default \"stun:stun.stunprotocol.org:3478\")";
type = with types; nullOr str;
default = null;
};
};
};
config = mkIf cfg.enable {
systemd.services.snowflake-proxy = {
wantedBy = [ "network-online.target" ];
serviceConfig = {
ExecStart =
"${pkgs.snowflake}/bin/proxy " + concatStringsSep " " (
optional (cfg.broker != null) "-broker ${cfg.broker}"
++ optional (cfg.capacity != null) "-capacity ${builtins.toString cfg.capacity}"
++ optional (cfg.relay != null) "-relay ${cfg.relay}"
++ optional (cfg.stun != null) "-stun ${cfg.stun}"
);
# Security Hardening
# Refer to systemd.exec(5) for option descriptions.
CapabilityBoundingSet = "";
# implies RemoveIPC=, PrivateTmp=, NoNewPrivileges=, RestrictSUIDSGID=,
# ProtectSystem=strict, ProtectHome=read-only
DynamicUser = true;
LockPersonality = true;
PrivateDevices = true;
PrivateUsers = true;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectProc = "invisible";
ProtectKernelModules = true;
ProtectKernelTunables = true;
RestrictAddressFamilies = [ "AF_INET" "AF_INET6" "AF_UNIX" ];
RestrictNamespaces = true;
RestrictRealtime = true;
SystemCallArchitectures = "native";
SystemCallFilter = "~@clock @cpu-emulation @debug @mount @obsolete @reboot @swap @privileged @resources";
UMask = "0077";
};
};
};
meta.maintainers = with maintainers; [ yayayayaka ];
}

View file

@ -1,7 +1,7 @@
{ config, lib, pkgs, ... }: { config, lib, pkgs, ... }:
{ {
options.services.tetrd.enable = lib.mkEnableOption pkgs.tetrd.meta.description; options.services.tetrd.enable = lib.mkEnableOption "tetrd";
config = lib.mkIf config.services.tetrd.enable { config = lib.mkIf config.services.tetrd.enable {
environment = { environment = {

View file

@ -9,7 +9,7 @@ let
pkg = pkgs.clamav; pkg = pkgs.clamav;
toKeyValue = generators.toKeyValue { toKeyValue = generators.toKeyValue {
mkKeyValue = generators.mkKeyValueDefault {} " "; mkKeyValue = generators.mkKeyValueDefault { } " ";
listsAsDuplicateKeys = true; listsAsDuplicateKeys = true;
}; };
@ -30,7 +30,7 @@ in
settings = mkOption { settings = mkOption {
type = with types; attrsOf (oneOf [ bool int str (listOf str) ]); type = with types; attrsOf (oneOf [ bool int str (listOf str) ]);
default = {}; default = { };
description = '' description = ''
ClamAV configuration. Refer to <link xlink:href="https://linux.die.net/man/5/clamd.conf"/>, ClamAV configuration. Refer to <link xlink:href="https://linux.die.net/man/5/clamd.conf"/>,
for details on supported values. for details on supported values.
@ -59,7 +59,7 @@ in
settings = mkOption { settings = mkOption {
type = with types; attrsOf (oneOf [ bool int str (listOf str) ]); type = with types; attrsOf (oneOf [ bool int str (listOf str) ]);
default = {}; default = { };
description = '' description = ''
freshclam configuration. Refer to <link xlink:href="https://linux.die.net/man/5/freshclam.conf"/>, freshclam configuration. Refer to <link xlink:href="https://linux.die.net/man/5/freshclam.conf"/>,
for details on supported values. for details on supported values.
@ -104,7 +104,6 @@ in
systemd.services.clamav-daemon = mkIf cfg.daemon.enable { systemd.services.clamav-daemon = mkIf cfg.daemon.enable {
description = "ClamAV daemon (clamd)"; description = "ClamAV daemon (clamd)";
after = optional cfg.updater.enable "clamav-freshclam.service"; after = optional cfg.updater.enable "clamav-freshclam.service";
requires = optional cfg.updater.enable "clamav-freshclam.service";
wantedBy = [ "multi-user.target" ]; wantedBy = [ "multi-user.target" ];
restartTriggers = [ clamdConfigFile ]; restartTriggers = [ clamdConfigFile ];
@ -134,7 +133,7 @@ in
systemd.services.clamav-freshclam = mkIf cfg.updater.enable { systemd.services.clamav-freshclam = mkIf cfg.updater.enable {
description = "ClamAV virus database updater (freshclam)"; description = "ClamAV virus database updater (freshclam)";
restartTriggers = [ freshclamConfigFile ]; restartTriggers = [ freshclamConfigFile ];
after = [ "network-online.target" ];
preStart = '' preStart = ''
mkdir -m 0755 -p ${stateDir} mkdir -m 0755 -p ${stateDir}
chown ${clamavUser}:${clamavGroup} ${stateDir} chown ${clamavUser}:${clamavGroup} ${stateDir}

View file

@ -1,82 +0,0 @@
{ config, lib, pkgs, ... }:
with lib;
let
fprotUser = "fprot";
stateDir = "/var/lib/fprot";
fprotGroup = fprotUser;
cfg = config.services.fprot;
in {
options = {
services.fprot = {
updater = {
enable = mkEnableOption "automatic F-Prot virus definitions database updates";
productData = mkOption {
description = ''
product.data file. Defaults to the one supplied with installation package.
'';
type = types.path;
};
frequency = mkOption {
default = 30;
type = types.int;
description = ''
Update virus definitions every X minutes.
'';
};
licenseKeyfile = mkOption {
type = types.path;
description = ''
License keyfile. Defaults to the one supplied with installation package.
'';
};
};
};
};
###### implementation
config = mkIf cfg.updater.enable {
services.fprot.updater.productData = mkDefault "${pkgs.fprot}/opt/f-prot/product.data";
services.fprot.updater.licenseKeyfile = mkDefault "${pkgs.fprot}/opt/f-prot/license.key";
environment.systemPackages = [ pkgs.fprot ];
environment.etc."f-prot.conf" = {
source = "${pkgs.fprot}/opt/f-prot/f-prot.conf";
};
users.users.${fprotUser} =
{ uid = config.ids.uids.fprot;
description = "F-Prot daemon user";
home = stateDir;
};
users.groups.${fprotGroup} =
{ gid = config.ids.gids.fprot; };
services.cron.systemCronJobs = [ "*/${toString cfg.updater.frequency} * * * * root start fprot-updater" ];
systemd.services.fprot-updater = {
serviceConfig = {
Type = "oneshot";
RemainAfterExit = false;
};
wantedBy = [ "multi-user.target" ];
# have to copy fpupdate executable because it insists on storing the virus database in the same dir
preStart = ''
mkdir -m 0755 -p ${stateDir}
chown ${fprotUser}:${fprotGroup} ${stateDir}
cp ${pkgs.fprot}/opt/f-prot/fpupdate ${stateDir}
ln -sf ${cfg.updater.productData} ${stateDir}/product.data
'';
script = "/var/lib/fprot/fpupdate --keyfile ${cfg.updater.licenseKeyfile}";
};
};
}

View file

@ -3,22 +3,123 @@
with lib; with lib;
let let
name = "opensnitch";
cfg = config.services.opensnitch; cfg = config.services.opensnitch;
format = pkgs.formats.json {};
in { in {
options = { options = {
services.opensnitch = { services.opensnitch = {
enable = mkEnableOption "Opensnitch application firewall"; enable = mkEnableOption "Opensnitch application firewall";
settings = mkOption {
type = types.submodule {
freeformType = format.type;
options = {
Server = {
Address = mkOption {
type = types.str;
description = ''
Unix socket path (unix:///tmp/osui.sock, the "unix:///" part is
mandatory) or TCP socket (192.168.1.100:50051).
'';
};
LogFile = mkOption {
type = types.path;
description = ''
File to write logs to (use /dev/stdout to write logs to standard
output).
'';
};
};
DefaultAction = mkOption {
type = types.enum [ "allow" "deny" ];
description = ''
Default action whether to block or allow application internet
access.
'';
};
DefaultDuration = mkOption {
type = types.enum [
"once" "always" "until restart" "30s" "5m" "15m" "30m" "1h"
];
description = ''
Default duration of firewall rule.
'';
};
InterceptUnknown = mkOption {
type = types.bool;
description = ''
Wheter to intercept spare connections.
'';
};
ProcMonitorMethod = mkOption {
type = types.enum [ "ebpf" "proc" "ftrace" "audit" ];
description = ''
Which process monitoring method to use.
'';
};
LogLevel = mkOption {
type = types.enum [ 0 1 2 3 4 ];
description = ''
Default log level from 0 to 4 (debug, info, important, warning,
error).
'';
};
Firewall = mkOption {
type = types.enum [ "iptables" "nftables" ];
description = ''
Which firewall backend to use.
'';
};
Stats = {
MaxEvents = mkOption {
type = types.int;
description = ''
Max events to send to the GUI.
'';
};
MaxStats = mkOption {
type = types.int;
description = ''
Max stats per item to keep in backlog.
'';
};
};
};
};
description = ''
opensnitchd configuration. Refer to
<link xlink:href="https://github.com/evilsocket/opensnitch/wiki/Configurations"/>
for details on supported values.
'';
};
}; };
}; };
config = mkIf cfg.enable { config = mkIf cfg.enable {
# pkg.opensnitch is referred to elsewhere in the module so we don't need to worry about it being garbage collected
services.opensnitch.settings = mapAttrs (_: v: mkDefault v) (builtins.fromJSON (builtins.unsafeDiscardStringContext (builtins.readFile "${pkgs.opensnitch}/etc/default-config.json")));
systemd = { systemd = {
packages = [ pkgs.opensnitch ]; packages = [ pkgs.opensnitch ];
services.opensnitchd.wantedBy = [ "multi-user.target" ]; services.opensnitchd.wantedBy = [ "multi-user.target" ];
}; };
environment.etc."opensnitchd/default-config.json".source = format.generate "default-config.json" cfg.settings;
}; };
} }

View file

@ -106,6 +106,9 @@ in
ConditionFileNotEmpty = ""; # override upstream ConditionFileNotEmpty = ""; # override upstream
}; };
serviceConfig = { serviceConfig = {
User = "step-ca";
Group = "step-ca";
UMask = "0077";
Environment = "HOME=%S/step-ca"; Environment = "HOME=%S/step-ca";
WorkingDirectory = ""; # override upstream WorkingDirectory = ""; # override upstream
ReadWriteDirectories = ""; # override upstream ReadWriteDirectories = ""; # override upstream
@ -127,6 +130,14 @@ in
}; };
}; };
users.users.step-ca = {
home = "/var/lib/step-ca";
group = "step-ca";
isSystemUser = true;
};
users.groups.step-ca = {};
networking.firewall = lib.mkIf cfg.openFirewall { networking.firewall = lib.mkIf cfg.openFirewall {
allowedTCPPorts = [ cfg.port ]; allowedTCPPorts = [ cfg.port ];
}; };

View file

@ -151,7 +151,7 @@ in {
}; };
systemd.services.backup-vaultwarden = mkIf (cfg.backupDir != null) { systemd.services.backup-vaultwarden = mkIf (cfg.backupDir != null) {
aliases = [ "backup-bitwarden_rs" ]; aliases = [ "backup-bitwarden_rs.service" ];
description = "Backup vaultwarden"; description = "Backup vaultwarden";
environment = { environment = {
DATA_FOLDER = "/var/lib/bitwarden_rs"; DATA_FOLDER = "/var/lib/bitwarden_rs";
@ -169,7 +169,7 @@ in {
}; };
systemd.timers.backup-vaultwarden = mkIf (cfg.backupDir != null) { systemd.timers.backup-vaultwarden = mkIf (cfg.backupDir != null) {
aliases = [ "backup-bitwarden_rs" ]; aliases = [ "backup-bitwarden_rs.service" ];
description = "Backup vaultwarden on time"; description = "Backup vaultwarden on time";
timerConfig = { timerConfig = {
OnCalendar = mkDefault "23:00"; OnCalendar = mkDefault "23:00";

View file

@ -39,20 +39,12 @@ in
''; '';
}; };
useKernelOOMKiller= mkOption { # TODO: remove or warn after 1.7 (https://github.com/rfjakob/earlyoom/commit/7ebc4554)
type = types.bool;
default = false;
description = ''
Use kernel OOM killer instead of own user-space implementation.
'';
};
ignoreOOMScoreAdjust = mkOption { ignoreOOMScoreAdjust = mkOption {
type = types.bool; type = types.bool;
default = false; default = false;
description = '' description = ''
Ignore oom_score_adjust values of processes. Ignore oom_score_adjust values of processes.
User-space implementation only.
''; '';
}; };
@ -87,16 +79,21 @@ in
}; };
}; };
imports = [
(mkRemovedOptionModule [ "services" "earlyoom" "useKernelOOMKiller" ] ''
This option is deprecated and ignored by earlyoom since 1.2.
'')
];
config = mkIf ecfg.enable { config = mkIf ecfg.enable {
assertions = [ assertions = [
{ assertion = ecfg.freeMemThreshold > 0 && ecfg.freeMemThreshold <= 100; { assertion = ecfg.freeMemThreshold > 0 && ecfg.freeMemThreshold <= 100;
message = "Needs to be a positive percentage"; } message = "Needs to be a positive percentage"; }
{ assertion = ecfg.freeSwapThreshold > 0 && ecfg.freeSwapThreshold <= 100; { assertion = ecfg.freeSwapThreshold > 0 && ecfg.freeSwapThreshold <= 100;
message = "Needs to be a positive percentage"; } message = "Needs to be a positive percentage"; }
{ assertion = !ecfg.useKernelOOMKiller || !ecfg.ignoreOOMScoreAdjust;
message = "Both options in conjunction do not make sense"; }
]; ];
# TODO: reimplement this option as -N after 1.7 (https://github.com/rfjakob/earlyoom/commit/afe03606)
warnings = optional (ecfg.notificationsCommand != null) warnings = optional (ecfg.notificationsCommand != null)
"`services.earlyoom.notificationsCommand` is deprecated and ignored by earlyoom since 1.6."; "`services.earlyoom.notificationsCommand` is deprecated and ignored by earlyoom since 1.6.";
@ -107,15 +104,13 @@ in
serviceConfig = { serviceConfig = {
StandardOutput = "null"; StandardOutput = "null";
StandardError = "journal"; StandardError = "journal";
ExecStart = '' ExecStart = concatStringsSep " " ([
${pkgs.earlyoom}/bin/earlyoom \ "${pkgs.earlyoom}/bin/earlyoom"
-m ${toString ecfg.freeMemThreshold} \ "-m ${toString ecfg.freeMemThreshold}"
-s ${toString ecfg.freeSwapThreshold} \ "-s ${toString ecfg.freeSwapThreshold}"
${optionalString ecfg.useKernelOOMKiller "-k"} \ ] ++ optional ecfg.ignoreOOMScoreAdjust "-i"
${optionalString ecfg.ignoreOOMScoreAdjust "-i"} \ ++ optional ecfg.enableDebugInfo "-d"
${optionalString ecfg.enableDebugInfo "-d"} \ ++ optional ecfg.enableNotifications "-n");
${optionalString ecfg.enableNotifications "-n"}
'';
}; };
}; };

View file

@ -81,6 +81,8 @@ in {
}; };
}; };
security.polkit.enable = true;
security.pam.services.cage.text = '' security.pam.services.cage.text = ''
auth required pam_unix.so nullok auth required pam_unix.so nullok
account required pam_unix.so account required pam_unix.so

Some files were not shown because too many files have changed in this diff Show more