Merge commit '6f456e34e5cf13571ea9c7d6d88436171739e23c' into haskell-updates

This commit is contained in:
Wolfgang Walther
2025-12-10 18:18:33 +01:00
2180 changed files with 31541 additions and 14614 deletions
+5 -2
View File
@@ -27,7 +27,7 @@ jobs:
steps:
# Use a GitHub App to create the PR so that CI gets triggered
# The App is scoped to Repository > Contents and Pull Requests: write for Nixpkgs
- uses: actions/create-github-app-token@7e473efe3cb98aa54f8d4bac15400b15fad77d94 # v2.2.0
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
id: app-token
with:
app-id: ${{ vars.NIXPKGS_CI_APP_ID }}
@@ -36,7 +36,7 @@ jobs:
permission-pull-requests: write
permission-workflows: write
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
ref: ${{ github.event.pull_request.head.sha }}
token: ${{ steps.app-token.outputs.token }}
@@ -61,6 +61,9 @@ jobs:
Even as a non-committer, if you find that it is not acceptable, leave a comment.
> [!TIP]
> If you maintain all packages touched by this pull request, and they are all located under `pkgs/by-name/*`, you can comment **`@NixOS/nixpkgs-merge-bot merge`** to automatically merge this PR using the [`nixpkgs-merge-bot`](https://github.com/NixOS/nixpkgs/blob/master/ci/README.md#nixpkgs-merge-bot).
- name: Log current API rate limits
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
+2 -2
View File
@@ -46,7 +46,7 @@ jobs:
# https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout: |
@@ -56,7 +56,7 @@ jobs:
run: npm install @actions/artifact bottleneck
# Use a GitHub App, because it has much higher rate limits: 12,500 instead of 5,000 req / hour.
- uses: actions/create-github-app-token@7e473efe3cb98aa54f8d4bac15400b15fad77d94 # v2.2.0
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
if: github.event_name != 'pull_request' && vars.NIXPKGS_CI_APP_ID
id: app-token
with:
+1 -1
View File
@@ -52,7 +52,7 @@ jobs:
runs-on: ${{ matrix.runner }}
timeout-minutes: 60
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout: .github/actions
+2 -2
View File
@@ -35,7 +35,7 @@ jobs:
runs-on: ubuntu-slim
timeout-minutes: 3
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
path: trusted
@@ -75,7 +75,7 @@ jobs:
runs-on: ubuntu-24.04-arm
timeout-minutes: 5
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout: .github/actions
+2 -2
View File
@@ -23,14 +23,14 @@ jobs:
timeout-minutes: 2
if: contains(github.event.comment.body, '@NixOS/nixpkgs-merge-bot merge')
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout: |
ci/github-script
# Use the GitHub App to make sure the reaction happens with the same user who will later merge.
- uses: actions/create-github-app-token@7e473efe3cb98aa54f8d4bac15400b15fad77d94 # v2.2.0
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
if: github.event_name != 'pull_request' && vars.NIXPKGS_CI_APP_ID
id: app-token
with:
+1 -1
View File
@@ -36,7 +36,7 @@ jobs:
# Use a GitHub App to create the PR so that CI gets triggered
# The App is scoped to Repository > Contents and Pull Requests: write for Nixpkgs
# We only need Pull Requests: write here, but the app is also used for backports.
- uses: actions/create-github-app-token@7e473efe3cb98aa54f8d4bac15400b15fad77d94 # v2.2.0
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
id: app-token
with:
app-id: ${{ vars.NIXPKGS_CI_APP_ID }}
+5 -5
View File
@@ -37,7 +37,7 @@ jobs:
outputs:
versions: ${{ steps.versions.outputs.versions }}
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
path: trusted
@@ -45,7 +45,7 @@ jobs:
ci/supportedVersions.nix
- name: Check out the PR at the test merge commit
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
ref: ${{ inputs.mergedSha }}
@@ -89,7 +89,7 @@ jobs:
sudo mkswap /swap
sudo swapon /swap
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout: .github/actions
@@ -171,7 +171,7 @@ jobs:
statuses: write
timeout-minutes: 5
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout: .github/actions
@@ -342,7 +342,7 @@ jobs:
runs-on: ubuntu-24.04-arm
timeout-minutes: 10
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout: .github/actions
+3 -3
View File
@@ -26,7 +26,7 @@ jobs:
runs-on: ubuntu-24.04-arm
timeout-minutes: 10
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout: .github/actions
@@ -61,7 +61,7 @@ jobs:
runs-on: ubuntu-24.04-arm
timeout-minutes: 10
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout: .github/actions
@@ -90,7 +90,7 @@ jobs:
runs-on: ubuntu-24.04-arm
timeout-minutes: 10
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout: .github/actions
+1 -1
View File
@@ -25,7 +25,7 @@ jobs:
targetSha: ${{ steps.prepare.outputs.targetSha }}
systems: ${{ steps.prepare.outputs.systems }}
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout: |
+2 -2
View File
@@ -26,7 +26,7 @@ jobs:
steps:
# Use a GitHub App to create the PR so that CI gets triggered
# The App is scoped to Repository > Contents and Pull Requests: write for Nixpkgs
- uses: actions/create-github-app-token@7e473efe3cb98aa54f8d4bac15400b15fad77d94 # v2.2.0
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
id: app-token
with:
app-id: ${{ vars.NIXPKGS_CI_APP_ID }}
@@ -34,7 +34,7 @@ jobs:
permission-contents: write
permission-pull-requests: write
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
+1 -1
View File
@@ -31,7 +31,7 @@ jobs:
systems: ${{ steps.prepare.outputs.systems }}
touched: ${{ steps.prepare.outputs.touched }}
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout-cone-mode: true # default, for clarity
+2 -2
View File
@@ -20,14 +20,14 @@ jobs:
runs-on: ubuntu-slim
timeout-minutes: 2
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout: |
ci/github-script
# Use the GitHub App to make sure the reaction happens with the same user who will later merge.
- uses: actions/create-github-app-token@7e473efe3cb98aa54f8d4bac15400b15fad77d94 # v2.2.0
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
if: github.event_name != 'pull_request' && vars.NIXPKGS_CI_APP_ID
id: app-token
with:
+3 -3
View File
@@ -19,7 +19,7 @@ jobs:
steps:
# Use a GitHub App to create the PR so that CI gets triggered and to
# request team member lists.
- uses: actions/create-github-app-token@7e473efe3cb98aa54f8d4bac15400b15fad77d94 # v2.2.0
- uses: actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf # v2.2.1
id: app-token
with:
app-id: ${{ vars.NIXPKGS_CI_APP_ID }}
@@ -30,7 +30,7 @@ jobs:
permission-pull-requests: write
- name: Fetch source
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout: |
@@ -64,7 +64,7 @@ jobs:
echo "git-string=$name <$email>" >> "$GITHUB_OUTPUT"
- name: Create Pull Request
uses: peter-evans/create-pull-request@84ae59a2cdc2258d6fa0732dd66352dddae2a412 # v7.0.9
uses: peter-evans/create-pull-request@22a9089034f40e5a961c8808d113e2c98fb63676 # v7.0.11
with:
token: ${{ steps.app-token.outputs.token }}
add-paths: maintainers/github-teams.json
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
push: ${{ steps.files.outputs.push }}
targetSha: ${{ steps.prepare.outputs.targetSha }}
steps:
- uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
with:
persist-credentials: false
sparse-checkout-cone-mode: true # default, for clarity
+3
View File
@@ -26,6 +26,9 @@ Sandro Jäckel <sandro.jaeckel@gmail.com>
Sandro Jäckel <sandro.jaeckel@gmail.com> <sandro.jaeckel@sap.com>
superherointj <5861043+superherointj@users.noreply.github.com>
Tomodachi94 <tomodachi94@protonmail.com> Tomo <68489118+Tomodachi94@users.noreply.github.com>
toastal <toastal@posteo.net>
toastal <toastal@posteo.net> <561087+toastal@users.noreply.github.com>
toastal <toastal@posteo.net> <toastal@protonmail.com>
Vladimír Čunát <v@cunat.cz> <vcunat@gmail.com>
Vladimír Čunát <v@cunat.cz> <vladimir.cunat@nic.cz>
Yifei Sun <ysun@hey.com>
+2 -2
View File
@@ -659,13 +659,13 @@ If you have any problems with formatting, please ping the [formatting team](http
Do
```nix
{ rev = version; }
{ tag = version; }
```
instead of
```nix
{ rev = "${version}"; }
{ tag = "${version}"; }
```
- Building lists conditionally _should_ be done with `lib.optional(s)` instead of using `if cond then [ ... ] else null` or `if cond then [ ... ] else [ ]`.
+10 -10
View File
@@ -206,9 +206,9 @@ nixos/modules/installer/tools/nix-fallback-paths.nix @NixOS/nix-team @raitobeza
/pkgs/top-level/haskell-packages.nix @sternenseemann @maralorn @wolfgangwalther
# Perl
/pkgs/development/interpreters/perl @stigtsp @zakame @marcusramberg
/pkgs/top-level/perl-packages.nix @stigtsp @zakame @marcusramberg
/pkgs/development/perl-modules @stigtsp @zakame @marcusramberg
/pkgs/development/interpreters/perl @stigtsp @marcusramberg
/pkgs/top-level/perl-packages.nix @stigtsp @marcusramberg
/pkgs/development/perl-modules @stigtsp @marcusramberg
# R
/pkgs/applications/science/math/R @jbedo
@@ -262,7 +262,7 @@ pkgs/development/python-modules/buildcatrust/ @ajs124 @lukegb @mweinelt
/pkgs/top-level/java-packages.nix @NixOS/java
# Jetbrains
/pkgs/applications/editors/jetbrains @edwtjo @leona-ya @theCapypara
/pkgs/applications/editors/jetbrains @leona-ya @theCapypara
# Licenses
/lib/licenses.nix @alyssais @emilazy @jopejoe1
@@ -382,12 +382,12 @@ pkgs/development/python-modules/buildcatrust/ @ajs124 @lukegb @mweinelt
/pkgs/applications/editors/vscode/extensions
# PHP interpreter, packages, extensions, tests and documentation
/doc/languages-frameworks/php.section.md @aanderse @globin @ma27 @talyz
/nixos/tests/php @aanderse @globin @ma27 @talyz
/pkgs/build-support/php/build-pecl.nix @aanderse @globin @ma27 @talyz
/pkgs/development/interpreters/php @jtojnar @aanderse @globin @ma27 @talyz
/pkgs/development/php-packages @aanderse @globin @ma27 @talyz
/pkgs/top-level/php-packages.nix @jtojnar @aanderse @globin @ma27 @talyz
/doc/languages-frameworks/php.section.md @aanderse @ma27 @talyz
/nixos/tests/php @aanderse @ma27 @talyz
/pkgs/build-support/php/build-pecl.nix @aanderse @ma27 @talyz
/pkgs/development/interpreters/php @jtojnar @aanderse @ma27 @talyz
/pkgs/development/php-packages @aanderse @ma27 @talyz
/pkgs/top-level/php-packages.nix @jtojnar @aanderse @ma27 @talyz
# Docker tools
/pkgs/build-support/docker @roberth @jhol
+1 -2
View File
@@ -765,7 +765,7 @@ Used with Subversion. Expects `url` to a Subversion directory, `rev`, and `hash`
## `fetchgit` {#fetchgit}
Used with Git. Expects `url` to a Git repo, `rev`, and `hash`. `rev` in this case can be full the git commit id (SHA1 hash) or a tag name like `refs/tags/v1.0`.
Used with Git. Expects `url` to a Git repo, `rev` or `tag`, and `hash`. `rev` in this case can be full the git commit id (SHA1 hash), or use `tag` for a tag name like `refs/tags/v1.0`.
If you want to fetch a tag you should pass the `tag` parameter instead of `rev` which has the same effect as setting `rev = "refs/tags"/${version}"`.
This is safer than just setting `rev = version` w.r.t. possible branch and tag name conflicts.
@@ -1005,4 +1005,3 @@ fetchtorrent {
- `config`: When using `transmission` as the `backend`, a json configuration can
be supplied to transmission. Refer to the [upstream documentation](https://github.com/transmission/transmission/blob/main/docs/Editing-Configuration-Files.md) for information on how to configure.
+2 -2
View File
@@ -26,7 +26,7 @@ crystal.buildCrystalPackage rec {
src = fetchFromGitHub {
owner = "mint-lang";
repo = "mint";
rev = version;
tag = version;
hash = "sha256-dFN9l5fgrM/TtOPqlQvUYgixE4KPr629aBmkwdDoq28=";
};
@@ -68,7 +68,7 @@ crystal.buildCrystalPackage rec {
src = fetchFromGitHub {
owner = "mint-lang";
repo = "mint";
rev = version;
tag = version;
hash = "sha256-dFN9l5fgrM/TtOPqlQvUYgixE4KPr629aBmkwdDoq28=";
};
+1 -1
View File
@@ -84,7 +84,7 @@ nix-prefetch -E "{ sha256 }: ((import ./. { }).my-package.overrideAttrs { vendor
version = "0.4.0";
src = fetchFromGitHub {
inherit (previousAttrs.src) owner repo;
rev = "v${finalAttrs.version}";
tag = "v${finalAttrs.version}";
hash = "sha256-gVTpzmXekQxGMucDKskGi+e+34nJwwsXwvQTjRO6Gdg=";
};
vendorHash = "sha256-dUvp7FEW09V0xMuhewPGw3TuAic/sD7xyXEYviZ2Ivs=";
@@ -539,7 +539,7 @@ stdenv.mkDerivation (finalAttrs: {
src = fetchFromGitHub {
owner = "...";
repo = "...";
rev = "v${finalAttrs.version}";
tag = "v${finalAttrs.version}";
hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
};
+1 -1
View File
@@ -86,7 +86,7 @@ jd-cli.overrideMavenAttrs (old: rec {
src = fetchFromGitHub {
owner = old.src.owner;
repo = old.src.repo;
rev = "${old.pname}-${version}";
tag = "${old.pname}-${version}";
# old source hash of 1.2.0 version
hash = "sha256-US7j6tQ6mh1libeHnQdFxPGoxHzbZHqehWSgCYynKx8=";
};
+2 -2
View File
@@ -20,7 +20,7 @@ buildNimPackage (finalAttrs: {
src = fetchFromGitHub {
owner = "inv2004";
repo = "ttop";
rev = "v${finalAttrs.version}";
tag = "v${finalAttrs.version}";
hash = lib.fakeHash;
};
@@ -74,7 +74,7 @@ buildNimSbom (finalAttrs: {
src = fetchFromSourcehut {
owner = "~ehmry";
repo = "nim_lk";
rev = finalAttrs.version;
tag = finalAttrs.version;
hash = lib.fakeHash;
};
buildInputs = [ openssl ];
+1 -4
View File
@@ -45,10 +45,7 @@ Here is a simple package example.
- It also accepts a `duneVersion` parameter (valid values are `"2"`, and
`"3"`). The recommended practice is to set it only if you don't want the
default value and/or it depends on something else like package version. You
might see a not-supported argument `useDune2`. The behavior was `useDune2 =
true;` => `duneVersion = "2";` and `useDune2 = false;` => `duneVersion =
"1";`. It was used at the time when dune3 didn't exist.
default value and/or it depends on something else like package version.
- It sets the optional `doCheck` attribute such that tests will be run with
`dune runtest -p angstrom` after the build (`dune build -p angstrom`) is
+1 -1
View File
@@ -307,7 +307,7 @@ stdenvNoCC.mkDerivation (
src = fetchFromGitHub {
owner = "git-owner";
repo = "git-repo";
rev = finalAttrs.version;
tag = finalAttrs.version;
hash = "sha256-VcQRSss2dssfkJ+iUb5qT+FJ10GHiFDzySigcmuVI+8=";
};
in
+15
View File
@@ -14,8 +14,15 @@
- `kanata` now requires `karabiner-dk` version 6.0+ or later.
The package has been updated to use the new `karabiner-dk` package and the `darwinDriver` output stays at the version defined in the package.
- `iroh` has been removed and split up into `iroh-dns-server` and `iroh-relay`.
- All Log4Shell vulnerability scanners were removed, as they were all unmaintained upstream and are no longer relevant given that the vulnerability has been fixed upstream for several years.
- `asio` (standalone version of `boost::asio`) has been updated from 1.24.0 to 1.36.0. Some breaking changes were introduced between these
two versions, and the one affected most was the removal of `asio::io_service` in favor of `asio::io_context` in 1.33.0. `asio_1_32_0` is
retained for packages that have not completed migration. `asio_1_10` has been removed as no packages depend on it anymore.
`asio` also no longer propagates `boost` as it is used independent from `boost` in most cases.
- `python3packages.pillow-avif-plugin` has been removed as the functionality is included in `python3packages.pillow` directly since version 11.3.
## Other Notable Changes {#sec-nixpkgs-release-26.05-notable-changes}
@@ -26,6 +33,10 @@
If your SQLite database is corrupted, the migration might fail and require [manual intervention](https://github.com/louislam/uptime-kuma/issues/5281).
See the [migration guide](https://github.com/louislam/uptime-kuma/wiki/Migration-From-v1-To-v2) for more information.
- Added `dell-bios-fan-control` package and service.
- We now use the upstream wrapper script for Gradle, supporting both the `JAVA_HOME` and `GRADLE_OPTS` environment variables.
## Nixpkgs Library {#sec-nixpkgs-release-26.05-lib}
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
@@ -34,6 +45,10 @@
- `corepack_latest` has been removed, as Corepack is no longer distributed with Node.js.
- The `nodejs_latest` alias now points to `nodejs_25` instead of `nodejs_24`.
- `mold` is now wrapped by default.
### Deprecations {#sec-nixpkgs-release-26.05-lib-deprecations}
+13 -13
View File
@@ -86,7 +86,7 @@ If both the dependency and depending packages aren't compilers or other machine-
Finally, if the depending package is a compiler or other machine-code-producing tool, it might need dependencies that run at "emit time". This is for compilers that (regrettably) insist on being built together with their source languages' standard libraries. Assuming build != host != target, a run-time dependency of the standard library cannot be run at the compiler's build time or run time, but only at the run time of code emitted by the compiler.
Putting this all together, that means that we have dependency types of the form "X→ E", which means that the dependency executes on X and emits code for E; each of X and E can be `build`, `host`, or `target`, and E can be `*` to indicate that the dependency is not a compiler-like package.
Putting this all together, that means that we have dependency types of the form `X → E`, which means that the dependency executes on `X` and emits code for `E`; each of `X` and `E` can be `build`, `host`, or `target`, and `E` can be `*` to indicate that the dependency is not a compiler-like package.
Dependency types describe the relationships that a package has with each of its transitive dependencies. You could think of attaching one or more dependency types to each of the formal parameters at the top of a package's `.nix` file, as well as to all of *their* formal parameters, and so on. Triples like `(foo, bar, baz)`, on the other hand, are a property of an instantiated derivation -- you could would attach a triple `(mips-linux, mips-linux, sparc-solaris)` to a `.drv` file in `/nix/store`.
@@ -94,17 +94,17 @@ Only nine dependency types matter in practice:
#### Possible dependency types {#possible-dependency-types}
| Dependency type | Dependencys host platform | Dependencys target platform |
|-----------------|----------------------------|------------------------------|
| build → * | build | (none) |
| build → build | build | build |
| build → host | build | host |
| build → target | build | target |
| host → * | host | (none) |
| host → host | host | host |
| host → target | host | target |
| target → * | target | (none) |
| target → target | target | target |
| Dependency type | Dependencys host platform | Dependencys target platform |
|-------------------|----------------------------|------------------------------|
| `build → *` | `build` | (none) |
| `build → build` | `build` | `build` |
| `build → host` | `build` | `host` |
| `build → target` | `build` | `target` |
| `host → *` | `host` | (none) |
| `host → host` | `host` | `host` |
| `host → target` | `host` | `target` |
| `target → *` | `target` | (none) |
| `target → target` | `target` | `target` |
Let's use `g++` as an example to make this table clearer. `g++` is a C++ compiler written in C. Suppose we are building `g++` with a `(build, host, target)` platform triple of `(foo, bar, baz)`. This means we are using a `foo`-machine to build a copy of `g++` which will run on a `bar`-machine and emit binaries for the `baz`-machine.
@@ -235,7 +235,7 @@ One would think that `localSystem` and `crossSystem` overlap horribly with the t
### Implementation of dependencies {#ssec-cross-dependency-implementation}
The categories of dependencies developed in [](#ssec-cross-dependency-categorization) are specified as lists of derivations given to `mkDerivation`, as documented in [](#ssec-stdenv-dependencies). In short, each list of dependencies for "host → target" is called `deps<host><target>` (where `host`, and `target` values are either `build`, `host`, or `target`), with exceptions for backwards compatibility that `depsBuildHost` is instead called `nativeBuildInputs` and `depsHostTarget` is instead called `buildInputs`. Nixpkgs is now structured so that each `deps<host><target>` is automatically taken from `pkgs<host><target>`. (These `pkgs<host><target>`s are quite new, so there is no special case for `nativeBuildInputs` and `buildInputs`.) For example, `pkgsBuildHost.gcc` should be used at build-time, while `pkgsHostTarget.gcc` should be used at run-time.
The categories of dependencies developed in [](#ssec-cross-dependency-categorization) are specified as lists of derivations given to `mkDerivation`, as documented in [](#ssec-stdenv-dependencies). In short, each list of dependencies for `host → target` is called `deps<host><target>` (where `host`, and `target` values are either `build`, `host`, or `target`), with exceptions for backwards compatibility that `depsBuildHost` is instead called `nativeBuildInputs` and `depsHostTarget` is instead called `buildInputs`. Nixpkgs is now structured so that each `deps<host><target>` is automatically taken from `pkgs<host><target>`. (These `pkgs<host><target>`s are quite new, so there is no special case for `nativeBuildInputs` and `buildInputs`.) For example, `pkgsBuildHost.gcc` should be used at build-time, while `pkgsHostTarget.gcc` should be used at run-time.
Now, for most of Nixpkgs's history, there were no `pkgs<host><target>` attributes, and most packages have not been refactored to use it explicitly. Prior to those, there were just `buildPackages`, `pkgs`, and `targetPackages`. Those are now redefined as aliases to `pkgsBuildHost`, `pkgsHostTarget`, and `pkgsTargetTarget`. It is acceptable, even recommended, to use them for libraries to show that the host platform is irrelevant.
+8 -8
View File
@@ -327,14 +327,14 @@ Dependency propagation takes cross compilation into account, meaning that depend
To determine the exact rules for dependency propagation, we start by assigning to each dependency a couple of ternary numbers (`-1` for `build`, `0` for `host`, and `1` for `target`) representing its [dependency type](#possible-dependency-types), which captures how its host and target platforms are each "offset" from the depending derivations host and target platforms. The following table summarize the different combinations that can be obtained:
| `host → target` | attribute name | offset | typical purpose |
| ------------------- | ------------------- | -------- | --------------------------------------------- |
| `build --> build` | `depsBuildBuild` | `-1, -1` | compilers for build helpers |
| `build --> host` | `nativeBuildInputs` | `-1, 0` | build tools, compilers, setup hooks |
| `build --> target` | `depsBuildTarget` | `-1, 1` | compilers to build stdlibs to run on target |
| `host --> host` | `depsHostHost` | `0, 0` | compilers to build C code at runtime (rare) |
| `host --> target` | `buildInputs` | `0, 1` | libraries |
| `target --> target` | `depsTargetTarget` | `1, 1` | stdlibs to run on target |
| Dependency type | attribute name | offset | typical purpose |
| ----------------- | ------------------- | -------- | --------------------------------------------- |
| `build build` | `depsBuildBuild` | `-1, -1` | compilers for build helpers |
| `build host` | `nativeBuildInputs` | `-1, 0` | build tools, compilers, setup hooks |
| `build target` | `depsBuildTarget` | `-1, 1` | compilers to build stdlibs to run on target |
| `host host` | `depsHostHost` | `0, 0` | compilers to build C code at runtime (rare) |
| `host target` | `buildInputs` | `0, 1` | libraries |
| `target target` | `depsTargetTarget` | `1, 1` | stdlibs to run on target |
Algorithmically, we traverse propagated inputs, accumulating every propagated dependencys propagated dependencies and adjusting them to account for the “shift in perspective” described by the current dependencys platform offsets. This results in a sort of transitive closure of the dependency relation, with the offsets being approximately summed when two dependency links are combined. We also prune transitive dependencies whose combined offsets go out-of-bounds, which can be viewed as a filter over that transitive closure removing dependencies that are blatantly absurd.
+3
View File
@@ -437,6 +437,9 @@ rec {
isMacho = {
kernel.execFormat = execFormats.macho;
};
isPE = {
kernel.execFormat = execFormats.pe;
};
};
# given two patterns, return a pattern which is their logical AND.
+43 -39
View File
@@ -59,7 +59,11 @@ evalConfig() {
local attr=$1
shift
local script="import ./default.nix { modules = [ $* ];}"
local-nix-instantiate -E "$script" -A "$attr"
if [ "${ABORT_ON_WARN-0}" = "1" ]; then
local-nix-instantiate --option abort-on-warn true -E "$script" -A "$attr"
else
local-nix-instantiate -E "$script" -A "$attr"
fi
}
reportFailure() {
@@ -495,49 +499,49 @@ checkConfigError 'The option .mergedName. in .*\.nix. is already declared in .*\
# - non-merged types
# - nestedTypes elemType
# attrsWith
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.attrsWith.type.functor.wrapped ./deprecated-wrapped.nix
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedAttrsWith.type.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.attrsWith.type.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedAttrsWith.type.functor.wrapped ./deprecated-wrapped.nix
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.attrsWith.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedAttrsWith.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.attrsWith.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedAttrsWith.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
# listOf
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.listOf.type.functor.wrapped ./deprecated-wrapped.nix
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedListOf.type.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.listOf.type.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedListOf.type.functor.wrapped ./deprecated-wrapped.nix
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.listOf.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedListOf.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.listOf.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedListOf.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
# unique / uniq
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.unique.type.functor.wrapped ./deprecated-wrapped.nix
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedUnique.type.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.unique.type.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedUnique.type.functor.wrapped ./deprecated-wrapped.nix
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.unique.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedUnique.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.unique.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedUnique.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
# nullOr
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.nullOr.type.functor.wrapped ./deprecated-wrapped.nix
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedNullOr.type.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.nullOr.type.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedNullOr.type.functor.wrapped ./deprecated-wrapped.nix
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.nullOr.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedNullOr.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.nullOr.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedNullOr.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
# functionTo
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.functionTo.type.functor.wrapped ./deprecated-wrapped.nix
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedFunctionTo.type.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.functionTo.type.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedFunctionTo.type.functor.wrapped ./deprecated-wrapped.nix
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.functionTo.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedFunctionTo.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.functionTo.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedFunctionTo.type.nestedTypes.elemType.functor.wrapped ./deprecated-wrapped.nix
# coercedTo
# Note: test 'nestedTypes.finalType' and 'nestedTypes.coercedType'
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.coercedTo.type.functor.wrapped ./deprecated-wrapped.nix
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.coercedTo.type.nestedTypes.finalType.functor.wrapped ./deprecated-wrapped.nix
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.coercedTo.type.nestedTypes.coercedType.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.coercedTo.type.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.coercedTo.type.nestedTypes.finalType.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.coercedTo.type.nestedTypes.coercedType.functor.wrapped ./deprecated-wrapped.nix
# either
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.either.type.functor.wrapped ./deprecated-wrapped.nix
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedEither.type.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.either.type.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedEither.type.functor.wrapped ./deprecated-wrapped.nix
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.either.type.nestedTypes.left.functor.wrapped ./deprecated-wrapped.nix
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.either.type.nestedTypes.right.functor.wrapped ./deprecated-wrapped.nix
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedEither.type.nestedTypes.left.functor.wrapped ./deprecated-wrapped.nix
NIX_ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedEither.type.nestedTypes.right.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.either.type.nestedTypes.left.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.either.type.nestedTypes.right.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedEither.type.nestedTypes.left.functor.wrapped ./deprecated-wrapped.nix
ABORT_ON_WARN=1 checkConfigError 'The deprecated `.*functor.wrapped` attribute .*is accessed, use `.*nestedTypes.elemType` instead.' options.mergedEither.type.nestedTypes.right.functor.wrapped ./deprecated-wrapped.nix
# Even with multiple assignments, a type error should be thrown if any of them aren't valid
checkConfigError 'A definition for option .* is not of type .*' \
@@ -575,24 +579,24 @@ checkConfigOutput '^10$' config.free.yyy.bar ./freeform-submodules.nix
# Regression of either, due to freeform not beeing checked previously
checkConfigOutput '^"foo"$' config.either.int ./freeform-deprecated-malicous.nix ./freeform-deprecated-malicous-wrong.nix
NIX_ABORT_ON_WARN=1 checkConfigError "One or more definitions did not pass the type-check of the \'either\' type" config.either.int ./freeform-deprecated-malicous.nix ./freeform-deprecated-malicous-wrong.nix
ABORT_ON_WARN=1 checkConfigError "One or more definitions did not pass the type-check of the \'either\' type" config.either.int ./freeform-deprecated-malicous.nix ./freeform-deprecated-malicous-wrong.nix
checkConfigOutput '^"foo"$' config.eitherBehindNullor.int ./freeform-deprecated-malicous.nix ./freeform-deprecated-malicous-wrong.nix
NIX_ABORT_ON_WARN=1 checkConfigError "One or more definitions did not pass the type-check of the \'either\' type" config.eitherBehindNullor.int ./freeform-deprecated-malicous.nix ./freeform-deprecated-malicous-wrong.nix
ABORT_ON_WARN=1 checkConfigError "One or more definitions did not pass the type-check of the \'either\' type" config.eitherBehindNullor.int ./freeform-deprecated-malicous.nix ./freeform-deprecated-malicous-wrong.nix
checkConfigOutput '^"foo"$' config.oneOf.int ./freeform-deprecated-malicous.nix ./freeform-deprecated-malicous-wrong.nix
NIX_ABORT_ON_WARN=1 checkConfigError "One or more definitions did not pass the type-check of the \'either\' type" config.oneOf.int ./freeform-deprecated-malicous.nix ./freeform-deprecated-malicous-wrong.nix
ABORT_ON_WARN=1 checkConfigError "One or more definitions did not pass the type-check of the \'either\' type" config.oneOf.int ./freeform-deprecated-malicous.nix ./freeform-deprecated-malicous-wrong.nix
checkConfigOutput '^"foo"$' config.number.str ./freeform-deprecated-malicous.nix ./freeform-deprecated-malicous-wrong.nix
NIX_ABORT_ON_WARN=1 checkConfigError "One or more definitions did not pass the type-check of the \'either\' type" config.number.str ./freeform-deprecated-malicous.nix ./freeform-deprecated-malicous-wrong.nix
ABORT_ON_WARN=1 checkConfigError "One or more definitions did not pass the type-check of the \'either\' type" config.number.str ./freeform-deprecated-malicous.nix ./freeform-deprecated-malicous-wrong.nix
checkConfigOutput '^42$' config.either.int ./freeform-deprecated-malicous.nix ./freeform-deprecated-malicous-wrong2.nix
NIX_ABORT_ON_WARN=1 checkConfigError "One or more definitions did not pass the type-check of the \'either\' type" config.either.int ./freeform-deprecated-malicous.nix ./freeform-deprecated-malicous-wrong2.nix
ABORT_ON_WARN=1 checkConfigError "One or more definitions did not pass the type-check of the \'either\' type" config.either.int ./freeform-deprecated-malicous.nix ./freeform-deprecated-malicous-wrong2.nix
checkConfigOutput '^42$' config.eitherBehindNullor.int ./freeform-deprecated-malicous.nix ./freeform-deprecated-malicous-wrong2.nix
NIX_ABORT_ON_WARN=1 checkConfigError "One or more definitions did not pass the type-check of the \'either\' type" config.eitherBehindNullor.int ./freeform-deprecated-malicous.nix ./freeform-deprecated-malicous-wrong2.nix
ABORT_ON_WARN=1 checkConfigError "One or more definitions did not pass the type-check of the \'either\' type" config.eitherBehindNullor.int ./freeform-deprecated-malicous.nix ./freeform-deprecated-malicous-wrong2.nix
checkConfigOutput '^42$' config.oneOf.int ./freeform-deprecated-malicous.nix ./freeform-deprecated-malicous-wrong2.nix
NIX_ABORT_ON_WARN=1 checkConfigError "One or more definitions did not pass the type-check of the \'either\' type" config.oneOf.int ./freeform-deprecated-malicous.nix ./freeform-deprecated-malicous-wrong2.nix
ABORT_ON_WARN=1 checkConfigError "One or more definitions did not pass the type-check of the \'either\' type" config.oneOf.int ./freeform-deprecated-malicous.nix ./freeform-deprecated-malicous-wrong2.nix
checkConfigOutput '^42$' config.number.str ./freeform-deprecated-malicous.nix ./freeform-deprecated-malicous-wrong2.nix
NIX_ABORT_ON_WARN=1 checkConfigError "One or more definitions did not pass the type-check of the \'either\' type" config.number.str ./freeform-deprecated-malicous.nix ./freeform-deprecated-malicous-wrong2.nix
ABORT_ON_WARN=1 checkConfigError "One or more definitions did not pass the type-check of the \'either\' type" config.number.str ./freeform-deprecated-malicous.nix ./freeform-deprecated-malicous-wrong2.nix
# Value OK: Fail if a warning is emitted
NIX_ABORT_ON_WARN=1 checkConfigOutput "^42$" config.number.int ./freeform-attrsof-either.nix
ABORT_ON_WARN=1 checkConfigOutput "^42$" config.number.int ./freeform-attrsof-either.nix
## types.anything
+1 -1
View File
@@ -51,7 +51,7 @@ The maintainer is welcome to come back at any time.
When a pull request is made against a package, nixpkgs CI will notify the appropriate maintainer(s) by trying to correlate the files the PR touches with the packages that need rebuilding.
This process is subject to error however, so we encourage PR authors to notify the appropriate people.
Maintainers can also invoke the [nixpkgs-merge-bot](https://github.com/nixos/nixpkgs-merge-bot) to merge pull requests targeting packages they are the maintainer of, which satisfy the current security [constraints](https://github.com/NixOS/nixpkgs-merge-bot/blob/main/README.md#constraints).
Maintainers can also invoke the [nixpkgs-merge-bot](../ci/README.md#nixpkgs-merge-bot) to merge pull requests targeting packages they are the maintainer of, which satisfy the current security [constraints](../ci/README.md#merge-bot-constraints).
Examples: [#397273](https://github.com/NixOS/nixpkgs/pull/397273#issuecomment-2789382120) and [#377027](https://github.com/NixOS/nixpkgs/pull/377027#issuecomment-2614510869)
New maintainers will automatically get invited to join the [NixOS/nixpkgs-maintainers](https://github.com/orgs/NixOS/teams/nixpkgs-maintainers) GitHub team.
+2 -10
View File
@@ -49,8 +49,7 @@
"ethercrow": 222467,
"groodt": 343415,
"kalbasit": 87115,
"mboes": 51356,
"uri-canva": 33242106
"mboes": 51356
},
"name": "Bazel"
},
@@ -61,7 +60,6 @@
"happysalada": 5317234
},
"members": {
"Br1ght0ne": 12615679,
"DianaOlympos": 15774340,
"adamcstephens": 2071575,
"ankhers": 750786,
@@ -146,7 +144,6 @@
"peterhoeg": 722550
},
"members": {
"Br1ght0ne": 12615679,
"manveru": 3507
},
"name": "crystal-lang"
@@ -261,7 +258,6 @@
"thefloweringash": 42933,
"tricktron": 16036882,
"uncenter": 47499684,
"uri-canva": 33242106,
"usertam": 22500027,
"veprbl": 245573,
"viraptor": 188063,
@@ -501,7 +497,6 @@
},
"members": {
"cpages": 411324,
"edwtjo": 54799,
"minijackson": 1200507,
"peterhoeg": 722550,
"sephalon": 893474
@@ -529,7 +524,6 @@
"members": {
"K900": 386765,
"Ma27": 6025220,
"NeQuissimus": 628342,
"TredwellGit": 61860346
},
"name": "Linux kernel"
@@ -898,9 +892,7 @@
"winterqt": 78392041,
"zowoq": 59103226
},
"members": {
"tjni": 3806110
},
"members": {},
"name": "rust"
},
"scala": {
+120 -85
View File
@@ -374,6 +374,11 @@
githubId = 22131756;
name = "Aaqa Ishtyaq";
};
aaravrav = {
name = "aaravrav";
github = "aaravrav";
githubId = 3279912;
};
aarnphm = {
email = "contact@aarnphm.xyz";
github = "aarnphm";
@@ -800,6 +805,12 @@
githubId = 1141462;
name = "Vladyslav Pekker";
};
agustinmista = {
email = "agustin@mista.me";
github = "agustinmista";
githubId = 5265348;
name = "Agustin Mista";
};
agvantibo = {
email = "apicalium@gmail.com";
github = "agvantibo-again";
@@ -1625,6 +1636,13 @@
githubId = 24651767;
name = "Felix Andreas";
};
andreashgk = {
name = "andreashgk";
email = "andreas@hgk.me";
github = "andreashgk";
githubId = 36563463;
keys = [ { fingerprint = "E1C1 693D 0FF7 E8FD 73F2 C145 A894 A279 2F01 5C46"; } ];
};
andreasvoss = {
name = "andreasvoss";
email = "andreas@anvo.dk";
@@ -3112,6 +3130,12 @@
githubId = 354230;
name = "Benjamin Esham";
};
bdim404 = {
email = "i@bdim.moe";
github = "bdim404";
githubId = 102711645;
name = "bdim";
};
bdimcheff = {
email = "brandon@dimcheff.com";
github = "bdimcheff";
@@ -3385,12 +3409,6 @@
githubId = 45831883;
name = "Brieuc Dubois";
};
bhipple = {
email = "bhipple@protonmail.com";
github = "bhipple";
githubId = 2071583;
name = "Benjamin Hipple";
};
bhougland = {
email = "benjamin.hougland@gmail.com";
github = "bhougland18";
@@ -3748,13 +3766,6 @@
githubId = 140968250;
keys = [ { fingerprint = "8321 ED3A 8DB9 99A5 1F3B F80F F268 2914 EA42 DE26"; } ];
};
Br1ght0ne = {
email = "brightone@protonmail.com";
github = "Br1ght0ne";
githubId = 12615679;
name = "Oleksii Filonenko";
keys = [ { fingerprint = "F549 3B7F 9372 5578 FDD3 D0B8 A1BC 8428 323E CFE8"; } ];
};
br337 = {
email = "brian.porumb@proton.me";
github = "br337";
@@ -4916,6 +4927,17 @@
githubId = 9336788;
name = "Claes Hallström";
};
claymorwan = {
name = "claymorwan";
github = "claymorwan";
githubId = 86072589;
email = "claymorwan@fembois.dev";
keys = [
{
fingerprint = "AA7C 29C3 A26A DB2F 80E5 294D CC5E 1DF0 6FB7 8249";
}
];
};
clebs = {
email = "borja.clemente@gmail.com";
github = "clebs";
@@ -6440,6 +6462,12 @@
githubId = 17111639;
name = "Devin Singh";
};
devoid = {
name = "Scott Devoid";
email = "nixpkgs-github@d3void.net";
github = "devoid";
githubId = 581597;
};
devplayer0 = {
email = "dev@nul.ie";
github = "devplayer0";
@@ -7419,12 +7447,6 @@
githubId = 494483;
name = "Michael Francis";
};
edwtjo = {
email = "ed@cflags.cc";
github = "edwtjo";
githubId = 54799;
name = "Edward Tjörnhammar";
};
eeedean = {
github = "eeedean";
githubId = 8173116;
@@ -8242,6 +8264,11 @@
githubId = 175898536;
keys = [ { fingerprint = "4319 2667 85A9 E6BD 9A84 4BC7 1313 15C2 0524 200C"; } ];
};
ezratweaver = {
name = "Ezra Weaver";
github = "ezratweaver";
githubId = 101545981;
};
ezrizhu = {
name = "Ezri Zhu";
email = "me@ezrizhu.com";
@@ -9216,12 +9243,6 @@
githubId = 57430880;
name = "Gustavo Araiza";
};
garbas = {
email = "rok@garbas.si";
github = "garbas";
githubId = 20208;
name = "Rok Garbas";
};
gardspirito = {
name = "gardspirito";
email = "nyxoroso@gmail.com";
@@ -9663,6 +9684,12 @@
githubId = 58785758;
name = "Tim Lanzinger";
};
gonsolo = {
email = "gonsolo@gmail.com";
github = "gonsolo";
githubId = 2041764;
name = "Andreas Wendleder";
};
Gonzih = {
email = "gonzih@gmail.com";
github = "Gonzih";
@@ -9700,6 +9727,12 @@
githubId = 6375438;
keys = [ { fingerprint = "5214 2D39 A7CE F8FA 872B CA7F DE62 E1E2 A614 5556"; } ];
};
govindsi = {
email = "govind.sk85@gmail.com";
github = "govindsi";
githubId = 8924200;
name = "Govind Singh";
};
gp2112 = {
email = "me@guip.dev";
github = "gp2112";
@@ -10614,12 +10647,6 @@
githubId = 137852;
name = "Hraban Luyat";
};
hrdinka = {
email = "c.nix@hrdinka.at";
github = "hrdinka";
githubId = 1436960;
name = "Christoph Hrdinka";
};
hrhino = {
email = "hora.rhino@gmail.com";
github = "hrhino";
@@ -11577,12 +11604,6 @@
githubId = 10690970;
name = "James Duff";
};
jagajaga = {
email = "ars.seroka@gmail.com";
github = "jagajaga";
githubId = 2179419;
name = "Arseniy Seroka";
};
jakecleary = {
email = "shout@jakecleary.net";
github = "jakecleary";
@@ -13510,6 +13531,12 @@
name = "Kevin Cox";
keys = [ { fingerprint = "B66B 891D D83B 0E67 7D84 FC30 9BB9 2CC1 552E 99AA"; } ];
};
kevingimbel = {
email = "kevin@gimbel.dev";
github = "KevinGimbel";
githubId = 2161714;
name = "Kevin Gimbel";
};
kevingriffin = {
email = "me@kevin.jp";
github = "kevingriffin";
@@ -13931,6 +13958,12 @@
githubId = 36413794;
name = "Arek Kalandyk";
};
korken89 = {
email = "emil.fresk@gmail.com";
github = "korken89";
githubId = 913109;
name = "Emil Fresk";
};
koschi13 = {
email = "maximilian.konter@protonmail.com";
github = "koschi13";
@@ -15056,14 +15089,6 @@
githubId = 88983487;
name = "Loïc Reynier";
};
lom = {
email = "legendofmiracles@protonmail.com";
matrix = "@legendofmiracles:matrix.org";
github = "legendofmiracles";
githubId = 30902201;
name = "legendofmiracles";
keys = [ { fingerprint = "CC50 F82C 985D 2679 0703 AF15 19B0 82B3 DEFE 5451"; } ];
};
lomenzel = {
name = "Leonard-Orlando Menzel";
email = "leonard.menzel@tutanota.com";
@@ -15215,12 +15240,6 @@
githubId = 5341193;
name = "Leon Schuermann";
};
lsix = {
email = "lsix@lancelotsix.com";
github = "lsix";
githubId = 724339;
name = "Lancelot SIX";
};
ltavard = {
email = "laure.tavard@univ-grenoble-alpes.fr";
github = "ltavard";
@@ -15278,6 +15297,12 @@
githubId = 15693688;
name = "Lucas Eduardo Wendt";
};
lucasfa = {
name = "Lucas Fehlau Arbulu";
githubId = 23667494;
github = "LucasFA";
matrix = "@lucasfa:matrix.org";
};
lucastso10 = {
email = "lucastso10@gmail.com";
github = "lucastso10";
@@ -15290,6 +15315,12 @@
githubId = 1104419;
name = "Lucas Hoffmann";
};
luckshiba = {
email = "luckshiba@protonmail.com";
github = "luckshiba";
githubId = 43530291;
name = "LuckShiba";
};
lucperkins = {
email = "lucperkins@gmail.com";
github = "lucperkins";
@@ -17123,6 +17154,12 @@
githubId = 5378535;
name = "Milo Gertjejansen";
};
milomc123 = {
email = "contact@milo.zip";
github = "milomc123";
githubId = 33701036;
name = "Milo Mc";
};
mimame = {
email = "miguel.madrid.mencia@gmail.com";
github = "mimame";
@@ -18356,12 +18393,6 @@
githubId = 1771772;
name = "Alexander Ben Nasrallah";
};
nequissimus = {
email = "tim@nequissimus.com";
github = "NeQuissimus";
githubId = 628342;
name = "Tim Steinbach";
};
nerdypepper = {
email = "nerdy@peppe.rs";
github = "oppiliappan";
@@ -18850,6 +18881,12 @@
githubId = 41154684;
name = "nokazn";
};
nolith = {
github = "nolith";
githubId = 78752;
name = "Alessio Caiazza";
matrix = "@alessio:caiazza.info";
};
nomaterials = {
email = "nomaterials@gmail.com";
github = "no-materials";
@@ -19206,6 +19243,12 @@
email = "nyu@nyuku.ru";
githubId = 97425873;
};
nyxonios = {
name = "nyxonios";
github = "Nyxonios";
email = "martin.n.seller@gmail.com";
githubId = 18164197;
};
nzbr = {
email = "nixos@nzbr.de";
github = "nzbr";
@@ -20175,11 +20218,12 @@
name = "pentane";
keys = [ { fingerprint = "4231 75F6 8360 68C8 2ACB AEDA 63F4 EC2F FE55 0874"; } ];
};
perchun = {
PerchunPak = {
name = "Perchun Pak";
email = "nixpkgs@perchun.it";
github = "PerchunPak";
githubId = 68118654;
keys = [ { fingerprint = "BBB5 1142 959D 8549 A3D2 F6C5 313F 67D1 EAB7 70F9"; } ];
};
peret = {
name = "Peter Retzlaff";
@@ -22143,6 +22187,11 @@
githubId = 13792812;
name = "James Leitch";
};
rickyelopez = {
github = "rickyelopez";
githubId = 31072564;
name = "Ricky";
};
rickynils = {
email = "rickynils@gmail.com";
github = "rickynils";
@@ -23140,12 +23189,6 @@
github = "SandaruKasa";
githubId = 50824690;
};
sander = {
email = "s.vanderburg@tudelft.nl";
github = "svanderburg";
githubId = 1153271;
name = "Sander van der Burg";
};
sandptel = {
email = "sandppatel15@gmail.com";
github = "sandptel";
@@ -24882,7 +24925,7 @@
stepbrobd = {
name = "Yifei Sun";
email = "ysun@hey.com";
matrix = "@stepbrobd:matrix.org";
matrix = "@ysun:beeper.com";
github = "stepbrobd";
githubId = 81826728;
};
@@ -26366,14 +26409,6 @@
githubId = 36288711;
name = "Tim Keller";
};
tjni = {
email = "43ngvg@masqt.com";
matrix = "@tni:matrix.org";
name = "Theodore Ni";
github = "tjni";
githubId = 3806110;
keys = [ { fingerprint = "4384 B8E1 299F C028 1641 7B8F EC30 EFBE FA7E 84A4"; } ];
};
tkerber = {
email = "tk@drwx.org";
github = "tkerber";
@@ -27139,12 +27174,6 @@
githubId = 771193;
name = "Matej Urbas";
};
uri-canva = {
email = "uri@canva.com";
github = "uri-canva";
githubId = 33242106;
name = "Uri Baghin";
};
urlordjames = {
email = "urlordjames@gmail.com";
github = "urlordjames";
@@ -27887,6 +27916,12 @@
name = "Han Verstraete";
keys = [ { fingerprint = "2145 955E 3F5E 0C95 3458 41B5 11F7 BAEA 8567 43FF"; } ];
};
wenbin-liu = {
name = "wenbin-liu";
email = "wenbin_liu@outlook.com";
github = "wenbin-liu";
githubId = 25171141;
};
wenjinnn = {
name = "wenjin";
email = "hewenjin94@outlook.com";
@@ -28779,6 +28814,12 @@
githubId = 40352765;
name = "Yoctocell";
};
YodaDaCoda = {
email = "pickeringw@gmail.com";
github = "YodaDaCoda";
githubId = 365349;
name = "William Brockhus";
};
yogansh = {
email = "yogansh@yogansh.tech";
github = "YoganshSharma";
@@ -29004,12 +29045,6 @@
githubId = 62440012;
name = "Zain Kergaye";
};
zakame = {
email = "zakame@zakame.net";
github = "zakame";
githubId = 110625;
name = "Zak B. Elep";
};
zakkor = {
email = "edward.dalbon@gmail.com";
github = "zakkor";
+4 -7
View File
@@ -79,7 +79,6 @@ with lib.maintainers;
bazel = {
members = [
mboes
uri-canva
cbley
olebedev
groodt
@@ -342,6 +341,10 @@ with lib.maintainers;
enableFeatureFreezePing = true;
};
feel-co = {
github = "feel-co";
};
flutter = {
enableFeatureFreezePing = false;
github = "flutter";
@@ -396,7 +399,6 @@ with lib.maintainers;
gitlab = {
members = [
globin
krav
leona
talyz
@@ -491,7 +493,6 @@ with lib.maintainers;
jetbrains = {
members = [
edwtjo
leona
theCapypara
thiagokokada
@@ -531,7 +532,6 @@ with lib.maintainers;
aanderse
cpages
dschrempf
edwtjo
kazenyuk
minijackson
peterhoeg
@@ -547,8 +547,6 @@ with lib.maintainers;
libretro = {
members = [
aanderse
edwtjo
hrdinka
thiagokokada
];
scope = "Maintain Libretro, RetroArch and related packages.";
@@ -788,7 +786,6 @@ with lib.maintainers;
members = [
sgo
marcusramberg
zakame
];
scope = "Maintain the Perl interpreter and Perl packages.";
shortName = "Perl";
@@ -922,7 +922,7 @@ Make sure to also check the many updates in the [Nixpkgs library](#sec-release-2
- [frp](https://github.com/fatedier/frp), a fast reverse proxy to help you
expose a local server behind a NAT or firewall to the Internet. Available as
[services.frp](#opt-services.frp.enable).
`services.frp`.
- [river](https://github.com/riverwm/river), A dynamic tiling wayland
compositor. Available as `programs.river`.
@@ -10,7 +10,11 @@
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
- Create the first release note entry in this section!
- [knot-resolver](https://www.knot-resolver.cz/) in version 6. Available as `services.knot-resolver`. A module for knot-resolver 5 was already available as `services.kresd`.
- [ImmichFrame](https://immichframe.dev/), display your photos from Immich as a digital photo frame. Available as `services.immichframe`.
- [udp-over-tcp](https://github.com/mullvad/udp-over-tcp), a tunnel for proxying UDP traffic over a TCP stream. Available as `services.udp-over-tcp`.
## Backward Incompatibilities {#sec-release-26.05-incompatibilities}
@@ -22,4 +26,6 @@
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
- Create the first release note entry in this section!
- `services.frp` now supports multiple instances through `services.frp.instances` to make it possible to run multiple frp clients or servers at the same time.
- `services.openssh` now supports generating host SSH keys by setting `services.openssh.generateHostKeys = true` while leaving `services.openssh.enable` disabled. This is particularly useful for systems that have no need of an SSH daemon but want SSH host keys for other purposes such as using agenix or sops-nix.
+112
View File
@@ -0,0 +1,112 @@
{
armv6l-linux = {
magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\x00\xff\xfe\xff\xff\xff'';
};
armv7l-linux = {
magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\x00\xff\xfe\xff\xff\xff'';
};
aarch64-linux = {
magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\x00\xff\xfe\xff\xff\xff'';
};
aarch64_be-linux = {
magicOrExtension = ''\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
};
i386-linux = {
magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00'';
mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
};
i486-linux = {
magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00'';
mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
};
i586-linux = {
magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00'';
mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
};
i686-linux = {
magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00'';
mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
};
x86_64-linux = {
magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00'';
mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
};
alpha-linux = {
magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x26\x90'';
mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
};
sparc64-linux = {
magicOrExtension = ''\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
};
sparc-linux = {
magicOrExtension = ''\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x12'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
};
powerpc-linux = {
magicOrExtension = ''\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
};
powerpc64-linux = {
magicOrExtension = ''\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
};
powerpc64le-linux = {
magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15\x00'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\x00'';
};
mips-linux = {
magicOrExtension = ''\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20'';
};
mipsel-linux = {
magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00'';
};
mips64-linux = {
magicOrExtension = ''\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
};
mips64el-linux = {
magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
};
mips64-linuxabin32 = {
magicOrExtension = ''\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20'';
};
mips64el-linuxabin32 = {
magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00'';
};
riscv32-linux = {
magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
};
riscv64-linux = {
magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
};
loongarch64-linux = {
magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02\x01'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\xfc\x00\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
};
wasm32-wasi = {
magicOrExtension = ''\x00asm'';
mask = ''\xff\xff\xff\xff'';
};
wasm64-wasi = {
magicOrExtension = ''\x00asm'';
mask = ''\xff\xff\xff\xff'';
};
s390x-linux = {
magicOrExtension = ''\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x16'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
};
x86_64-windows.magicOrExtension = "MZ";
i686-windows.magicOrExtension = "MZ";
}
+78 -18
View File
@@ -1,12 +1,43 @@
import datetime as dt
import fcntl
import io
import os
import pty
import select
import subprocess
import typing
from pathlib import Path
from test_driver.logger import AbstractLogger
def readline_with_timeout(
readable: typing.IO[str], timeout: dt.timedelta
) -> typing.Generator[str]:
"""
Read a line from `readable` within the given `timeout`, otherwise raises `TimeoutError`.
Note: while the generator is running, `readable` will be in nonblocking mode.
"""
fd = readable.fileno()
og_flags = fcntl.fcntl(fd, fcntl.F_GETFL)
fcntl.fcntl(fd, fcntl.F_SETFL, og_flags | os.O_NONBLOCK)
try:
while True:
ready, _, _ = select.select([readable], [], [], timeout.total_seconds())
if len(ready) == 0:
raise TimeoutError()
# Under the hood, `readline` may read more than one line from the file descriptor,
# so we cannot just return to the `select`, as it may block, despite there being more
# lines buffered. So, read all the lines before returning to the select. This only
# works if the file descriptor is in non-blocking mode!
while line := readable.readline():
yield line
finally:
fcntl.fcntl(fd, fcntl.F_SETFL, og_flags)
class VLan:
"""This class handles a VLAN that the run-vm scripts identify via its
number handles. The network's lifetime equals the object's lifetime.
@@ -33,33 +64,62 @@ class VLan:
os.environ[f"QEMU_VDE_SOCKET_{self.nr}"] = str(self.socket_dir)
self.logger.info("start vlan")
pty_master, pty_slave = pty.openpty()
# The --hub is required for the scenario determined by
# nixos/tests/networking.nix vlan-ping.
# VLAN Tagged traffic (802.1Q) seams to be blocked if a vde_switch is
# used without the hub mode (flood packets to all ports).
self.process = subprocess.Popen(
["vde_switch", "-s", self.socket_dir, "--dirmode", "0700", "--hub"],
stdin=pty_slave,
[
"vde_switch",
"--sock",
self.socket_dir,
"--dirmode",
"0700",
# The --hub is required for the scenario determined by
# nixos/tests/networkd-and-scripted.nix vlan-ping.
# VLAN Tagged traffic (802.1Q) seems to be blocked if a vde_switch is
# used without the hub mode (flood packets to all ports).
"--hub",
],
bufsize=1, # Line buffered.
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
shell=False,
stderr=None, # Do not swallow stderr.
text=True,
)
self.pid = self.process.pid
self.fd = os.fdopen(pty_master, "w")
self.fd.write("version\n")
# TODO: perl version checks if this can be read from
# an if not, dies. we could hang here forever. Fix it.
assert self.process.stdin is not None
self.process.stdin.write("showinfo\n")
# showinfo's output looks like this:
#
# ```
# vde$ showinfo
# 0000 DATA END WITH '.'
# VDE switch V.2.3.3
# (C) Virtual Square Team (coord. R. Davoli) 2005,2006,2007 - GPLv2
#
# pid 82406 MAC 00:ff:62:25:47:55 uptime 45
# .
# 1000 Success
# ```
#
# We read past all the output until we get to the `1000 Success`.
# This serves 2 purposes:
# 1. It's a nice sanity check that `vde_switch` is actually working.
# 2. By the time we're done, `vde_switch` will have created the
# `ctl` socket in `socket_dir`, so we don't have to wait for it to exist.
assert self.process.stdout is not None
self.process.stdout.readline()
if not (self.socket_dir / "ctl").exists():
self.logger.error("cannot start vde_switch")
for line in readline_with_timeout(
self.process.stdout, timeout=dt.timedelta(seconds=5)
):
if "1000 Success" in line:
break
assert (self.socket_dir / "ctl").exists(), "cannot start vde_switch"
self.logger.info(f"running vlan (pid {self.pid}; ctl {self.socket_dir})")
def stop(self) -> None:
self.logger.info(f"kill vlan (pid {self.pid})")
self.fd.close()
assert self.process.stdin is not None
self.process.stdin.close()
self.process.terminate()
+8
View File
@@ -533,6 +533,14 @@ let
units = import ./systemd-network-units.nix { inherit lib systemdUtils; };
};
};
/*
Mapping of systems to magicOrExtension and mask. Mostly taken from:
- https://github.com/cleverca22/nixos-configs/blob/master/qemu.nix
and
- https://github.com/qemu/qemu/blob/master/scripts/qemu-binfmt-conf.sh
*/
binfmtMagics = import ./binfmt-magics.nix;
};
in
utils
+1 -1
View File
@@ -119,7 +119,7 @@ in
pkgs = lib.mkOption {
defaultText = lib.literalExpression ''
import "''${nixos}/.." {
inherit (cfg) config overlays localSystem crossSystem;
inherit (config.nixpkgs) config overlays localSystem crossSystem;
}
'';
type = pkgsType;
+9
View File
@@ -201,6 +201,7 @@
./programs/direnv.nix
./programs/dmrconfig.nix
./programs/droidcam.nix
./programs/dsearch.nix
./programs/dublin-traceroute.nix
./programs/ecryptfs.nix
./programs/environment.nix
@@ -340,6 +341,7 @@
./programs/vivid.nix
./programs/vscode.nix
./programs/wavemon.nix
./programs/wayland/dms-shell.nix
./programs/wayland/dwl.nix
./programs/wayland/gtklock.nix
./programs/wayland/hyprland.nix
@@ -605,6 +607,7 @@
./services/development/zammad.nix
./services/display-managers/cosmic-greeter.nix
./services/display-managers/default.nix
./services/display-managers/dms-greeter.nix
./services/display-managers/gdm.nix
./services/display-managers/greetd.nix
./services/display-managers/lemurs.nix
@@ -648,6 +651,7 @@
./services/hardware/buffyboard.nix
./services/hardware/ddccontrol.nix
./services/hardware/deepcool-digital-linux.nix
./services/hardware/dell-bios-fan-control.nix
./services/hardware/display.nix
./services/hardware/fancontrol.nix
./services/hardware/freefall.nix
@@ -1228,6 +1232,7 @@
./services/networking/keepalived/default.nix
./services/networking/keybase.nix
./services/networking/kismet.nix
./services/networking/knot-resolver.nix
./services/networking/knot.nix
./services/networking/kresd.nix
./services/networking/lambdabot.nix
@@ -1399,6 +1404,7 @@
./services/networking/trickster.nix
./services/networking/twingate.nix
./services/networking/ucarp.nix
./services/networking/udp-over-tcp.nix
./services/networking/umurmur.nix
./services/networking/unbound.nix
./services/networking/unifi.nix
@@ -1628,8 +1634,10 @@
./services/web-apps/icingaweb2/icingaweb2.nix
./services/web-apps/icingaweb2/module-monitoring.nix
./services/web-apps/ifm.nix
./services/web-apps/immich-kiosk.nix
./services/web-apps/immich-public-proxy.nix
./services/web-apps/immich.nix
./services/web-apps/immichframe.nix
./services/web-apps/invidious.nix
./services/web-apps/isso.nix
./services/web-apps/jirafeau.nix
@@ -1727,6 +1735,7 @@
./services/web-apps/suwayomi-server.nix
./services/web-apps/szurubooru.nix
./services/web-apps/trilium.nix
./services/web-apps/tt-rss.nix
./services/web-apps/tuliprox.nix
./services/web-apps/umami.nix
./services/web-apps/vikunja.nix
-1
View File
@@ -9,7 +9,6 @@ let
cfg = config.programs.bandwhich;
in
{
meta.maintainers = with lib.maintainers; [ Br1ght0ne ];
options = {
programs.bandwhich = {
+53
View File
@@ -0,0 +1,53 @@
{
config,
lib,
pkgs,
...
}:
let
inherit (lib)
mkEnableOption
mkOption
mkIf
mkPackageOption
types
;
cfg = config.programs.dsearch;
in
{
options.programs.dsearch = {
enable = mkEnableOption "dsearch, a fast filesystem search service with fuzzy matching";
package = mkPackageOption pkgs "dsearch" { };
systemd = {
enable = mkEnableOption "systemd user service for dsearch" // {
default = true;
};
target = mkOption {
type = types.str;
default = "default.target";
description = ''
The systemd target that will automatically start the dsearch service.
By default, dsearch starts with the user session (`default.target`).
You can change this to `graphical-session.target` if you only want
it to run in graphical sessions.
'';
};
};
};
config = mkIf cfg.enable {
environment.systemPackages = [ cfg.package ];
systemd.packages = [ cfg.package ];
systemd.user.services.dsearch.wantedBy = mkIf cfg.systemd.enable [ cfg.systemd.target ];
};
meta.maintainers = with lib.maintainers; [ luckshiba ];
}
+1
View File
@@ -10,6 +10,7 @@ in
{
meta.maintainers = with lib.maintainers; [
NotAShelf
mdaniels5757
viperML
];
+6 -1
View File
@@ -29,7 +29,12 @@ let
setw -g pane-base-index ${toString cfg.baseIndex}
set -g history-limit ${toString cfg.historyLimit}
${optionalString cfg.newSession "new-session"}
${optionalString cfg.newSession ''
# Use -A to make new-session idempotent: attach if session "0" exists,
# otherwise create it. This prevents duplicate sessions when multiple
# configs (e.g., system and user) both enable newSession.
new-session -A -s 0
''}
${optionalString cfg.reverseSplit ''
bind v split-window -h
@@ -0,0 +1,202 @@
{
config,
lib,
pkgs,
...
}:
let
inherit (lib)
mkEnableOption
mkOption
mkIf
mkPackageOption
types
optional
optionals
;
cfg = config.programs.dms-shell;
optionalPackages =
optionals cfg.enableSystemMonitoring [ pkgs.dgop ]
++ optionals cfg.enableClipboard [
pkgs.cliphist
pkgs.wl-clipboard
]
++ optionals cfg.enableVPN [
pkgs.glib
pkgs.networkmanager
]
++ optional cfg.enableBrightnessControl pkgs.brightnessctl
++ optional cfg.enableColorPicker pkgs.hyprpicker
++ optional cfg.enableDynamicTheming pkgs.matugen
++ optional cfg.enableAudioWavelength pkgs.cava
++ optional cfg.enableCalendarEvents pkgs.khal
++ optional cfg.enableSystemSound pkgs.kdePackages.qtmultimedia;
in
{
options.programs.dms-shell = {
enable = mkEnableOption "DankMaterialShell, a complete desktop shell for Wayland compositors";
package = mkPackageOption pkgs "dms-shell" { };
systemd = {
target = mkOption {
type = types.str;
default = "graphical-session.target";
description = ''
The systemd target that will automatically start the DankMaterialShell service.
Common targets include:
- `graphical-session.target` for most desktop environments
- `wayland-session.target` for Wayland-specific sessions
'';
};
restartIfChanged = mkOption {
type = types.bool;
default = true;
description = ''
Whether to restart the dms.service when the DankMaterialShell package or
configuration changes. This ensures the latest version is always running
after a system rebuild.
'';
};
};
enableSystemMonitoring = mkOption {
type = types.bool;
default = true;
description = ''
Whether to install dependencies required for system monitoring widgets.
This includes process list viewers and system resource monitors.
Requires: dgop
'';
};
enableClipboard = mkOption {
type = types.bool;
default = true;
description = ''
Whether to install dependencies required for clipboard management widgets.
This enables clipboard history and clipboard manager functionality.
Requires: cliphist, wl-clipboard
'';
};
enableVPN = mkOption {
type = types.bool;
default = true;
description = ''
Whether to install dependencies required for VPN widgets.
This enables VPN status monitoring and management through NetworkManager.
Requires: glib, networkmanager
'';
};
enableBrightnessControl = mkOption {
type = types.bool;
default = true;
description = ''
Whether to install dependencies required for brightness and backlight control.
This enables screen brightness adjustment widgets.
Requires: brightnessctl
'';
};
enableColorPicker = mkOption {
type = types.bool;
default = true;
description = ''
Whether to install dependencies required for color picking functionality.
This enables on-screen color picker tools.
Requires: hyprpicker
'';
};
enableDynamicTheming = mkOption {
type = types.bool;
default = true;
description = ''
Whether to install dependencies required for dynamic theming support.
This enables automatic theme generation based on wallpapers and other sources.
Requires: matugen
'';
};
enableAudioWavelength = mkOption {
type = types.bool;
default = true;
description = ''
Whether to install dependencies required for audio wavelength visualization.
This enables audio spectrum and waveform visualizer widgets.
Requires: cava
'';
};
enableCalendarEvents = mkOption {
type = types.bool;
default = true;
description = ''
Whether to install dependencies required for calendar events support.
This enables calendar widgets that display events and reminders via khal.
Requires: khal
'';
};
enableSystemSound = mkOption {
type = types.bool;
default = true;
description = ''
Whether to install dependencies required for system sound support.
This enables audio playback for system notifications and events.
Requires: qtmultimedia
'';
};
quickshell = {
package = mkPackageOption pkgs "quickshell" { };
};
};
config = mkIf cfg.enable {
environment.etc."xdg/quickshell/dms".source = "${cfg.package}/share/quickshell/dms";
systemd.packages = [ cfg.package ];
systemd.user.services.dms = {
wantedBy = [ cfg.systemd.target ];
restartTriggers = optional cfg.systemd.restartIfChanged "${cfg.package}/share/quickshell/dms";
path = lib.mkForce [ ];
};
environment.systemPackages = [
cfg.package
cfg.quickshell.package
pkgs.ddcutil
pkgs.libsForQt5.qt5ct
pkgs.kdePackages.qt6ct
]
++ optionalPackages;
fonts.packages = with pkgs; [
fira-code
inter
material-symbols
];
hardware.graphics.enable = lib.mkDefault true;
};
meta.maintainers = with lib.maintainers; [ luckshiba ];
}
+3 -2
View File
@@ -23,9 +23,10 @@ in
{
environment.systemPackages = [
cfg.package
]
];
# Required for xdg-desktop-portal-gnome's FileChooser to work properly
++ lib.optionals cfg.useNautilus [
services.dbus.packages = lib.mkIf cfg.useNautilus [
pkgs.nautilus
];
-3
View File
@@ -290,9 +290,6 @@ in
(mkRemovedOptionModule [ "services" "sourcehut" ] ''
The sourcehut packages and the corresponding module have been removed due to being broken and unmaintained.
'')
(mkRemovedOptionModule [ "services" "tt-rss" ] ''
The tt-rss package and module have been removed, since upstream development ceased 2025-11-01 and the source is no longer available officially.
'')
(mkRemovedOptionModule [ "services" "tvheadend" ]
"The tvheadend package and the corresponding module have been removed as nobody was willing to maintain them and they were stuck on an unmaintained version that required FFmpeg 4; please see https://github.com/NixOS/nixpkgs/pull/332259 if you are interested in maintaining a newer version."
)
-1
View File
@@ -206,5 +206,4 @@ in
) cfg.params;
};
meta.maintainers = with lib.maintainers; [ ekleog ];
}
@@ -128,11 +128,9 @@ in
lib.mkIf config.confinement.enable {
serviceConfig = {
ReadOnlyPaths = [ "+/" ];
RuntimeDirectory = [ "confinement/${mkPathSafeName name}" ];
RootDirectory = "/run/confinement/${mkPathSafeName name}";
InaccessiblePaths = [
"-+/run/confinement/${mkPathSafeName name}"
];
RuntimeDirectory = [ "confinement/%n" ];
RootDirectory = "/run/confinement/%n";
InaccessiblePaths = [ "-+/run/confinement/%n" ];
PrivateMounts = lib.mkDefault true;
# https://github.com/NixOS/nixpkgs/issues/14645 is a future attempt
+24 -1
View File
@@ -36,6 +36,7 @@ let
a = cfg.tcp.anonymousClients.allowedIpRanges;
in
lib.optional (a != [ ]) ''auth-ip-acl=${lib.concatStringsSep ";" a}'';
port = lib.optional (!(isNull cfg.tcp.port)) "port=${toString cfg.tcp.port}";
in
pkgs.writeTextFile {
name = "default.pa";
@@ -44,7 +45,7 @@ let
${addModuleIf cfg.zeroconf.publish.enable "module-zeroconf-publish"}
${addModuleIf cfg.zeroconf.discovery.enable "module-zeroconf-discover"}
${addModuleIf cfg.tcp.enable (
lib.concatStringsSep " " ([ "module-native-protocol-tcp" ] ++ allAnon ++ ipAnon)
lib.concatStringsSep " " ([ "module-native-protocol-tcp" ] ++ allAnon ++ ipAnon ++ port)
)}
${addModuleIf config.services.jack.jackd.enable "module-jack-sink"}
${addModuleIf config.services.jack.jackd.enable "module-jack-source"}
@@ -205,6 +206,19 @@ in
# TODO: enable by default?
tcp = {
enable = lib.mkEnableOption "tcp streaming support";
openFirewall = lib.mkEnableOption "Open firewall for the specified port";
port = lib.mkOption {
type = lib.types.nullOr lib.types.port;
description = ''
TCP connection port. The default `null` value, means
pulseaudio will try to use the default 4713 port, but if it is
occupied, it will fallback to a random port.
'';
# Per https://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/User/Network/#directconnection
example = 4713;
default = null;
};
anonymousClients = {
allowAll = lib.mkEnableOption "all anonymous clients to stream to the server";
@@ -226,6 +240,12 @@ in
config = lib.mkIf cfg.enable (
lib.mkMerge [
{
assertions = [
{
assertion = cfg.tcp.openFirewall -> (!isNull cfg.tcp.port);
message = "If you wish to open the firewall for the Pulseaudio's tcp.port, set the port explicitly";
}
];
environment.etc."pulse/client.conf".source = clientConf;
environment.systemPackages = [ overriddenPackage ];
@@ -280,6 +300,9 @@ in
services.avahi.publish.enable = true;
services.avahi.publish.userServices = true;
})
(lib.mkIf cfg.tcp.openFirewall {
networking.firewall.allowedTCPPorts = [ cfg.tcp.port ];
})
(lib.mkIf (!cfg.systemWide) {
environment.etc = {
+2 -2
View File
@@ -479,12 +479,12 @@ in
isSystemUser = true;
group = redisName name;
}
) enabledServers;
) (lib.filterAttrs (name: conf: conf.user == redisName name) enabledServers);
users.groups = lib.mapAttrs' (
name: conf:
lib.nameValuePair (redisName name) {
}
) enabledServers;
) (lib.filterAttrs (name: conf: conf.group == redisName name) enabledServers);
systemd.services = lib.mapAttrs' (
name: conf:
@@ -229,6 +229,7 @@ in
SystemCallFilter = [
"@system-service"
"~@privileged"
"mincore"
];
};
@@ -328,9 +328,19 @@ in
enable = true;
package = kdePackages.kwallet-pam;
};
# "kde" must not have fingerprint authentication otherwise it can block password login.
# See https://github.com/NixOS/nixpkgs/issues/239770 and https://invent.kde.org/plasma/kscreenlocker/-/merge_requests/163.
fprintAuth = false;
p11Auth = false;
};
kde-fingerprint = lib.mkIf config.services.fprintd.enable {
fprintAuth = true;
p11Auth = false;
};
kde-smartcard = lib.mkIf config.security.pam.p11.enable {
p11Auth = true;
fprintAuth = false;
};
kde-fingerprint = lib.mkIf config.services.fprintd.enable { fprintAuth = true; };
kde-smartcard = lib.mkIf config.security.pam.p11.enable { p11Auth = true; };
};
security.wrappers = {
@@ -0,0 +1,261 @@
{
config,
lib,
pkgs,
...
}:
let
inherit (lib)
types
mkEnableOption
mkOption
mkIf
mkDefault
mkPackageOption
literalExpression
getExe
makeBinPath
optionalString
concatMapStringsSep
;
cfg = config.services.displayManager.dms-greeter;
cfgAutoLogin = config.services.displayManager.autoLogin;
greeterScript = pkgs.writeShellScriptBin "dms-greeter-start" ''
export PATH=$PATH:${
makeBinPath [
cfg.quickshell.package
config.programs.${cfg.compositor.name}.package
]
}
exec ${cfg.package}/share/quickshell/dms/Modules/Greetd/assets/dms-greeter \
--command ${cfg.compositor.name} \
-p ${cfg.package}/share/quickshell/dms \
--cache-dir /var/lib/dms-greeter \
${
optionalString (
cfg.compositor.customConfig != ""
) "-C ${pkgs.writeText "dms-greeter-compositor-config" cfg.compositor.customConfig}"
} \
${optionalString cfg.logs.save ">> ${cfg.logs.path} 2>&1"}
'';
configFilesFromHome =
if cfg.configHome != null then
[
"${cfg.configHome}/.config/DankMaterialShell/settings.json"
"${cfg.configHome}/.local/state/DankMaterialShell/session.json"
"${cfg.configHome}/.cache/DankMaterialShell/dms-colors.json"
]
else
[ ];
in
{
options.services.displayManager.dms-greeter = {
enable = mkEnableOption "DankMaterialShell greeter";
package = mkPackageOption pkgs "dms-shell" { };
compositor = {
name = mkOption {
type = types.enum [
"niri"
"hyprland"
"sway"
];
example = "niri";
description = ''
The Wayland compositor to run the greeter in.
The specified compositor must be enabled via its corresponding
`programs.<compositor>.enable` option.
Supported compositors:
- niri: A scrollable-tiling Wayland compositor
- hyprland: A dynamic tiling Wayland compositor
- sway: An i3-compatible Wayland compositor
'';
};
customConfig = mkOption {
type = types.lines;
default = "";
example = ''
# Niri example
input {
keyboard {
xkb {
layout "us"
}
}
}
'';
description = ''
Custom compositor configuration to use for the greeter session.
This configuration is written to a file and passed to the compositor
when launching the greeter. The format and available options depend
on the selected compositor.
Leave empty to use the system's default compositor configuration.
'';
};
};
configFiles = mkOption {
type = types.listOf types.path;
default = [ ];
example = literalExpression ''
[
"/home/user/.config/DankMaterialShell/settings.json"
"/home/user/.local/state/DankMaterialShell/session.json"
]
'';
description = ''
List of DankMaterialShell configuration files to copy into the greeter
data directory at `/var/lib/dms-greeter`.
This is useful for preserving user preferences like wallpapers, themes,
and other settings in the greeter screen.
::: {.tip}
Use {option}`configHome` instead if your configuration files are in
standard XDG locations.
:::
'';
};
configHome = mkOption {
type = types.nullOr types.str;
default = null;
example = "/home/alice";
description = ''
Path to a user's home directory from which to copy DankMaterialShell
configuration files.
When set, the following files will be automatically copied to the greeter:
- `~/.config/DankMaterialShell/settings.json`
- `~/.local/state/DankMaterialShell/session.json`
- `~/.cache/DankMaterialShell/dms-colors.json`
If your configuration files are in non-standard locations, use the
{option}`configFiles` option instead.
'';
};
quickshell = {
package = mkPackageOption pkgs "quickshell" { };
};
logs = {
save = mkEnableOption "saving logs from the DMS greeter to a file";
path = mkOption {
type = types.path;
default = "/tmp/dms-greeter.log";
example = "/var/log/dms-greeter.log";
description = ''
File path where DMS greeter logs will be saved.
This is useful for debugging greeter issues. Logs will include
output from both the greeter and the compositor.
'';
};
};
};
config = mkIf cfg.enable {
assertions = [
{
assertion = config.programs.${cfg.compositor.name}.enable or false;
message = ''
DankMaterialShell greeter: The compositor "${cfg.compositor.name}" is not enabled.
Please enable the compositor via:
programs.${cfg.compositor.name}.enable = true;
'';
}
];
services.greetd = {
enable = true;
settings = {
default_session = {
user = "dms-greeter";
command = getExe greeterScript;
};
initial_session = mkIf (cfgAutoLogin.enable && (cfgAutoLogin.user != null)) {
inherit (cfgAutoLogin) user command;
};
};
};
environment.systemPackages = [ cfg.package ];
fonts.packages = with pkgs; [
fira-code
inter
material-symbols
];
systemd.tmpfiles.settings."10-dms-greeter"."/var/lib/dms-greeter".d = {
user = "dms-greeter";
group = "dms-greeter";
mode = "0750";
};
systemd.services.greetd.preStart =
let
allConfigFiles = cfg.configFiles ++ configFilesFromHome;
in
''
set -euo pipefail
cd /var/lib/dms-greeter || exit 1
${concatMapStringsSep "\n" (f: ''
if [[ -f "${f}" ]]; then
cp "${f}" . || true
fi
'') allConfigFiles}
# Handle session.json wallpaper path
if [[ -f session.json ]]; then
if wallpaper=$(${getExe pkgs.jq} -r '.wallpaperPath' session.json 2>/dev/null); then
if [[ -f "$wallpaper" ]]; then
cp "$wallpaper" wallpaper.jpg || true
mv session.json session.orig.json
${getExe pkgs.jq} '.wallpaperPath = "/var/lib/dms-greeter/wallpaper.jpg"' \
session.orig.json > session.json || true
fi
fi
fi
# Rename colors file if it exists
[[ -f dms-colors.json ]] && mv dms-colors.json colors.json || true
# Fix ownership of all files
chown -R "dms-greeter:dms-greeter" . || true
'';
users.groups.dms-greeter = { };
users.users.dms-greeter = {
description = "DankMaterialShell greeter user";
isSystemUser = true;
home = "/var/lib/dms-greeter";
homeMode = "0750";
createHome = true;
group = "dms-greeter";
extraGroups = [ "video" ];
};
security.pam.services.dms-greeter = { };
hardware.graphics.enable = mkDefault true;
services.libinput.enable = mkDefault true;
};
meta.maintainers = with lib.maintainers; [ luckshiba ];
}
@@ -0,0 +1,49 @@
{
config,
pkgs,
lib,
...
}:
let
cfg = config.services.hardware.dell-bios-fan-control;
in
{
meta.maintainers = with lib.maintainers; [ rickyelopez ];
options.services.hardware.dell-bios-fan-control = {
enable = lib.mkEnableOption "One-shot service to disable dell bios fan control on startup";
package = lib.mkPackageOption pkgs "dell-bios-fan-control" { };
};
config = lib.mkIf cfg.enable {
boot.kernelModules = [ "i8k" ];
environment.systemPackages = [ cfg.package ];
# see ref in aur: https://aur.archlinux.org/cgit/aur.git/tree/dell-bios-fan-control.service?h=dell-bios-fan-control-git
systemd.services.dell-bios-fan-control = {
description = "Disables BIOS control of fans at boot.";
wants = [ "dell-bios-fan-control-resume.service" ];
wantedBy = [ "multi-user.target" ];
before = [ "i8kmon.service" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
ExecStart = "${lib.getExe cfg.package} 0";
ExecStop = "${lib.getExe cfg.package} 1";
};
};
# see ref in aur: https://aur.archlinux.org/cgit/aur.git/tree/dell-bios-fan-control-resume.service?h=dell-bios-fan-control-git
systemd.services.dell-bios-fan-control-resume = {
description = "Restart dell-bios-fan-control on resume.";
wants = [ "dell-bios-fan-control.service" ];
wantedBy = [ "suspend.target" ];
after = [ "suspend.target" ];
serviceConfig = {
Type = "oneshot";
# re: sleep, see: https://github.com/NixOS/nixpkgs/pull/439978#discussion_r2404279441
ExecStartPre = "${pkgs.coreutils}/bin/sleep 30";
ExecStart = "${config.systemd.package}/bin/systemctl restart dell-bios-fan-control.service";
};
};
};
}
@@ -189,7 +189,7 @@
];
services.udev.extraRules = ''
KERNEL=="nvidia", RUN+="${lib.getExe' config.systemd.package "systemctl"} restart nvidia-container-toolkit-cdi-generator.service'"
KERNEL=="nvidia", RUN+="${lib.getExe' config.systemd.package "systemctl"} --no-block restart nvidia-container-toolkit-cdi-generator.service'"
'';
virtualisation = {
@@ -42,6 +42,20 @@ in
options = {
enable = mkEnableOption "Wyoming Piper server";
zeroconf = {
enable = mkEnableOption "zeroconf discovery" // {
default = true;
};
name = mkOption {
type = str;
default = "piper";
description = ''
The advertised name for zeroconf discovery.
'';
};
};
voice = mkOption {
type = str;
example = "en-us-ryan-medium";
@@ -95,10 +109,6 @@ in
apply = toString;
};
streaming = mkEnableOption "audio streaming on sentence boundaries" // {
default = true;
};
useCUDA = mkOption {
type = bool;
default = pkgs.config.cudaSupport;
@@ -168,8 +178,9 @@ in
"--noise-w-scale"
options.noiseWidth
]
++ lib.optionals options.streaming [
"--streaming"
++ lib.optionals options.zeroconf.enable [
"--zeroconf"
options.zeroconf.name
]
++ lib.optionals options.useCUDA [
"--use-cuda"
@@ -114,6 +114,7 @@ in
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
"AF_NETLINK"
];
RestrictNamespaces = true;
RestrictRealtime = true;
@@ -119,5 +119,4 @@ in
};
};
meta.maintainers = with lib.maintainers; [ ekleog ];
}
@@ -148,5 +148,4 @@ in
};
};
meta.maintainers = with lib.maintainers; [ ekleog ];
}
@@ -13,6 +13,7 @@ let
settingsFile = "${dataDir}/config.yaml";
settingsFileUnformatted = format.generate "discord-config-unsubstituted.yaml" cfg.settings;
default_token = "This value is generated when generating the registration";
in
{
options = {
@@ -415,66 +416,61 @@ in
rm -f '${settingsFile}'
old_umask=$(umask)
umask 0177
envsubst \
-o '${settingsFile}' \
-i '${settingsFileUnformatted}'
config_has_tokens=$(yq '.appservice | has("as_token") and has("hs_token")' '${settingsFile}')
registration_already_exists=$([[ -f '${registrationFile}' ]] && echo "true" || echo "false")
echo "There are tokens in the config: $config_has_tokens"
echo "Registration already existed: $registration_already_exists"
# tokens not configured from config/environment file, and registration file
# is already generated, override tokens in config to make sure they are not lost
if [[ $config_has_tokens == "false" && $registration_already_exists == "true" ]]; then
echo "Copying as_token, hs_token from registration into configuration"
yq -sY '.[0].appservice.as_token = .[1].as_token
| .[0].appservice.hs_token = .[1].hs_token
| .[0]' '${settingsFile}' '${registrationFile}' \
> '${settingsFile}.tmp'
envsubst -o '${settingsFile}' -i '${settingsFileUnformatted}'
# Check if config has tokens or uses defaults
as_token=$(yq -r '.appservice.as_token' '${settingsFile}')
hs_token=$(yq -r '.appservice.hs_token' '${settingsFile}')
config_has_tokens=$([[ "$as_token" != "${default_token}" && "$as_token" != "null" && "$hs_token" != "${default_token}" && "$hs_token" != "null" ]] && echo "true" || echo "false")
if [[ -f '${registrationFile}' ]]; then
registration_exists="true"
else
registration_exists="false"
fi
echo "Config has tokens: $config_has_tokens, Registration exists: $registration_exists"
# If config has default tokens but registration exists, restore tokens from registration
if [[ $config_has_tokens == "false" && $registration_exists == "true" ]]; then
echo "Restoring tokens from existing registration"
yq -sY '.[0].appservice.as_token = .[1].as_token | .[0].appservice.hs_token = .[1].hs_token | .[0]' \
'${settingsFile}' '${registrationFile}' > '${settingsFile}.tmp'
mv '${settingsFile}.tmp' '${settingsFile}'
fi
# make sure --generate-registration does not affect config.yaml
# If config has default tokens and no registration exists, generate new tokens
if [[ $config_has_tokens == "false" && $registration_exists == "false" ]]; then
echo "Generating new tokens for first-time setup"
# Generate random tokens (64 character alphanumeric strings)
new_as_token=$(LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 64)
new_hs_token=$(LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 64)
# Save generated tokens to config
yq -Y ".appservice.as_token = \"$new_as_token\" | .appservice.hs_token = \"$new_hs_token\"" \
'${settingsFile}' > '${settingsFile}.tmp'
mv '${settingsFile}.tmp' '${settingsFile}'
# Verify tokens were replaced
if [[ $(yq -r '.appservice.as_token' '${settingsFile}') == "${default_token}" ]]; then
echo "ERROR: Failed to replace default tokens"
exit 1
fi
echo "Successfully generated and saved new tokens"
fi
# Generate registration file with tokens from config
cp '${settingsFile}' '${settingsFile}.tmp'
echo "Generating registration file"
mautrix-discord \
--generate-registration \
--config='${settingsFile}.tmp' \
--registration='${registrationFile}'
mautrix-discord --generate-registration --config='${settingsFile}.tmp' --registration='${registrationFile}'
rm '${settingsFile}.tmp'
# no tokens configured, and new were just generated by generate registration for first time
if [[ $config_has_tokens == "false" && $registration_already_exists == "false" ]]; then
echo "Copying newly generated as_token, hs_token from registration into configuration"
yq -sY '.[0].appservice.as_token = .[1].as_token
| .[0].appservice.hs_token = .[1].hs_token
| .[0]' '${settingsFile}' '${registrationFile}' \
> '${settingsFile}.tmp'
mv '${settingsFile}.tmp' '${settingsFile}'
fi
# make sure --generate-registration does not affect config.yaml
cp '${settingsFile}' '${settingsFile}.tmp'
echo "Generating registration file"
mautrix-discord \
--generate-registration \
--config='${settingsFile}.tmp' \
--registration='${registrationFile}'
rm '${settingsFile}.tmp'
# no tokens configured, and new were just generated by generate registration for first time
if [[ $config_has_tokens == "false" && $registration_already_exists == "false" ]]; then
echo "Copying newly generated as_token, hs_token from registration into configuration"
yq -sY '.[0].appservice.as_token = .[1].as_token
| .[0].appservice.hs_token = .[1].hs_token
| .[0]' '${settingsFile}' '${registrationFile}' \
> '${settingsFile}.tmp'
mv '${settingsFile}.tmp' '${settingsFile}'
fi
# Make sure correct tokens are in the registration file
if [[ $config_has_tokens == "true" || $registration_already_exists == "true" ]]; then
echo "Copying as_token, hs_token from configuration to the registration file"
yq -sY '.[1].as_token = .[0].appservice.as_token
| .[1].hs_token = .[0].appservice.hs_token
| .[1]' '${settingsFile}' '${registrationFile}' \
> '${registrationFile}.tmp'
mv '${registrationFile}.tmp' '${registrationFile}'
fi
# Ensure registration file has the same tokens as config (mautrix-discord may regenerate them)
yq -sY '.[1].as_token = .[0].appservice.as_token | .[1].hs_token = .[0].appservice.hs_token | .[1]' \
'${settingsFile}' '${registrationFile}' > '${registrationFile}.tmp'
mv '${registrationFile}.tmp' '${registrationFile}'
umask $old_umask
chown :mautrix-discord-registration '${registrationFile}'
chmod 640 '${registrationFile}'
+1 -1
View File
@@ -340,7 +340,7 @@ in
};
mailer = {
ENABLED = true;
MAILER_TYPE = "sendmail";
PROTOCOL = "sendmail";
FROM = "do-not-reply@example.org";
SENDMAIL_PATH = "''${pkgs.system-sendmail}/bin/sendmail";
};
+1 -1
View File
@@ -50,7 +50,7 @@ in
- `ollama`: default behavior; usually equivalent to `ollama-cpu`
- if `nixpkgs.config.rocmSupport` is enabled, is equivalent to `ollama-rocm`
- if `nixpkgs.config.cudaSupport` is enabled, is equivalent to `ollama-cuda`
- otherwise defaults to `false`
- otherwise defaults to `ollama-cpu`
- `ollama-cpu`: disable GPU; only use CPU
- `ollama-rocm`: supported by most modern AMD GPUs
- may require overriding gpu type with `services.ollama.rocmOverrideGfx`
+1 -1
View File
@@ -56,7 +56,7 @@ in
'';
description = ''
Extra environment variables for Open-WebUI.
For more details see <https://docs.openwebui.com/getting-started/advanced-topics/env-configuration/>
For more details see <https://docs.openwebui.com/getting-started/env-configuration>
'';
};
@@ -642,7 +642,7 @@ in
let
nginxHasSSL =
with config.services.nginx.virtualHosts."${cfg.hostname}";
onlySSL || enableSSL || addSSL || forceSSL;
onlySSL || addSSL || forceSSL;
in
''
set -euo pipefail
@@ -6,7 +6,6 @@
...
}:
let
inherit (lib) maintainers;
inherit (lib.meta) getExe;
inherit (lib.modules) mkIf mkMerge;
inherit (lib.options)
@@ -205,6 +204,7 @@ in
systemd.services.scrutiny = {
description = "Hard Drive S.M.A.R.T Monitoring, Historical Trends & Real World Failure Thresholds";
enableStrictShellChecks = true;
wantedBy = [ "multi-user.target" ];
after = [ "network.target" ] ++ lib.optional cfg.influxdb.enable "influxdb2.service";
wants = lib.optional cfg.influxdb.enable "influxdb2.service";
@@ -217,7 +217,7 @@ in
${genJqSecretsReplacementSnippet cfg.settings "/run/scrutiny/config.yaml"}
'';
postStart = ''
for i in $(seq 300); do
for _ in $(seq 300); do
if "${lib.getExe pkgs.curl}" --fail --silent --head "http://${cfg.settings.web.listen.host}:${toString cfg.settings.web.listen.port}" >/dev/null; then
echo "Scrutiny is ready (port is open)"
exit 0
@@ -251,6 +251,7 @@ in
systemd = {
services.scrutiny-collector = {
description = "Scrutiny Collector Service";
enableStrictShellChecks = true;
after = lib.optional cfg.enable "scrutiny.service";
wants = lib.optional cfg.enable "scrutiny.service";
environment = {
@@ -20,11 +20,11 @@ let
${lib.optionalString (cfg.username != "") "login=${cfg.username}"}
${
if cfg.protocol == "nsupdate" then
"/run/${RuntimeDirectory}/ddclient.key"
"password=/run/${RuntimeDirectory}/ddclient.key"
else if (cfg.passwordFile != null) then
"password=@password_placeholder@"
else if (cfg.secretsFile != null) then
"@secrets_placeholder@"
"password=@secrets_placeholder@"
else
""
}
+110 -75
View File
@@ -7,95 +7,130 @@
let
cfg = config.services.frp;
settingsFormat = pkgs.formats.toml { };
configFile = settingsFormat.generate "frp.toml" cfg.settings;
isClient = (cfg.role == "client");
isServer = (cfg.role == "server");
enabledInstances = lib.filterAttrs (name: conf: conf.enable) cfg.instances;
in
{
imports = [
(lib.mkRenamedOptionModule
[ "services" "frp" "enable" ]
[ "services" "frp" "instances" "" "enable" ]
)
(lib.mkRenamedOptionModule [ "services" "frp" "role" ] [ "services" "frp" "instances" "" "role" ])
(lib.mkRenamedOptionModule
[ "services" "frp" "settings" ]
[ "services" "frp" "instances" "" "settings" ]
)
];
options = {
services.frp = {
enable = lib.mkEnableOption "frp";
instances = lib.mkOption {
type = lib.types.attrsOf (
lib.types.submodule {
options = {
enable = lib.mkEnableOption "frp";
package = lib.mkPackageOption pkgs "frp" { };
role = lib.mkOption {
type = lib.types.enum [
"server"
"client"
];
description = ''
The frp consists of `client` and `server`. The server is usually
deployed on the machine with a public IP address, and
the client is usually deployed on the machine
where the Intranet service to be penetrated resides.
'';
};
role = lib.mkOption {
type = lib.types.enum [
"server"
"client"
];
description = ''
The frp consists of `client` and `server`. The server is usually
deployed on the machine with a public IP address, and
the client is usually deployed on the machine
where the Intranet service to be penetrated resides.
'';
};
settings = lib.mkOption {
type = settingsFormat.type;
settings = lib.mkOption {
type = settingsFormat.type;
default = { };
description = ''
Frp configuration, for configuration options
see the example of [client](https://github.com/fatedier/frp/blob/dev/conf/frpc_full_example.toml)
or [server](https://github.com/fatedier/frp/blob/dev/conf/frps_full_example.toml) on github.
'';
example = {
serverAddr = "x.x.x.x";
serverPort = 7000;
proxies = [
{
name = "ssh";
type = "tcp";
localIP = "127.0.0.1";
localPort = 22;
remotePort = 6000;
}
];
};
};
};
}
);
default = { };
description = ''
Frp configuration, for configuration options
see the example of [client](https://github.com/fatedier/frp/blob/dev/conf/frpc_full_example.toml)
or [server](https://github.com/fatedier/frp/blob/dev/conf/frps_full_example.toml) on github.
Frp instances.
'';
example = {
serverAddr = "x.x.x.x";
serverPort = 7000;
};
};
package = lib.mkPackageOption pkgs "frp" { };
};
};
config =
let
serviceCapability = lib.optionals isServer [ "CAP_NET_BIND_SERVICE" ];
executableFile = if isClient then "frpc" else "frps";
in
lib.mkIf cfg.enable {
systemd.services = {
frp = {
wants = lib.optionals isClient [ "network-online.target" ];
after = if isClient then [ "network-online.target" ] else [ "network.target" ];
wantedBy = [ "multi-user.target" ];
description = "A fast reverse proxy frp ${cfg.role}";
serviceConfig = {
Type = "simple";
Restart = "on-failure";
RestartSec = 15;
ExecStart = "${cfg.package}/bin/${executableFile} --strict_config -c ${configFile}";
DynamicUser = true;
# Hardening
CapabilityBoundingSet = serviceCapability;
AmbientCapabilities = serviceCapability;
PrivateDevices = true;
ProtectHostname = true;
ProtectClock = true;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectKernelLogs = true;
ProtectControlGroups = true;
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
]
++ lib.optionals isClient [ "AF_UNIX" ];
LockPersonality = true;
MemoryDenyWriteExecute = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
PrivateMounts = true;
SystemCallArchitectures = "native";
SystemCallFilter = [ "@system-service" ];
}
// lib.optionalAttrs isServer {
StateDirectory = "frp";
StateDirectoryMode = "0700";
UMask = "0007";
};
config = lib.mkIf (enabledInstances != { }) {
systemd.services = lib.mapAttrs' (
instance: options:
let
serviceName = "frp" + lib.optionalString (instance != "") ("-" + instance);
configFile = settingsFormat.generate "${serviceName}.toml" options.settings;
isClient = (options.role == "client");
isServer = (options.role == "server");
serviceCapability = lib.optionals isServer [ "CAP_NET_BIND_SERVICE" ];
executableFile = if isClient then "frpc" else "frps";
in
lib.nameValuePair serviceName {
wants = lib.optionals isClient [ "network-online.target" ];
after = if isClient then [ "network-online.target" ] else [ "network.target" ];
wantedBy = [ "multi-user.target" ];
description = "A fast reverse proxy frp ${options.role} for instance ${instance}";
serviceConfig = {
Type = "simple";
Restart = "on-failure";
RestartSec = 15;
ExecStart = "${cfg.package}/bin/${executableFile} --strict_config -c ${configFile}";
DynamicUser = true;
# Hardening
CapabilityBoundingSet = serviceCapability;
AmbientCapabilities = serviceCapability;
PrivateDevices = true;
ProtectHostname = true;
ProtectClock = true;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectKernelLogs = true;
ProtectControlGroups = true;
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
]
++ lib.optionals isClient [ "AF_UNIX" ];
LockPersonality = true;
MemoryDenyWriteExecute = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
PrivateMounts = true;
SystemCallArchitectures = "native";
SystemCallFilter = [ "@system-service" ];
}
// lib.optionalAttrs isServer {
StateDirectory = "frp";
StateDirectoryMode = "0700";
UMask = "0007";
};
};
};
}
) enabledInstances;
};
meta.maintainers = with lib.maintainers; [ zaldnoay ];
}
@@ -0,0 +1,160 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.knot-resolver;
# pkgs.writers.yaml_1_1.generate with additional kresctl validate
configFile =
pkgs.runCommandLocal "knot-resolver.yaml"
{
nativeBuildInputs = [ pkgs.remarshal_0_17 ];
value = builtins.toJSON cfg.settings;
passAsFile = [ "value" ];
}
''
json2yaml "$valuePath" "$out"
${cfg.managerPackage}/bin/kresctl validate "$out"
'';
in
{
meta.maintainers = [
lib.maintainers.vcunat # upstream developer
]
++ lib.teams.flyingcircus.members;
###### interface
options.services.knot-resolver = {
enable = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Whether to enable knot-resolver (version 6) domain name server.
DNSSEC validation is turned on by default.
If you want to use knot-resolver 5, please use services.kresd.
'';
};
package = lib.mkPackageOption pkgs "knot-resolver_6" {
example = "knot-resolver_6.override { extraFeatures = true; }";
};
managerPackage = lib.mkPackageOption pkgs "knot-resolver-manager_6" { };
settings = lib.mkOption {
type = lib.types.submodule {
freeformType = (pkgs.formats.yaml { }).type;
options = {
network.listen = lib.mkOption {
type = lib.types.listOf (
lib.types.submodule {
freeformType = (pkgs.formats.yaml { }).type;
}
);
description = "List of interfaces to listen to and its configuration.";
default = [
{
interface = [ "127.0.0.1" ];
kind = "dns";
freebind = false;
}
]
++ lib.optionals config.networking.enableIPv6 [
{
interface = [ "::1" ];
kind = "dns";
freebind = false;
}
];
defaultText = lib.literalExpression ''
[
{
interface = [ "127.0.0.1" ];
kind = "dns";
freebind = false;
}
]
++ lib.optionals config.networking.enableIPv6 [
{
interface = [ "::1" ];
kind = "dns";
freebind = false;
}
];
'';
};
workers = lib.mkOption {
type = lib.types.oneOf [
(lib.types.enum [ "auto" ])
lib.types.ints.unsigned
];
default = 1;
description = ''
The number of running kresd (Knot Resolver daemon) workers. If set to 'auto', it is equal to number of CPUs available.
'';
};
};
};
default = { };
description = ''
Nix-based (RFC 42) configuration for Knot Resolver.
For configuration reference (described as YAML) see
<https://www.knot-resolver.cz/documentation/latest/config-overview.html>
'';
};
};
###### implementation
config = lib.mkIf cfg.enable {
users.users.knot-resolver = {
isSystemUser = true;
group = "knot-resolver";
description = "Knot-resolver daemon user";
};
users.groups.knot-resolver = { };
networking.resolvconf.useLocalResolver = lib.mkDefault true;
assertions = [
{
assertion = lib.versionAtLeast cfg.package.version "6.0.0";
message = ''
services.knot-resolver only works with knot-resolver 6 or later.
Please use services.kresd for knot-resolver 5.
'';
}
];
environment = {
etc."knot-resolver/config.yaml".source = configFile;
systemPackages = [
# We just avoid including the other binaries, e.g. supervisorctl.
(pkgs.runCommandLocal "knot-resolver-cmds" { } ''
mkdir -p "$out/bin"
ln -s '${cfg.managerPackage}/bin/kresctl' "$out/bin/"
'')
];
};
systemd.packages = [ cfg.package ]; # the unit gets patched a bit just below
systemd.services."knot-resolver" = {
wantedBy = [ "multi-user.target" ];
path = [ (lib.getBin cfg.package) ];
stopIfChanged = false;
reloadTriggers = [
configFile
];
serviceConfig = {
ExecStart = "${cfg.managerPackage}/bin/knot-resolver";
ExecReload = "${cfg.managerPackage}/bin/kresctl reload";
StateDirectory = "knot-resolver";
StateDirectoryMode = "0770";
RuntimeDirectory = "knot-resolver";
RuntimeDirectoryMode = "0770";
CacheDirectory = "knot-resolver";
CacheDirectoryMode = "0770";
};
};
};
}
+13 -3
View File
@@ -66,13 +66,14 @@ in
type = lib.types.bool;
default = false;
description = ''
Whether to enable knot-resolver domain name server.
Whether to enable knot-resolver (version 5) domain name server.
DNSSEC validation is turned on by default.
You can run `kresd-cli 1` and give commands interactively to kresd@1.service.
If you want to user knot-resolver 6, please use services.knot-resolver.
'';
};
package = lib.mkPackageOption pkgs "knot-resolver" {
example = "knot-resolver.override { extraFeatures = true; }";
package = lib.mkPackageOption pkgs "knot-resolver_5" {
example = "knot-resolver_5.override { extraFeatures = true; }";
};
extraConfig = lib.mkOption {
type = lib.types.lines;
@@ -134,6 +135,15 @@ in
###### implementation
config = lib.mkIf cfg.enable {
assertions = [
{
assertion = lib.versionOlder cfg.package.version "6.0.0";
message = ''
services.kresd only works with knot-resolver 5.
Please use services.knot-resolver for knot-resolver 6 and newer.
'';
}
];
environment = {
etc."knot-resolver/kresd.conf".source = configFile; # not required
systemPackages = [
@@ -1047,6 +1047,4 @@ in
};
};
meta.maintainers = with lib.maintainers; [ hrdinka ];
}
@@ -292,5 +292,4 @@ in
) cfg.redsocks;
};
meta.maintainers = with lib.maintainers; [ ekleog ];
}
+227 -209
View File
@@ -381,6 +381,19 @@ in
'';
};
generateHostKeys = lib.mkOption {
type = lib.types.bool;
default = config.services.openssh.enable;
defaultText = lib.literalExpression "services.openssh.enable";
description = ''
Whether to generate SSH host keys.
This can be enabled explicitly if you want to generate host keys but
don't want to enable the SSH daemon.
'';
example = true;
};
banner = lib.mkOption {
type = lib.types.nullOr lib.types.lines;
default = null;
@@ -669,115 +682,232 @@ in
###### implementation
config = lib.mkIf cfg.enable {
config = lib.mkMerge [
(lib.mkIf cfg.enable {
users.users.sshd = {
isSystemUser = true;
group = "sshd";
description = "SSH privilege separation user";
};
users.groups.sshd = { };
services.openssh.moduliFile = lib.mkDefault "${cfg.package}/etc/ssh/moduli";
services.openssh.sftpServerExecutable = lib.mkDefault "${cfg.package}/libexec/sftp-server";
environment.etc =
authKeysFiles
// authPrincipalsFiles
// {
"ssh/moduli".source = cfg.moduliFile;
"ssh/sshd_config".source = sshconf;
users.users.sshd = {
isSystemUser = true;
group = "sshd";
description = "SSH privilege separation user";
};
users.groups.sshd = { };
systemd.tmpfiles.settings."ssh-root-provision" = {
"/root"."d-" = {
user = "root";
group = ":root";
mode = ":700";
};
"/root/.ssh"."d-" = {
user = "root";
group = ":root";
mode = ":700";
};
"/root/.ssh/authorized_keys"."f^" = {
user = "root";
group = ":root";
mode = ":600";
argument = "ssh.authorized_keys.root";
};
};
services.openssh.moduliFile = lib.mkDefault "${cfg.package}/etc/ssh/moduli";
services.openssh.sftpServerExecutable = lib.mkDefault "${cfg.package}/libexec/sftp-server";
systemd = {
sockets.sshd = lib.mkIf cfg.startWhenNeeded {
description = "SSH Socket";
wantedBy = [ "sockets.target" ];
socketConfig.ListenStream =
if cfg.listenAddresses != [ ] then
lib.concatMap (
{ addr, port }:
if port != null then [ "${addr}:${toString port}" ] else map (p: "${addr}:${toString p}") cfg.ports
) cfg.listenAddresses
else
cfg.ports;
socketConfig.Accept = true;
# Prevent brute-force attacks from shutting down socket
socketConfig.TriggerLimitIntervalSec = 0;
};
environment.etc =
authKeysFiles
// authPrincipalsFiles
// {
"ssh/moduli".source = cfg.moduliFile;
"ssh/sshd_config".source = sshconf;
};
services."sshd@" = {
description = "SSH per-connection Daemon";
after = [
"network.target"
"sshd-keygen.service"
];
wants = [ "sshd-keygen.service" ];
stopIfChanged = false;
path = [ cfg.package ];
environment.LD_LIBRARY_PATH = nssModulesPath;
serviceConfig = {
ExecStart = lib.concatStringsSep " " [
"-${lib.getExe' cfg.package "sshd"}"
"-i"
"-D"
"-f /etc/ssh/sshd_config"
];
KillMode = "process";
StandardInput = "socket";
StandardError = "journal";
systemd.tmpfiles.settings."ssh-root-provision" = {
"/root"."d-" = {
user = "root";
group = ":root";
mode = ":700";
};
"/root/.ssh"."d-" = {
user = "root";
group = ":root";
mode = ":700";
};
"/root/.ssh/authorized_keys"."f^" = {
user = "root";
group = ":root";
mode = ":600";
argument = "ssh.authorized_keys.root";
};
};
services.sshd = lib.mkIf (!cfg.startWhenNeeded) {
description = "SSH Daemon";
wantedBy = [ "multi-user.target" ];
after = [
"network.target"
"sshd-keygen.service"
];
wants = [ "sshd-keygen.service" ];
stopIfChanged = false;
path = [ cfg.package ];
environment.LD_LIBRARY_PATH = nssModulesPath;
systemd = {
sockets.sshd = lib.mkIf cfg.startWhenNeeded {
description = "SSH Socket";
wantedBy = [ "sockets.target" ];
socketConfig.ListenStream =
if cfg.listenAddresses != [ ] then
lib.concatMap (
{ addr, port }:
if port != null then [ "${addr}:${toString port}" ] else map (p: "${addr}:${toString p}") cfg.ports
) cfg.listenAddresses
else
cfg.ports;
socketConfig.Accept = true;
# Prevent brute-force attacks from shutting down socket
socketConfig.TriggerLimitIntervalSec = 0;
};
restartTriggers = [ config.environment.etc."ssh/sshd_config".source ];
serviceConfig = {
Type = "notify-reload";
Restart = "always";
ExecStart = lib.concatStringsSep " " [
(lib.getExe' cfg.package "sshd")
"-D"
"-f"
"/etc/ssh/sshd_config"
services."sshd@" = {
description = "SSH per-connection Daemon";
after = [
"network.target"
"sshd-keygen.service"
];
KillMode = "process";
wants = lib.mkIf cfg.generateHostKeys [ "sshd-keygen.service" ];
stopIfChanged = false;
path = [ cfg.package ];
environment.LD_LIBRARY_PATH = nssModulesPath;
serviceConfig = {
ExecStart = lib.concatStringsSep " " [
"-${lib.getExe' cfg.package "sshd"}"
"-i"
"-D"
"-f /etc/ssh/sshd_config"
];
KillMode = "process";
StandardInput = "socket";
StandardError = "journal";
};
};
services.sshd = lib.mkIf (!cfg.startWhenNeeded) {
description = "SSH Daemon";
wantedBy = [ "multi-user.target" ];
after = [
"network.target"
"sshd-keygen.service"
];
wants = lib.mkIf cfg.generateHostKeys [ "sshd-keygen.service" ];
stopIfChanged = false;
path = [ cfg.package ];
environment.LD_LIBRARY_PATH = nssModulesPath;
restartTriggers = [ config.environment.etc."ssh/sshd_config".source ];
serviceConfig = {
Type = "notify-reload";
Restart = "always";
ExecStart = lib.concatStringsSep " " [
(lib.getExe' cfg.package "sshd")
"-D"
"-f"
"/etc/ssh/sshd_config"
];
KillMode = "process";
};
};
};
services.sshd-keygen = {
networking.firewall.allowedTCPPorts = lib.optionals cfg.openFirewall cfg.ports;
security.pam.services.sshd = lib.mkIf (cfg.settings.UsePAM == true) {
startSession = true;
showMotd = true;
unixAuth = if cfg.settings.PasswordAuthentication == true then true else false;
};
# These values are merged with the ones defined externally, see:
# https://github.com/NixOS/nixpkgs/pull/10155
# https://github.com/NixOS/nixpkgs/pull/41745
services.openssh.authorizedKeysFiles =
lib.optional cfg.authorizedKeysInHomedir "%h/.ssh/authorized_keys"
++ [ "/etc/ssh/authorized_keys.d/%u" ];
services.openssh.settings.AuthorizedPrincipalsFile = lib.mkIf (
authPrincipalsFiles != { }
) "/etc/ssh/authorized_principals.d/%u";
services.openssh.extraConfig = lib.mkOrder 0 (
lib.concatStringsSep "\n" (
[
"Banner ${if cfg.banner == null then "none" else pkgs.writeText "ssh_banner" cfg.banner}"
"AddressFamily ${if config.networking.enableIPv6 then "any" else "inet"}"
]
++ lib.map (port: ''Port ${toString port}'') cfg.ports
++ lib.map (
{ port, addr, ... }:
''ListenAddress ${addr}${lib.optionalString (port != null) (":" + toString port)}''
) cfg.listenAddresses
++ lib.optional cfgc.setXAuthLocation "XAuthLocation ${lib.getExe pkgs.xorg.xauth}"
++ lib.optional cfg.allowSFTP ''Subsystem sftp ${cfg.sftpServerExecutable} ${lib.concatStringsSep " " cfg.sftpFlags}''
++ [
"AuthorizedKeysFile ${toString cfg.authorizedKeysFiles}"
]
++ lib.optional (cfg.authorizedKeysCommand != "none") ''
AuthorizedKeysCommand ${cfg.authorizedKeysCommand}
AuthorizedKeysCommandUser ${cfg.authorizedKeysCommandUser}
''
++ lib.map (k: "HostKey ${k.path}") cfg.hostKeys
)
);
system.checks = [
(pkgs.runCommand "check-sshd-config"
{
nativeBuildInputs = [ validationPackage ];
}
''
${lib.concatMapStringsSep "\n" (
lport: "sshd -G -T -C lport=${toString lport} -f ${sshconf} > /dev/null"
) cfg.ports}
${lib.concatMapStringsSep "\n" (
la:
lib.concatMapStringsSep "\n" (
port:
"sshd -G -T -C ${lib.escapeShellArg "laddr=${la.addr},lport=${toString port}"} -f ${sshconf} > /dev/null"
) (if la.port != null then [ la.port ] else cfg.ports)
) cfg.listenAddresses}
touch $out
''
)
];
assertions = [
{
assertion = if cfg.settings.X11Forwarding then cfgc.setXAuthLocation else true;
message = "cannot enable X11 forwarding without setting xauth location";
}
{
assertion =
(builtins.match "(.*\n)?(\t )*[Kk][Ee][Rr][Bb][Ee][Rr][Oo][Ss][Aa][Uu][Tt][Hh][Ee][Nn][Tt][Ii][Cc][Aa][Tt][Ii][Oo][Nn][ |\t|=|\"]+yes.*" "${configFile}\n${cfg.extraConfig}")
!= null
-> cfgc.package.withKerberos;
message = "cannot enable Kerberos authentication without using a package with Kerberos support";
}
{
assertion =
(builtins.match "(.*\n)?(\t )*[Gg][Ss][Ss][Aa][Pp][Ii][Aa][Uu][Tt][Hh][Ee][Nn][Tt][Ii][Cc][Aa][Tt][Ii][Oo][Nn][ |\t|=|\"]+yes.*" "${configFile}\n${cfg.extraConfig}")
!= null
-> cfgc.package.withKerberos;
message = "cannot enable GSSAPI authentication without using a package with Kerberos support";
}
(
let
duplicates =
# Filter out the groups with more than 1 element
lib.filter (l: lib.length l > 1) (
# Grab the groups, we don't care about the group identifiers
lib.attrValues (
# Group the settings that are the same in lower case
lib.groupBy lib.strings.toLower (lib.attrNames cfg.settings)
)
);
formattedDuplicates = lib.concatMapStringsSep ", " (
dupl: "(${lib.concatStringsSep ", " dupl})"
) duplicates;
in
{
assertion = lib.length duplicates == 0;
message = ''Duplicate sshd config key; does your capitalization match the option's? Duplicate keys: ${formattedDuplicates}'';
}
)
]
++ lib.forEach cfg.listenAddresses (
{ addr, ... }:
{
assertion = addr != null;
message = "addr must be specified in each listenAddresses entry";
}
);
})
(lib.mkIf cfg.generateHostKeys {
systemd.services.sshd-keygen = {
description = "SSH Host Keys Generation";
wantedBy = [ "multi-user.target" ];
unitConfig = {
ConditionFileNotEmpty = map (k: "|!${k.path}") cfg.hostKeys;
};
@@ -802,119 +932,7 @@ in
fi
'');
};
};
networking.firewall.allowedTCPPorts = lib.optionals cfg.openFirewall cfg.ports;
security.pam.services.sshd = lib.mkIf cfg.settings.UsePAM {
startSession = true;
showMotd = true;
unixAuth = if cfg.settings.PasswordAuthentication == true then true else false;
};
# These values are merged with the ones defined externally, see:
# https://github.com/NixOS/nixpkgs/pull/10155
# https://github.com/NixOS/nixpkgs/pull/41745
services.openssh.authorizedKeysFiles =
lib.optional cfg.authorizedKeysInHomedir "%h/.ssh/authorized_keys"
++ [ "/etc/ssh/authorized_keys.d/%u" ];
services.openssh.settings.AuthorizedPrincipalsFile = lib.mkIf (
authPrincipalsFiles != { }
) "/etc/ssh/authorized_principals.d/%u";
services.openssh.extraConfig = lib.mkOrder 0 (
lib.concatStringsSep "\n" (
[
"Banner ${if cfg.banner == null then "none" else pkgs.writeText "ssh_banner" cfg.banner}"
"AddressFamily ${if config.networking.enableIPv6 then "any" else "inet"}"
]
++ lib.map (port: ''Port ${toString port}'') cfg.ports
++ lib.map (
{ port, addr, ... }:
''ListenAddress ${addr}${lib.optionalString (port != null) (":" + toString port)}''
) cfg.listenAddresses
++ lib.optional cfgc.setXAuthLocation "XAuthLocation ${lib.getExe pkgs.xorg.xauth}"
++ lib.optional cfg.allowSFTP ''Subsystem sftp ${cfg.sftpServerExecutable} ${lib.concatStringsSep " " cfg.sftpFlags}''
++ [
"AuthorizedKeysFile ${toString cfg.authorizedKeysFiles}"
]
++ lib.optional (cfg.authorizedKeysCommand != "none") ''
AuthorizedKeysCommand ${cfg.authorizedKeysCommand}
AuthorizedKeysCommandUser ${cfg.authorizedKeysCommandUser}
''
++ lib.map (k: "HostKey ${k.path}") cfg.hostKeys
)
);
system.checks = [
(pkgs.runCommand "check-sshd-config"
{
nativeBuildInputs = [ validationPackage ];
}
''
${lib.concatMapStringsSep "\n" (
lport: "sshd -G -T -C lport=${toString lport} -f ${sshconf} > /dev/null"
) cfg.ports}
${lib.concatMapStringsSep "\n" (
la:
lib.concatMapStringsSep "\n" (
port:
"sshd -G -T -C ${lib.escapeShellArg "laddr=${la.addr},lport=${toString port}"} -f ${sshconf} > /dev/null"
) (if la.port != null then [ la.port ] else cfg.ports)
) cfg.listenAddresses}
touch $out
''
)
];
assertions = [
{
assertion = if cfg.settings.X11Forwarding then cfgc.setXAuthLocation else true;
message = "cannot enable X11 forwarding without setting xauth location";
}
{
assertion =
(builtins.match "(.*\n)?(\t )*[Kk][Ee][Rr][Bb][Ee][Rr][Oo][Ss][Aa][Uu][Tt][Hh][Ee][Nn][Tt][Ii][Cc][Aa][Tt][Ii][Oo][Nn][ |\t|=|\"]+yes.*" "${configFile}\n${cfg.extraConfig}")
!= null
-> cfgc.package.withKerberos;
message = "cannot enable Kerberos authentication without using a package with Kerberos support";
}
{
assertion =
(builtins.match "(.*\n)?(\t )*[Gg][Ss][Ss][Aa][Pp][Ii][Aa][Uu][Tt][Hh][Ee][Nn][Tt][Ii][Cc][Aa][Tt][Ii][Oo][Nn][ |\t|=|\"]+yes.*" "${configFile}\n${cfg.extraConfig}")
!= null
-> cfgc.package.withKerberos;
message = "cannot enable GSSAPI authentication without using a package with Kerberos support";
}
(
let
duplicates =
# Filter out the groups with more than 1 element
lib.filter (l: lib.length l > 1) (
# Grab the groups, we don't care about the group identifiers
lib.attrValues (
# Group the settings that are the same in lower case
lib.groupBy lib.strings.toLower (lib.attrNames cfg.settings)
)
);
formattedDuplicates = lib.concatMapStringsSep ", " (
dupl: "(${lib.concatStringsSep ", " dupl})"
) duplicates;
in
{
assertion = lib.length duplicates == 0;
message = ''Duplicate sshd config key; does your capitalization match the option's? Duplicate keys: ${formattedDuplicates}'';
}
)
]
++ lib.forEach cfg.listenAddresses (
{ addr, ... }:
{
assertion = addr != null;
message = "addr must be specified in each listenAddresses entry";
}
);
};
})
];
}
@@ -0,0 +1,281 @@
{
config,
lib,
pkgs,
...
}:
let
inherit (lib)
attrNames
escapeShellArgs
filterAttrs
getExe'
last
literalExpression
maintainers
mapAttrs'
mkOption
mkPackageOption
optionals
splitString
toInt
types
;
cfg = config.services.udp-over-tcp;
commonOptions = {
openFirewall = mkOption {
type = types.bool;
default = false;
description = ''
Open the appropriate ports in the firewall.
'';
};
# Options and descriptions as indicated by `tcp2udp --help` and `udp2tcp --help`.
forward = mkOption {
type = types.str;
description = ''
The IP and port to forward all traffic to.
'';
};
recvBufferSize = mkOption {
type = types.nullOr types.ints.positive;
description = ''
If given, sets the SO_RCVBUF option on the TCP socket to the given number of bytes.
Changes the size of the operating system's receive buffer associated with the socket.
'';
default = null;
};
sendBufferSize = mkOption {
type = types.nullOr types.ints.positive;
description = ''
If given, sets the SO_SNDBUF option on the TCP socket to the given number of bytes.
Changes the size of the operating system's send buffer associated with the socket.
'';
default = null;
};
recvTimeout = mkOption {
type = types.nullOr types.ints.positive;
description = ''
An application timeout on receiving data from the TCP socket.
'';
default = null;
};
fwmark = mkOption {
type = types.nullOr types.ints.u32;
description = ''
If given, sets the SO_MARK option on the TCP socket.
'';
default = null;
};
nodelay = mkOption {
type = types.bool;
description = ''
Enables TCP_NODELAY on the TCP socket.
'';
default = false;
};
};
tcp2udpSubmodule = {
options = commonOptions // {
threads = mkOption {
type = types.nullOr types.ints.positive;
description = ''
Sets the number of worker threads to use.
The default value is the number of cores available to the system.
'';
default = null;
};
bind = mkOption {
type = types.nullOr types.str;
description = ''
Which local IP to bind the UDP socket to.
'';
default = null;
};
};
};
udp2tcpSubmodule = {
options = commonOptions;
};
configToService = type: buildCmdline: listen: conf: {
name = "${type}-${listen}";
value = {
description = "${type} tunnel from ${listen} to ${conf.forward}";
after = [ "network-online.target" ];
wants = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
reloadIfChanged = true;
serviceConfig = {
Type = "exec";
ExecStart = "${getExe' cfg.package type} " + escapeShellArgs (buildCmdline listen conf);
DynamicUser = true;
User = "udp-over-tcp";
# CAP_NET_BIND_SERVICE in case we are binding to ports < 1024, CAP_NET_ADMIN only covers addresses.
# CAP_NET_ADMIN for setting SO_MARK on the socket.
AmbientCapabilities = [
"CAP_NET_ADMIN"
"CAP_NET_BIND_SERVICE"
];
CapabilityBoundingSet = [
"CAP_NET_ADMIN"
"CAP_NET_BIND_SERVICE"
];
Restart = "on-failure";
RestartSec = 10;
LockPersonality = true;
MemoryDenyWriteExecute = true;
NoNewPrivileges = true;
PrivateMounts = true;
PrivateTmp = true;
PrivateUsers = false;
ProcSubset = "pid";
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
ProtectSystem = "strict";
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallFilter = "@system-service";
UMask = "077";
};
};
};
buildCommonCmdline =
listen: conf:
optionals (conf.recvBufferSize != null) [
"--recv-buffer"
conf.recvBufferSize
]
++ optionals (conf.sendBufferSize != null) [
"--send-buffer"
conf.sendBufferSize
]
++ optionals (conf.recvTimeout != null) [
"--tcp-recv-timeout"
conf.recvTimeout
]
++ optionals (conf.fwmark != null) [
"--fwmark"
conf.fwmark
]
++ optionals conf.nodelay [
"--nodelay"
];
buildTcp2udpCmdline =
listen: conf:
[
"--tcp-listen"
listen
"--udp-forward"
conf.forward
]
++ optionals (conf.threads != null) [
"--threads"
conf.threads
]
++ optionals (conf.bind != null) [
"--udp-bind"
conf.bind
]
++ buildCommonCmdline listen conf;
buildUdp2tcpCmdline =
listen: conf:
[
"--udp-listen"
listen
"--tcp-forward"
conf.forward
]
++ buildCommonCmdline listen conf;
getFirewallPorts =
instances:
map (e: toInt (last (splitString ":" e))) (
attrNames (filterAttrs (_: e: e.openFirewall) instances)
);
in
{
options.services.udp-over-tcp = {
package = mkPackageOption pkgs "udp-over-tcp" { };
tcp2udp = mkOption {
type = types.attrsOf (types.submodule tcp2udpSubmodule);
example = literalExpression ''
{
"0.0.0.0:443" = {
forward = "127.0.0.1:51820";
openFirewall = true;
};
"0.0.0.0:444" = {
threads = 2;
forward = "127.0.0.1:51821";
bind = "127.0.0.1";
recvBufferSize = 16384;
sendBufferSize = 16384;
recvTimeout = 10;
fwmark = 1337;
nodelay = true;
};
}
'';
description = ''
Mapping of TCP listening ports to UDP forwarding ports or configurations.
'';
default = { };
};
udp2tcp = mkOption {
type = types.attrsOf (types.submodule udp2tcpSubmodule);
example = literalExpression ''
{
"0.0.0.0:51820" = {
forward = "10.0.0.1:443";
openFirewall = true;
};
"0.0.0.0:51821" = {
forward = "10.0.0.1:444";
recvBufferSize = 16384;
sendBufferSize = 16384;
recvTimeout = 10;
fwmark = 1337;
nodelay = true;
};
}
'';
description = ''
Mapping of UDP listening ports to TCP forwarding ports or configurations.
'';
default = { };
};
};
config = {
systemd.services =
(mapAttrs' (configToService "tcp2udp" buildTcp2udpCmdline) cfg.tcp2udp)
// (mapAttrs' (configToService "udp2tcp" buildUdp2tcpCmdline) cfg.udp2tcp);
networking.firewall.allowedTCPPorts = getFirewallPorts cfg.tcp2udp;
networking.firewall.allowedUDPPorts = getFirewallPorts cfg.udp2tcp;
};
meta.maintainers = with maintainers; [ timschumi ];
}
@@ -183,8 +183,10 @@ let
}
# finally start daemon
# shellcheck disable=SC2086
exec wpa_supplicant $args
'';
enableStrictShellChecks = true;
};
systemctl = "/run/current-system/systemd/bin/systemctl";
@@ -54,7 +54,6 @@ let
in
{
meta.maintainers = with lib.maintainers; [
Br1ght0ne
happysalada
];
meta.doc = ./meilisearch.md;
@@ -91,7 +91,7 @@ in
'';
};
enableKepubify = mkEnableOption "kebup conversion support";
enableKepubify = mkEnableOption "kepub conversion support";
enableBookUploading = mkOption {
type = types.bool;
@@ -0,0 +1,132 @@
{
config,
lib,
pkgs,
utils,
...
}:
let
cfg = config.services.immich-kiosk;
format = pkgs.formats.json { };
secretsReplacement = utils.genJqSecretsReplacement {
loadCredential = true;
} cfg.settings "/run/immich-kiosk/config.yaml";
in
{
meta.maintainers = with lib.maintainers; [ tlvince ];
options.services.immich-kiosk = {
enable = lib.mkEnableOption "Immich Kiosk slideshow service";
package = lib.mkPackageOption pkgs "immich-kiosk" { };
openFirewall = lib.mkOption {
type = lib.types.bool;
default = false;
description = ''
Whether to open the firewall for the immich-kiosk port.
'';
};
settings = lib.mkOption {
type = lib.types.submodule {
freeformType = format.type;
options = {
immich_url = lib.mkOption {
type = lib.types.str;
default = config.services.immich.settings.server.externalDomain;
defaultText = lib.literalExpression "config.services.immich.settings.server.externalDomain";
description = ''
URL of the immich instance.
'';
};
kiosk.port = lib.mkOption {
type = lib.types.port;
default = 3000;
description = ''
Port on which immich-kiosk will listen.
'';
};
};
};
default = { };
description = ''
Configuration for immich-kiosk. See
<https://docs.immichkiosk.app/configuration/>
for available options. Secret values can be loaded from files using
`._secret = "/path/to/secret";`.
'';
example = lib.literalExpression ''
{
immich_url = "https://immich.example.com";
immich_api_key._secret = "/run/secrets/immich-kiosk-api-key";
albums = [
"4fa933cf-051f-4621-9ac7-8d06776c261c"
"6466548c-4995-4fb5-ab1f-f63cc9ff3e5f"
];
duration = 30;
layout = "splitview";
disable_ui = true;
}
'';
};
};
config = lib.mkIf cfg.enable {
systemd.services.immich-kiosk = {
description = "Immich Kiosk slideshow service";
after = [ "immich-server.service" ];
wantedBy = [ "multi-user.target" ];
preStart = secretsReplacement.script;
serviceConfig = {
DynamicUser = true;
ExecStart = lib.getExe cfg.package;
Group = "immich-kiosk";
LoadCredential = secretsReplacement.credentials;
Restart = "on-failure";
RestartSec = 10;
RuntimeDirectory = "immich-kiosk";
RuntimeDirectoryMode = "0700";
SyslogIdentifier = "immich-kiosk";
Type = "simple";
User = "immich-kiosk";
WorkingDirectory = "/run/immich-kiosk";
# Hardening
CapabilityBoundingSet = [ "" ];
LockPersonality = true;
NoNewPrivileges = true;
PrivateDevices = true;
PrivateTmp = true;
PrivateUsers = true;
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectHostname = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectProc = "invisible";
RestrictAddressFamilies = [
"AF_INET"
"AF_INET6"
];
RestrictNamespaces = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
SystemCallArchitectures = "native";
SystemCallFilter = [
"@system-service"
"~@privileged"
"~@resources"
];
UMask = "0077";
};
};
networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ cfg.settings.kiosk.port ];
};
}
@@ -0,0 +1,142 @@
{
config,
lib,
pkgs,
...
}:
let
cfg = config.services.immichframe;
format = pkgs.formats.json { };
inherit (lib)
types
mkIf
mkOption
mkEnableOption
;
in
{
options.services.immichframe = {
enable = mkEnableOption "ImmichFrame";
package = lib.mkPackageOption pkgs "immichframe" { };
port = mkOption {
type = types.port;
default = 3000;
description = "The port that ImmichFrame will listen on.";
};
settings = mkOption {
type = types.submodule {
freeformType = format.type;
options = {
Accounts = mkOption {
type = types.listOf (
types.submodule {
freeformType = format.type;
options = {
ImmichServerUrl = mkOption {
type = types.str;
example = "http://photos.example.com";
description = "The URL of your Immich server.";
};
ApiKey = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
API key to talk to the Immich server.
Warning: it will be world-readable in /nix/store.
Consider using {option}`ApiKeyFile` instead.
See
<https://immichframe.online/docs/getting-started/configuration#api-key-permissions>
for details on what permissions this key needs.
'';
};
ApiKeyFile = mkOption {
type = types.nullOr types.externalPath;
default = null;
description = ''
File containing an API key to talk to the Immich server.
See
<https://immichframe.online/docs/getting-started/configuration#api-key-permissions>
for details on what permissions this key needs.
'';
};
};
}
);
description = ''
Accounts configuration, multiple are permitted. See
<https://immichframe.online/docs/getting-started/configuration>.
'';
};
};
};
default = { };
description = ''
Configuration for ImmichFrame. See
<https://immichframe.online/docs/getting-started/configuration> for
options and defaults.
'';
};
};
config = mkIf cfg.enable {
assertions = lib.imap0 (i: account: {
assertion = lib.xor (account.ApiKey == null) (account.ApiKeyFile == null);
message = "Exactly one of {option}`services.immichframe.settings.Accounts[${toString i}].ApiKey` and {option}`services.immichframe.settings.Accounts[${toString i}].ApiKeyFile` must be specified";
}) cfg.settings.Accounts;
systemd.services.immichframe =
let
accountsWithApiKeyFiles = lib.filter (account: account.ApiKeyFile != null) cfg.settings.Accounts;
apiKeyFileToId = lib.listToAttrs (
lib.imap0 (
index: account: lib.nameValuePair account.ApiKeyFile "api-key-${toString index}"
) accountsWithApiKeyFiles
);
settingsPatchWithCredentialPaths = {
Accounts = map (
account:
account
// (
if account.ApiKeyFile != null then
{
ApiKeyFile = "/run/credentials/${config.systemd.services.immichframe.name}/${
apiKeyFileToId.${account.ApiKeyFile}
}";
}
else
{ }
)
) cfg.settings.Accounts;
};
settingsWithFixedSecretPaths = lib.recursiveUpdate cfg.settings settingsPatchWithCredentialPaths;
in
{
description = "Display your photos from Immich as a digital photo frame";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
environment = {
IMMICHFRAME_CONFIG_PATH = pkgs.runCommand "Config" { } ''
mkdir $out
ln -s ${format.generate "Settings.json" settingsWithFixedSecretPaths} $out/Settings.json
'';
};
serviceConfig = {
ExecStart = "${lib.getExe cfg.package} --urls=http://localhost:${toString cfg.port}";
LoadCredential = lib.concatMapAttrsStringSep ":" (
apiKeyFile: id: "${id}:${apiKeyFile}"
) apiKeyFileToId;
DynamicUser = true;
Type = "simple";
Restart = "on-failure";
RestartSec = 3;
};
};
};
meta.maintainers = with lib.maintainers; [ jfly ];
}
@@ -466,7 +466,7 @@ in
defaultText = literalExpression "true";
description = ''
Create the database and database user locally.
This currently only applies if database type "mysql" is selected.
This currently only applies if database type "mysql" or "postgres" is selected.
'';
};
};
@@ -264,7 +264,7 @@ let
$decoded = json_decode(nix_read_secret($credential_name), true);
if (json_last_error() !== JSON_ERROR_NONE) {
error_log(sprintf("Cannot decode %s, because: %s", $file, json_last_error_msg()));
error_log(sprintf("Cannot decode %s, because: %s", $credential_name, json_last_error_msg()));
exit(1);
}
+22 -8
View File
@@ -12,9 +12,7 @@ let
configFile = format.generate "pretalx.cfg" cfg.settings;
finalPackage = cfg.package.override {
inherit (cfg) plugins;
};
inherit (cfg) finalPackage;
pythonEnv = finalPackage.python.buildEnv.override {
extraLibs =
@@ -41,6 +39,22 @@ in
package = lib.mkPackageOption pkgs "pretalx" { };
finalPackage = lib.mkOption {
type = lib.types.package;
default = cfg.package.override {
inherit (cfg) plugins;
};
defaultText = ''
config.services.package.override {
inherit (config.services.pretalx) plugins;
}
'';
readOnly = true;
description = ''
The effective pretalx package used. This is the base package with the selected plugins applied.
'';
};
group = lib.mkOption {
type = lib.types.str;
default = "pretalx";
@@ -220,8 +234,8 @@ in
};
static = lib.mkOption {
type = lib.types.path;
default = "${cfg.package.static}/";
defaultText = lib.literalExpression "\${config.services.pretalx.package}.static}/";
default = "${finalPackage.static}/";
defaultText = "\${config.services.pretalx.finalPackage.static}/";
readOnly = true;
description = ''
Path to the directory that contains static files.
@@ -299,7 +313,7 @@ in
};
config = lib.mkIf cfg.enable {
# https://docs.pretalx.org/administrator/installation.html
# https://docs.pretalx.org/administrator/installation/
environment.systemPackages = [
(pkgs.writeScriptBin "pretalx-manage" ''
@@ -331,7 +345,7 @@ in
recommendedTlsSettings = lib.mkDefault true;
upstreams.pretalx.servers."unix:/run/pretalx/pretalx.sock" = { };
virtualHosts.${cfg.nginx.domain} = {
# https://docs.pretalx.org/administrator/installation.html#step-7-ssl
# https://docs.pretalx.org/administrator/installation/#step-8-reverse-proxy
extraConfig = ''
more_set_headers "Referrer-Policy: same-origin";
more_set_headers "X-Content-Type-Options: nosniff";
@@ -442,7 +456,7 @@ in
preStart =
let
versionString = lib.concatStringsSep "\n" (
[ "pretalx-${cfg.package.version}" ]
[ "pretalx-${finalPackage.version}" ]
++ map (plugin: "${plugin.pname}-${plugin.version}") cfg.plugins
);
in
+13 -3
View File
@@ -299,12 +299,14 @@ in
]);
script = ''
export SZURUBOORU_SECRET="$(<${cfg.server.settings.secretFile})"
export SZURUBOORU_DATABASE_PASSWORD="$(<${cfg.database.passwordFile})"
export SZURUBOORU_SECRET="$(<$CREDENTIALS_DIRECTORY/secret)"
export SZURUBOORU_DATABASE_PASSWORD="$(<$CREDENTIALS_DIRECTORY/database)"
${lib.optionalString (cfg.server.settings.smtp.passFile != null) ''
export SZURUBOORU_SMTP_PASS=$(<${cfg.server.settings.smtp.passFile})
export SZURUBOORU_SMTP_PASS=$(<$CREDENTIALS_DIRECTORY/smtp)
''}
install -m0640 ${cfg.server.package.src}/config.yaml.dist ${cfg.dataDir}/config.yaml.dist
touch ${cfg.dataDir}/config.yaml
chmod 0640 ${cfg.dataDir}/config.yaml
envsubst -i ${configFile} -o ${cfg.dataDir}/config.yaml
sed 's|script_location = |script_location = ${cfg.server.package.src}/|' ${cfg.server.package.src}/alembic.ini > ${cfg.dataDir}/alembic.ini
alembic upgrade head
@@ -312,6 +314,14 @@ in
'';
serviceConfig = {
LoadCredential = [
"secret:${cfg.server.settings.secretFile}"
"database:${cfg.database.passwordFile}"
]
++ (lib.optionals (cfg.server.settings.smtp.passFile != null) [
"smtp:${cfg.server.settings.smtp.passFile}"
]);
User = cfg.user;
Group = cfg.group;
+714
View File
@@ -0,0 +1,714 @@
{
config,
lib,
pkgs,
...
}:
with lib;
let
cfg = config.services.tt-rss;
inherit (cfg) phpPackage;
configVersion = 26;
dbPort =
if cfg.database.port == null then
(if cfg.database.type == "pgsql" then 5432 else 3306)
else
cfg.database.port;
poolName = "tt-rss";
mysqlLocal = cfg.database.createLocally && cfg.database.type == "mysql";
pgsqlLocal = cfg.database.createLocally && cfg.database.type == "pgsql";
tt-rss-config =
let
password =
if (cfg.database.password != null) then
"'${(escape [ "'" "\\" ] cfg.database.password)}'"
else if (cfg.database.passwordFile != null) then
"file_get_contents('${cfg.database.passwordFile}')"
else
null;
in
pkgs.writeText "config.php" ''
<?php
putenv('TTRSS_PHP_EXECUTABLE=${phpPackage}/bin/php');
putenv('TTRSS_LOCK_DIRECTORY=${cfg.root}/lock');
putenv('TTRSS_CACHE_DIR=${cfg.root}/cache');
putenv('TTRSS_ICONS_DIR=${cfg.root}/feed-icons');
putenv('TTRSS_ICONS_URL=feed-icons');
putenv('TTRSS_SELF_URL_PATH=${cfg.selfUrlPath}');
putenv('TTRSS_MYSQL_CHARSET=UTF8');
putenv('TTRSS_DB_TYPE=${cfg.database.type}');
putenv('TTRSS_DB_HOST=${optionalString (cfg.database.host != null) cfg.database.host}');
putenv('TTRSS_DB_USER=${cfg.database.user}');
putenv('TTRSS_DB_NAME=${cfg.database.name}');
putenv('TTRSS_DB_PASS=' ${optionalString (password != null) ". ${password}"});
putenv('TTRSS_DB_PORT=${toString dbPort}');
putenv('TTRSS_AUTH_AUTO_CREATE=${boolToString cfg.auth.autoCreate}');
putenv('TTRSS_AUTH_AUTO_LOGIN=${boolToString cfg.auth.autoLogin}');
putenv('TTRSS_FEED_CRYPT_KEY=${escape [ "'" "\\" ] cfg.feedCryptKey}');
putenv('TTRSS_SINGLE_USER_MODE=${boolToString cfg.singleUserMode}');
putenv('TTRSS_SIMPLE_UPDATE_MODE=${boolToString cfg.simpleUpdateMode}');
# Never check for updates - the running version of the code should
# be controlled entirely by the version of TT-RSS active in the
# current Nix profile. If TT-RSS updates itself to a version
# requiring a database schema upgrade, and then the SystemD
# tt-rss.service is restarted, the old code copied from the Nix
# store will overwrite the updated version, causing the code to
# detect the need for a schema "upgrade" (since the schema version
# in the database is different than in the code), but the update
# schema operation in TT-RSS will do nothing because the schema
# version in the database is newer than that in the code.
putenv('TTRSS_CHECK_FOR_UPDATES=false');
putenv('TTRSS_FORCE_ARTICLE_PURGE=${toString cfg.forceArticlePurge}');
putenv('TTRSS_SESSION_COOKIE_LIFETIME=${toString cfg.sessionCookieLifetime}');
putenv('TTRSS_ENABLE_GZIP_OUTPUT=${boolToString cfg.enableGZipOutput}');
putenv('TTRSS_PLUGINS=${builtins.concatStringsSep "," cfg.plugins}');
putenv('TTRSS_LOG_DESTINATION=${cfg.logDestination}');
putenv('TTRSS_CONFIG_VERSION=${toString configVersion}');
putenv('TTRSS_PUBSUBHUBBUB_ENABLED=${boolToString cfg.pubSubHubbub.enable}');
putenv('TTRSS_PUBSUBHUBBUB_HUB=${cfg.pubSubHubbub.hub}');
putenv('TTRSS_SPHINX_SERVER=${cfg.sphinx.server}');
putenv('TTRSS_SPHINX_INDEX=${builtins.concatStringsSep "," cfg.sphinx.index}');
putenv('TTRSS_ENABLE_REGISTRATION=${boolToString cfg.registration.enable}');
putenv('TTRSS_REG_NOTIFY_ADDRESS=${cfg.registration.notifyAddress}');
putenv('TTRSS_REG_MAX_USERS=${toString cfg.registration.maxUsers}');
putenv('TTRSS_SMTP_SERVER=${cfg.email.server}');
putenv('TTRSS_SMTP_LOGIN=${cfg.email.login}');
putenv('TTRSS_SMTP_PASSWORD=${escape [ "'" "\\" ] cfg.email.password}');
putenv('TTRSS_SMTP_SECURE=${cfg.email.security}');
putenv('TTRSS_SMTP_FROM_NAME=${escape [ "'" "\\" ] cfg.email.fromName}');
putenv('TTRSS_SMTP_FROM_ADDRESS=${escape [ "'" "\\" ] cfg.email.fromAddress}');
putenv('TTRSS_DIGEST_SUBJECT=${escape [ "'" "\\" ] cfg.email.digestSubject}');
${cfg.extraConfig}
'';
# tt-rss and plugins and themes and config.php
servedRoot = pkgs.runCommand "tt-rss-served-root" { } ''
cp --no-preserve=mode -r ${pkgs.tt-rss} $out
cp ${tt-rss-config} $out/config.php
${optionalString (cfg.pluginPackages != [ ]) ''
for plugin in ${concatStringsSep " " cfg.pluginPackages}; do
cp -r "$plugin"/* "$out/plugins.local/"
done
''}
${optionalString (cfg.themePackages != [ ]) ''
for theme in ${concatStringsSep " " cfg.themePackages}; do
cp -r "$theme"/* "$out/themes.local/"
done
''}
'';
in
{
###### interface
options = {
services.tt-rss = {
enable = mkEnableOption "tt-rss";
root = mkOption {
type = types.path;
default = "/var/lib/tt-rss";
description = ''
Root of the application.
'';
};
user = mkOption {
type = types.str;
default = "tt_rss";
description = ''
User account under which both the update daemon and the web-application run.
'';
};
pool = mkOption {
type = types.str;
default = "${poolName}";
description = ''
Name of existing phpfpm pool that is used to run web-application.
If not specified a pool will be created automatically with
default values.
'';
};
virtualHost = mkOption {
type = types.nullOr types.str;
default = "tt-rss";
description = ''
Name of the nginx virtualhost to use and setup. If null, do not setup any virtualhost.
'';
};
database = {
type = mkOption {
type = types.enum [
"pgsql"
"mysql"
];
default = "pgsql";
description = ''
Database to store feeds. Supported are pgsql and mysql.
'';
};
host = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
Host of the database. Leave null to use Unix domain socket.
'';
};
name = mkOption {
type = types.str;
default = "tt_rss";
description = ''
Name of the existing database.
'';
};
user = mkOption {
type = types.str;
default = "tt_rss";
description = ''
The database user. The user must exist and has access to
the specified database.
'';
};
password = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
The database user's password.
'';
};
passwordFile = mkOption {
type = types.nullOr types.str;
default = null;
description = ''
The database user's password.
'';
};
port = mkOption {
type = types.nullOr types.port;
default = null;
description = ''
The database's port. If not set, the default ports will be provided (5432
and 3306 for pgsql and mysql respectively).
'';
};
createLocally = mkOption {
type = types.bool;
default = true;
description = "Create the database and database user locally.";
};
};
auth = {
autoCreate = mkOption {
type = types.bool;
default = true;
description = ''
Allow authentication modules to auto-create users in tt-rss internal
database when authenticated successfully.
'';
};
autoLogin = mkOption {
type = types.bool;
default = true;
description = ''
Automatically login user on remote or other kind of externally supplied
authentication, otherwise redirect to login form as normal.
If set to true, users won't be able to set application language
and settings profile.
'';
};
};
pubSubHubbub = {
hub = mkOption {
type = types.str;
default = "";
description = ''
URL to a PubSubHubbub-compatible hub server. If defined, "Published
articles" generated feed would automatically become PUSH-enabled.
'';
};
enable = mkOption {
type = types.bool;
default = false;
description = ''
Enable client PubSubHubbub support in tt-rss. When disabled, tt-rss
won't try to subscribe to PUSH feed updates.
'';
};
};
sphinx = {
server = mkOption {
type = types.str;
default = "localhost:9312";
description = ''
Hostname:port combination for the Sphinx server.
'';
};
index = mkOption {
type = types.listOf types.str;
default = [
"ttrss"
"delta"
];
description = ''
Index names in Sphinx configuration. Example configuration
files are available on tt-rss wiki.
'';
};
};
registration = {
enable = mkOption {
type = types.bool;
default = false;
description = ''
Allow users to register themselves. Please be aware that allowing
random people to access your tt-rss installation is a security risk
and potentially might lead to data loss or server exploit. Disabled
by default.
'';
};
notifyAddress = mkOption {
type = types.str;
default = "";
description = ''
Email address to send new user notifications to.
'';
};
maxUsers = mkOption {
type = types.int;
default = 0;
description = ''
Maximum amount of users which will be allowed to register on this
system. 0 - no limit.
'';
};
};
email = {
server = mkOption {
type = types.str;
default = "";
example = "localhost:25";
description = ''
Hostname:port combination to send outgoing mail. Blank - use system
MTA.
'';
};
login = mkOption {
type = types.str;
default = "";
description = ''
SMTP authentication login used when sending outgoing mail.
'';
};
password = mkOption {
type = types.str;
default = "";
description = ''
SMTP authentication password used when sending outgoing mail.
'';
};
security = mkOption {
type = types.enum [
""
"ssl"
"tls"
];
default = "";
description = ''
Used to select a secure SMTP connection. Allowed values: ssl, tls,
or empty.
'';
};
fromName = mkOption {
type = types.str;
default = "Tiny Tiny RSS";
description = ''
Name for sending outgoing mail. This applies to password reset
notifications, digest emails and any other mail.
'';
};
fromAddress = mkOption {
type = types.str;
default = "";
description = ''
Address for sending outgoing mail. This applies to password reset
notifications, digest emails and any other mail.
'';
};
digestSubject = mkOption {
type = types.str;
default = "[tt-rss] New headlines for last 24 hours";
description = ''
Subject line for email digests.
'';
};
};
sessionCookieLifetime = mkOption {
type = types.int;
default = 86400;
description = ''
Default lifetime of a session (e.g. login) cookie. In seconds,
0 means cookie will be deleted when browser closes.
'';
};
selfUrlPath = mkOption {
type = types.str;
description = ''
Full URL of your tt-rss installation. This should be set to the
location of tt-rss directory, e.g. http://example.org/tt-rss/
You need to set this option correctly otherwise several features
including PUSH, bookmarklets and browser integration will not work properly.
'';
example = "http://localhost";
};
feedCryptKey = mkOption {
type = types.str;
default = "";
description = ''
Key used for encryption of passwords for password-protected feeds
in the database. A string of 24 random characters. If left blank, encryption
is not used. Requires mcrypt functions.
Warning: changing this key will make your stored feed passwords impossible
to decrypt.
'';
};
singleUserMode = mkOption {
type = types.bool;
default = false;
description = ''
Operate in single user mode, disables all functionality related to
multiple users and authentication. Enabling this assumes you have
your tt-rss directory protected by other means (e.g. http auth).
'';
};
simpleUpdateMode = mkOption {
type = types.bool;
default = false;
description = ''
Enables fallback update mode where tt-rss tries to update feeds in
background while tt-rss is open in your browser.
If you don't have a lot of feeds and don't want to or can't run
background processes while not running tt-rss, this method is generally
viable to keep your feeds up to date.
Still, there are more robust (and recommended) updating methods
available, you can read about them here: <https://tt-rss.org/wiki/UpdatingFeeds>
'';
};
forceArticlePurge = mkOption {
type = types.int;
default = 0;
description = ''
When this option is not 0, users ability to control feed purging
intervals is disabled and all articles (which are not starred)
older than this amount of days are purged.
'';
};
enableGZipOutput = mkOption {
type = types.bool;
default = true;
description = ''
Selectively gzip output to improve wire performance. This requires
PHP Zlib extension on the server.
Enabling this can break tt-rss in several httpd/php configurations,
if you experience weird errors and tt-rss failing to start, blank pages
after login, or content encoding errors, disable it.
'';
};
phpPackage = lib.mkOption {
type = lib.types.package;
default = pkgs.php;
defaultText = "pkgs.php";
description = ''
php package to use for php fpm and update daemon.
'';
};
plugins = mkOption {
type = types.listOf types.str;
default = [
"auth_internal"
"note"
];
description = ''
List of plugins to load automatically for all users.
System plugins have to be specified here. Please enable at least one
authentication plugin here (auth_*).
Users may enable other user plugins from Preferences/Plugins but may not
disable plugins specified in this list.
Disabling auth_internal in this list would automatically disable
reset password link on the login form.
'';
};
pluginPackages = mkOption {
type = types.listOf types.package;
default = [ ];
description = ''
List of plugins to install. The list elements are expected to
be derivations. All elements in this derivation are automatically
copied to the `plugins.local` directory.
'';
};
themePackages = mkOption {
type = types.listOf types.package;
default = [ ];
description = ''
List of themes to install. The list elements are expected to
be derivations. All elements in this derivation are automatically
copied to the `themes.local` directory.
'';
};
logDestination = mkOption {
type = types.enum [
""
"sql"
"syslog"
];
default = "sql";
description = ''
Log destination to use. Possible values: sql (uses internal logging
you can read in Preferences -> System), syslog - logs to system log.
Setting this to blank uses PHP logging (usually to http server
error.log).
'';
};
updateDaemon = {
commandFlags = mkOption {
type = types.str;
default = "--quiet";
description = ''
Command-line flags passed to the update daemon.
The default --quiet flag mutes all logging, including errors.
'';
};
};
extraConfig = mkOption {
type = types.lines;
default = "";
description = ''
Additional lines to append to `config.php`.
'';
};
};
};
imports = [
(mkRemovedOptionModule [ "services" "tt-rss" "checkForUpdates" ] ''
This option was removed because setting this to true will cause TT-RSS
to be unable to start if an automatic update of the code in
services.tt-rss.root leads to a database schema upgrade that is not
supported by the code active in the Nix store.
'')
];
###### implementation
config = mkIf cfg.enable {
assertions = [
{
assertion = cfg.database.password != null -> cfg.database.passwordFile == null;
message = "Cannot set both password and passwordFile";
}
{
assertion =
cfg.database.createLocally -> cfg.database.name == cfg.user && cfg.database.user == cfg.user;
message = ''
When creating a database via NixOS, the db user and db name must be equal!
If you already have an existing DB+user and this assertion is new, you can safely set
`services.tt-rss.database.createLocally` to `false` because removal of `ensureUsers`
and `ensureDatabases` doesn't have any effect.
'';
}
];
services.phpfpm.pools = mkIf (cfg.pool == "${poolName}") {
${poolName} = {
inherit (cfg) user;
inherit phpPackage;
settings = mapAttrs (name: mkDefault) {
"listen.owner" = "nginx";
"listen.group" = "nginx";
"listen.mode" = "0600";
"pm" = "dynamic";
"pm.max_children" = 75;
"pm.start_servers" = 10;
"pm.min_spare_servers" = 5;
"pm.max_spare_servers" = 20;
"pm.max_requests" = 500;
"catch_workers_output" = 1;
};
};
};
# NOTE: No configuration is done if not using virtual host
services.nginx = mkIf (cfg.virtualHost != null) {
enable = true;
virtualHosts = {
${cfg.virtualHost} = {
root = "${cfg.root}/www";
locations."/" = {
index = "index.php";
};
# some clients might still access this old path directly, forward them to the API instead
# e.g. https://apps.apple.com/de/app/tiny-reader-rss/id689519762 at version 2.2.0
locations."~* /feed-icons/(\\d+)\\.ico" = {
return = "302 /public.php?op=feed_icon&id=$1";
};
locations."~ \\.php$" = {
extraConfig = ''
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:${config.services.phpfpm.pools.${cfg.pool}.socket};
fastcgi_index index.php;
'';
};
};
};
};
systemd.tmpfiles.rules = [
"d '${cfg.root}' 0555 ${cfg.user} tt_rss - -"
"d '${cfg.root}/lock' 0755 ${cfg.user} tt_rss - -"
"d '${cfg.root}/cache' 0755 ${cfg.user} tt_rss - -"
"d '${cfg.root}/cache/upload' 0755 ${cfg.user} tt_rss - -"
"d '${cfg.root}/cache/images' 0755 ${cfg.user} tt_rss - -"
"d '${cfg.root}/cache/export' 0755 ${cfg.user} tt_rss - -"
"d '${cfg.root}/cache/feed-icons' 0755 ${cfg.user} tt_rss - -"
"L+ '${cfg.root}/www' - - - - ${servedRoot}"
];
systemd.services = {
phpfpm-tt-rss = mkIf (cfg.pool == "${poolName}") {
restartTriggers = [ servedRoot ];
};
tt-rss = {
description = "Tiny Tiny RSS feeds update daemon";
preStart = ''
${phpPackage}/bin/php ${cfg.root}/www/update.php --update-schema --force-yes
'';
serviceConfig = {
User = "${cfg.user}";
Group = "tt_rss";
ExecStart = "${phpPackage}/bin/php ${cfg.root}/www/update.php --daemon ${cfg.updateDaemon.commandFlags}";
Restart = "on-failure";
RestartSec = "60";
SyslogIdentifier = "tt-rss";
};
wantedBy = [ "multi-user.target" ];
requires = optional mysqlLocal "mysql.service" ++ optional pgsqlLocal "postgresql.target";
after = [
"network.target"
]
++ optional mysqlLocal "mysql.service"
++ optional pgsqlLocal "postgresql.target";
};
};
services.mysql = mkIf mysqlLocal {
enable = true;
package = mkDefault pkgs.mariadb;
ensureDatabases = [ cfg.database.name ];
ensureUsers = [
{
name = cfg.user;
ensurePermissions = {
"${cfg.database.name}.*" = "ALL PRIVILEGES";
};
}
];
};
services.postgresql = mkIf pgsqlLocal {
enable = mkDefault true;
ensureDatabases = [ cfg.database.name ];
ensureUsers = [
{
name = cfg.database.user;
ensureDBOwnership = true;
}
];
};
users.users.tt_rss = optionalAttrs (cfg.user == "tt_rss") {
description = "tt-rss service user";
isSystemUser = true;
group = "tt_rss";
};
users.groups.tt_rss = { };
};
}
+58 -8
View File
@@ -13,6 +13,22 @@ in
enable = lib.mkEnableOption "xscreensaver user service";
package = lib.mkPackageOption pkgs "xscreensaver" { };
hooks = lib.mkOption {
type = with lib.types; attrsOf lines;
description = ''
An attrset of events and commands to run upon each event.
Refer to <https://www.jwz.org/xscreensaver/man3.html> for supported events.
'';
defaultText = lib.literalExpression "{ }";
default = { };
example = lib.literalExpression ''
# Reconfigure autorandr on screen wake up
{
"RUN" = "''${lib.getExe pkgs.autorandr} --change --ignore-lid";
};
'';
};
};
config = lib.mkIf cfg.enable {
@@ -25,14 +41,48 @@ in
source = "${pkgs.xscreensaver}/libexec/xscreensaver/xscreensaver-auth";
};
systemd.user.services.xscreensaver = {
enable = true;
description = "XScreenSaver";
after = [ "graphical-session-pre.target" ];
partOf = [ "graphical-session.target" ];
wantedBy = [ "graphical-session.target" ];
path = [ cfg.package ];
serviceConfig.ExecStart = "${cfg.package}/bin/xscreensaver -no-splash";
systemd.user.services = {
xscreensaver = {
enable = true;
description = "XScreenSaver";
after = [ "graphical-session-pre.target" ];
partOf = [ "graphical-session.target" ];
wantedBy = [ "graphical-session.target" ];
path = [ cfg.package ];
serviceConfig.ExecStart = "${cfg.package}/bin/xscreensaver -no-splash";
};
xscreensaver-hooks = lib.mkIf (cfg.enable && cfg.hooks != { }) {
enable = true;
description = "Run commands on XScreenSaver events";
after = [
"graphical-session.target"
"xscreensaver.service"
];
partOf = [ "graphical-session.target" ];
wantedBy = [ "graphical-session.target" ];
path = [ cfg.package ];
serviceConfig = {
Restart = "always";
};
script =
let
handlers = lib.concatMapAttrsStringSep "\n" (event: action: ''
"${event}")
( ${action}
)
;;
'') cfg.hooks;
in
''
xscreensaver-command -watch | while read event rest; do
echo "XScreenSaver handler script got \"$event\""
case $event in
${handlers}
esac
done
'';
};
};
};
+2 -118
View File
@@ -2,6 +2,7 @@
config,
lib,
pkgs,
utils,
...
}:
let
@@ -54,124 +55,7 @@ let
else
interpreter;
# Mapping of systems to “magicOrExtension” and “mask”. Mostly taken from:
# - https://github.com/cleverca22/nixos-configs/blob/master/qemu.nix
# and
# - https://github.com/qemu/qemu/blob/master/scripts/qemu-binfmt-conf.sh
# TODO: maybe put these in a JSON file?
magics = {
armv6l-linux = {
magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\x00\xff\xfe\xff\xff\xff'';
};
armv7l-linux = {
magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x28\x00'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\x00\xff\xfe\xff\xff\xff'';
};
aarch64-linux = {
magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7\x00'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\x00\xff\xfe\xff\xff\xff'';
};
aarch64_be-linux = {
magicOrExtension = ''\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xb7'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
};
i386-linux = {
magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03\x00'';
mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
};
i486-linux = {
magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00'';
mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
};
i586-linux = {
magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00'';
mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
};
i686-linux = {
magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06\x00'';
mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
};
x86_64-linux = {
magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00'';
mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
};
alpha-linux = {
magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x26\x90'';
mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
};
sparc64-linux = {
magicOrExtension = ''\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
};
sparc-linux = {
magicOrExtension = ''\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x12'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
};
powerpc-linux = {
magicOrExtension = ''\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
};
powerpc64-linux = {
magicOrExtension = ''\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
};
powerpc64le-linux = {
magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x15\x00'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\x00'';
};
mips-linux = {
magicOrExtension = ''\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20'';
};
mipsel-linux = {
magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00'';
};
mips64-linux = {
magicOrExtension = ''\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
};
mips64el-linux = {
magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
};
mips64-linuxabin32 = {
magicOrExtension = ''\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20'';
};
mips64el-linuxabin32 = {
magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\x00\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x20\x00\x00\x00'';
};
riscv32-linux = {
magicOrExtension = ''\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
};
riscv64-linux = {
magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\xf3\x00'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
};
loongarch64-linux = {
magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x02\x01'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\xfc\x00\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
};
wasm32-wasi = {
magicOrExtension = ''\x00asm'';
mask = ''\xff\xff\xff\xff'';
};
wasm64-wasi = {
magicOrExtension = ''\x00asm'';
mask = ''\xff\xff\xff\xff'';
};
s390x-linux = {
magicOrExtension = ''\x7fELF\x02\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x16'';
mask = ''\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff'';
};
x86_64-windows.magicOrExtension = "MZ";
i686-windows.magicOrExtension = "MZ";
};
magics = utils.binfmtMagics;
in
{
imports = [
+2 -2
View File
@@ -647,6 +647,8 @@ in
"sha512"
"af_alg"
"algif_skcipher"
"cryptd"
"input_leds" # for capslock LED on most keyboards in case decryption requires password
];
description = ''
A list of cryptographic kernel modules needed to decrypt the root device(s).
@@ -1135,8 +1137,6 @@ in
boot.initrd.availableKernelModules = [
"dm_mod"
"dm_crypt"
"cryptd"
"input_leds"
]
++ luks.cryptoModules
# workaround until https://marc.info/?l=linux-crypto-vger&m=148783562211457&w=4 is merged
+3 -2
View File
@@ -181,9 +181,10 @@ let
"machines.target"
"systemd-machined.service"
]
++ [
++ optionals cfg.package.withNspawn [
"systemd-nspawn@.service"
]
++ [
# Misc.
"systemd-sysctl.service"
"systemd-machine-id-commit.service"
+1
View File
@@ -87,6 +87,7 @@ in
contents."/etc/unl0kr.conf".source = settingsFormat.generate "unl0kr.conf" cfg.settings;
storePaths = with pkgs; [
libinput
libinput.out
xkeyboard_config
(lib.getExe' cfg.package "unl0kr")
"${cfg.package}/libexec/unl0kr-agent"
+1 -1
View File
@@ -1926,7 +1926,7 @@ in
# Udev attributes for systemd to name the device and to create a .device target.
systemdAttrs =
n:
''NAME:="${n}", ENV{INTERFACE}="${n}", ENV{SYSTEMD_ALIAS}="/sys/subsystem/net/devices/${n}", TAG+="systemd"'';
''NAME:="${n}", ENV{ID_NET_NAME}="${n}", ENV{SYSTEMD_ALIAS}="/sys/subsystem/net/devices/${n}", TAG+="systemd"'';
in
flip (concatMapStringsSep "\n") (attrNames wlanDeviceInterfaces) (
device:
+30 -10
View File
@@ -394,6 +394,11 @@ in
The backend used to setup virtual network firewall rules.
'';
};
dbus = {
enable = mkEnableOption "exposing libvirtd APIs over D-Bus";
package = mkPackageOption pkgs "libvirt-dbus" { };
};
};
###### implementation
@@ -426,15 +431,28 @@ in
boot.kernelModules = [ "tun" ];
users.groups.libvirtd.gid = config.ids.gids.libvirtd;
# libvirtd runs qemu as this user and group by default
users.extraGroups.qemu-libvirtd.gid = config.ids.gids.qemu-libvirtd;
users.extraUsers.qemu-libvirtd = {
uid = config.ids.uids.qemu-libvirtd;
isNormalUser = false;
group = "qemu-libvirtd";
};
users = lib.mkMerge [
{
# libvirtd runs qemu as this user and group by default
users.qemu-libvirtd = {
uid = config.ids.uids.qemu-libvirtd;
isNormalUser = false;
group = "qemu-libvirtd";
};
groups = {
libvirtd.gid = config.ids.gids.libvirtd;
qemu-libvirtd.gid = config.ids.gids.qemu-libvirtd;
};
}
(lib.mkIf cfg.dbus.enable {
users.libvirtdbus = {
isSystemUser = true;
group = "libvirtdbus";
description = "Libvirt D-Bus bridge";
};
groups.libvirtdbus = { };
})
];
security.wrappers.qemu-bridge-helper = {
setuid = true;
@@ -449,7 +467,7 @@ in
services.firewalld.packages = [ cfg.package ];
systemd.packages = [ cfg.package ];
systemd.packages = [ cfg.package ] ++ lib.optional cfg.dbus.enable cfg.dbus.package;
systemd.services.libvirtd-config = {
description = "Libvirt Virtual Machine Management Daemon - configuration";
@@ -629,5 +647,7 @@ in
(mkIf cfg.nss.enable (mkOrder 430 [ "libvirt" ]))
(mkIf cfg.nss.enableGuest (mkOrder 432 [ "libvirt_guest" ]))
];
services.dbus.packages = lib.optional cfg.dbus.enable cfg.dbus.package;
};
}
@@ -30,7 +30,7 @@ let
};
imageFile = mkOption {
type = with types; nullOr package;
type = with types; nullOr pathInStore;
default = null;
description = ''
Path to an image file to load before running the image. This can
+18 -16
View File
@@ -24,23 +24,25 @@ let
inherit (cfg.package) meta;
preferLocalBuild = true;
}
''
mkdir -p $out/bin
ln -s ${cfg.package}/bin/podman $out/bin/docker
(
''
mkdir -p $out/bin
ln -s ${cfg.package}/bin/podman $out/bin/docker
mkdir -p $man/share/man/man1
for f in ${cfg.package.man}/share/man/man1/*; do
basename=$(basename $f | sed s/podman/docker/g)
ln -s $f $man/share/man/man1/$basename
done
''
+ lib.optionalString (!stdenv.buildPlatform.canExecute stdenv.hostPlatform) ''
export HOME=$(mktemp -d) # work around `docker <cmd>`
installShellCompletion --cmd docker \
--bash <($out/bin/docker completion bash) \
--zsh <($out/bin/docker completion zsh) \
--fish <($out/bin/docker completion fish)
'';
mkdir -p $man/share/man/man1
for f in ${cfg.package.man}/share/man/man1/*; do
basename=$(basename $f | sed s/podman/docker/g)
ln -s $f $man/share/man/man1/$basename
done
''
+ lib.optionalString (stdenv.buildPlatform.canExecute stdenv.hostPlatform) ''
export HOME=$(mktemp -d) # work around `docker <cmd>`
installShellCompletion --cmd docker \
--bash <($out/bin/docker completion bash) \
--zsh <($out/bin/docker completion zsh) \
--fish <($out/bin/docker completion fish)
''
);
in
{
+2 -2
View File
@@ -2,6 +2,7 @@
config,
lib,
pkgs,
utils,
...
}:
@@ -72,8 +73,7 @@ in
# The required flags for binfmt are documented by Apple:
# https://developer.apple.com/documentation/virtualization/running_intel_binaries_in_linux_vms_with_rosetta
magicOrExtension = ''\x7fELF\x02\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x3e\x00'';
mask = ''\xff\xff\xff\xff\xff\xfe\xfe\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff'';
inherit (utils.binfmtMagics.x86_64-linux) magicOrExtension mask;
fixBinary = true;
matchCredentials = true;
preserveArgvZero = true;
@@ -95,6 +95,12 @@ in
type = lib.types.bool;
description = "Whether to load vboxsf";
};
use3rdPartyModules = lib.mkOption {
default = true;
type = lib.types.bool;
description = "Whether to use the kernel modules provided by VirtualBox instead of the ones from the upstream kernel.";
};
};
###### implementation
@@ -111,7 +117,7 @@ in
environment.systemPackages = [ kernel.virtualboxGuestAdditions ];
boot.extraModulePackages = [ kernel.virtualboxGuestAdditions ];
boot.extraModulePackages = lib.mkIf cfg.use3rdPartyModules [ kernel.virtualboxGuestAdditions ];
systemd.services.virtualbox = {
description = "VirtualBox Guest Services";
+6 -3
View File
@@ -752,9 +752,11 @@ in
iftop = runTest ./iftop.nix;
image-contents = handleTest ./image-contents.nix { };
immich = runTest ./web-apps/immich.nix;
immich-kiosk = runTest ./web-apps/immich-kiosk.nix;
immich-public-proxy = runTest ./web-apps/immich-public-proxy.nix;
immich-vectorchord-migration = runTest ./web-apps/immich-vectorchord-migration.nix;
immich-vectorchord-reindex = runTest ./web-apps/immich-vectorchord-reindex.nix;
immichframe = runTest ./web-apps/immichframe.nix;
incron = runTest ./incron.nix;
incus = import ./incus {
inherit runTestOn;
@@ -1302,6 +1304,7 @@ in
public-inbox = runTest ./public-inbox.nix;
pufferpanel = runTest ./pufferpanel.nix;
pulseaudio = discoverTests (import ./pulseaudio.nix);
pulseaudio-tcp = runTest ./pulseaudio-tcp.nix;
pykms = runTest ./pykms.nix;
pyload = runTest ./pyload.nix;
qbittorrent = runTest ./qbittorrent.nix;
@@ -1457,9 +1460,7 @@ in
syncthing-guiPassword = runTest ./syncthing/guiPassword.nix;
syncthing-guiPasswordFile = runTest ./syncthing/guiPasswordFile.nix;
syncthing-init = runTest ./syncthing/init.nix;
# FIXME: Test has been failing since 2025-07-06:
# https://github.com/NixOS/nixpkgs/issues/447674
# syncthing-many-devices = runTest ./syncthing/many-devices.nix;
syncthing-many-devices = runTest ./syncthing/many-devices.nix;
syncthing-no-settings = runTest ./syncthing/no-settings.nix;
syncthing-relay = runTest ./syncthing/relay.nix;
sysfs = runTest ./sysfs.nix;
@@ -1581,6 +1582,7 @@ in
trickster = runTest ./trickster.nix;
trilium-server = runTestOn [ "x86_64-linux" ] ./trilium-server.nix;
tsm-client-gui = runTest ./tsm-client-gui.nix;
tt-rss = runTest ./web-apps/tt-rss.nix;
ttyd = runTest ./web-servers/ttyd.nix;
tuliprox = runTest ./tuliprox.nix;
tuned = runTest ./tuned.nix;
@@ -1595,6 +1597,7 @@ in
tzupdate = runTest ./tzupdate.nix;
ucarp = runTest ./ucarp.nix;
udisks2 = runTest ./udisks2.nix;
udp-over-tcp = runTest ./udp-over-tcp.nix;
ulogd = runTest ./ulogd/ulogd.nix;
umami = runTest ./web-apps/umami.nix;
umurmur = runTest ./umurmur.nix;
+17 -17
View File
@@ -32,38 +32,38 @@
# Creates some auto gc roots
# Use /run/current-system so that we do not need to build anything new
machine.succeed("nix build /run/current-system --out-link /tmp/root-auto-gc-root-1")
machine.succeed("nix build /run/current-system --out-link /tmp/root-auto-gc-root-2")
machine.succeed("su normal --command 'nix build /run/current-system --out-link /tmp/user-auto-gc-root-1'")
machine.succeed("su normal --command 'nix build /run/current-system --out-link /tmp/user-auto-gc-root-2'")
machine.succeed("nix build /run/current-system --out-link /tmp/result-root-auto-gc-root-1")
machine.succeed("nix build /run/current-system --out-link /tmp/result-root-auto-gc-root-2")
machine.succeed("su normal --command 'nix build /run/current-system --out-link /tmp/result-user-auto-gc-root-1'")
machine.succeed("su normal --command 'nix build /run/current-system --out-link /tmp/result-user-auto-gc-root-2'")
machine.systemctl("start nix-gc.service")
# Not auto gc root will be removed
machine.succeed("readlink /tmp/root-auto-gc-root-1")
machine.succeed("readlink /tmp/root-auto-gc-root-2")
machine.succeed("readlink /tmp/user-auto-gc-root-1")
machine.succeed("readlink /tmp/user-auto-gc-root-2")
machine.succeed("readlink /tmp/result-root-auto-gc-root-1")
machine.succeed("readlink /tmp/result-root-auto-gc-root-2")
machine.succeed("readlink /tmp/result-user-auto-gc-root-1")
machine.succeed("readlink /tmp/result-user-auto-gc-root-2")
# Change time to 8 days after (greater than 7d)
machine.succeed("date -s '8 days'")
# Touch GC roots `-2`
machine.succeed("touch /tmp/root-auto-gc-root-2 --no-dereference")
machine.succeed("touch /tmp/user-auto-gc-root-2 --no-dereference")
machine.succeed("touch /tmp/result-root-auto-gc-root-2 --no-dereference")
machine.succeed("touch /tmp/result-user-auto-gc-root-2 --no-dereference")
machine.systemctl("start nix-gc.service")
# Only GC roots `-1` are removed
machine.succeed("test ! -f /tmp/root-auto-gc-root-1")
machine.succeed("readlink /tmp/root-auto-gc-root-2")
machine.succeed("test ! -f /tmp/user-auto-gc-root-1")
machine.succeed("readlink /tmp/user-auto-gc-root-2")
machine.succeed("test ! -e /tmp/result-root-auto-gc-root-1")
machine.succeed("readlink /tmp/result-root-auto-gc-root-2")
machine.succeed("test ! -e /tmp/result-user-auto-gc-root-1")
machine.succeed("readlink /tmp/result-user-auto-gc-root-2")
# Change time again
machine.succeed("date -s '8 days'")
machine.systemctl("start nix-gc.service")
# All auto GC roots are removed
machine.succeed("test ! -f /tmp/root-auto-gc-root-2")
machine.succeed("test ! -f /tmp/user-auto-gc-root-2")
machine.succeed("test ! -e /tmp/result-root-auto-gc-root-2")
machine.succeed("test ! -e /tmp/result-user-auto-gc-root-2")
# Direnv integration test
machine.succeed("mkdir /tmp/test-direnv")
@@ -74,7 +74,7 @@
# The root will be removed if we does not use the direnv recently
machine.succeed("date -s '8 days'")
machine.systemctl("start nix-gc.service")
machine.succeed("test ! -f /tmp/test-direnv/.direnv/gc-root")
machine.succeed("test ! -e /tmp/test-direnv/.direnv/gc-root")
# Recreate the root
machine.succeed("nix build /run/current-system --out-link /tmp/test-direnv/.direnv/gc-root")
+6 -4
View File
@@ -7,10 +7,12 @@
{
name = "owasp blint test";
meta.maintainers = with lib; [
maintainers.ethancedwards8
teams.ngi
];
meta.maintainers =
with lib;
[
maintainers.ethancedwards8
]
++ teams.ngi.members;
nodes.machine = {
environment.systemPackages = with pkgs; [
-1
View File
@@ -3,7 +3,6 @@
name = "caddy";
meta = with pkgs.lib.maintainers; {
maintainers = [
Br1ght0ne
stepbrobd
];
};

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