Merge commit '6f456e34e5cf13571ea9c7d6d88436171739e23c' into haskell-updates
This commit is contained in:
@@ -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 }}
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 }}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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: |
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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 [ ]`.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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=";
|
||||
};
|
||||
|
||||
|
||||
@@ -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=";
|
||||
};
|
||||
|
||||
|
||||
@@ -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=";
|
||||
};
|
||||
|
||||
@@ -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 ];
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}
|
||||
|
||||
|
||||
@@ -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 | Dependency’s host platform | Dependency’s 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 | Dependency’s host platform | Dependency’s 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.
|
||||
|
||||
|
||||
@@ -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 derivation’s 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 dependency’s propagated dependencies and adjusting them to account for the “shift in perspective” described by the current dependency’s 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.
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
@@ -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";
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -9,7 +9,6 @@ let
|
||||
cfg = config.programs.bandwhich;
|
||||
in
|
||||
{
|
||||
meta.maintainers = with lib.maintainers; [ Br1ght0ne ];
|
||||
|
||||
options = {
|
||||
programs.bandwhich = {
|
||||
|
||||
@@ -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 ];
|
||||
}
|
||||
@@ -10,6 +10,7 @@ in
|
||||
{
|
||||
meta.maintainers = with lib.maintainers; [
|
||||
NotAShelf
|
||||
mdaniels5757
|
||||
viperML
|
||||
];
|
||||
|
||||
|
||||
@@ -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 ];
|
||||
}
|
||||
@@ -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
|
||||
];
|
||||
|
||||
|
||||
@@ -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."
|
||||
)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
@@ -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}'
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
|
||||
@@ -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`
|
||||
|
||||
@@ -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
|
||||
""
|
||||
}
|
||||
|
||||
@@ -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";
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -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 ];
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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 = { };
|
||||
};
|
||||
}
|
||||
@@ -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,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 = [
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,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";
|
||||
|
||||
@@ -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
@@ -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")
|
||||
|
||||
@@ -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; [
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user