Merge remote-tracking branch 'upstream/master' into mberndt123/stratis-rootfs

This commit is contained in:
Matthias Berndt 2023-05-17 21:47:19 -04:00
commit cb410a8c59
2191 changed files with 123232 additions and 81845 deletions

39
.github/CODEOWNERS vendored
View file

@ -22,19 +22,19 @@
/.editorconfig @Mic92 @zowoq
# Libraries
/lib @edolstra @nbp @infinisil
/lib/systems @alyssais @nbp @ericson2314 @matthewbauer
/lib/generators.nix @edolstra @nbp @Profpatsch
/lib/cli.nix @edolstra @nbp @Profpatsch
/lib/debug.nix @edolstra @nbp @Profpatsch
/lib/asserts.nix @edolstra @nbp @Profpatsch
/lib @edolstra @infinisil
/lib/systems @alyssais @ericson2314 @matthewbauer
/lib/generators.nix @edolstra @Profpatsch
/lib/cli.nix @edolstra @Profpatsch
/lib/debug.nix @edolstra @Profpatsch
/lib/asserts.nix @edolstra @Profpatsch
/lib/path.* @infinisil @fricklerhandwerk
# Nixpkgs Internals
/default.nix @nbp
/pkgs/top-level/default.nix @nbp @Ericson2314
/pkgs/top-level/impure.nix @nbp @Ericson2314
/pkgs/top-level/stage.nix @nbp @Ericson2314 @matthewbauer
/default.nix @Ericson2314
/pkgs/top-level/default.nix @Ericson2314
/pkgs/top-level/impure.nix @Ericson2314
/pkgs/top-level/stage.nix @Ericson2314 @matthewbauer
/pkgs/top-level/splice.nix @Ericson2314 @matthewbauer
/pkgs/top-level/release-cross.nix @Ericson2314 @matthewbauer
/pkgs/stdenv/generic @Ericson2314 @matthewbauer
@ -67,22 +67,9 @@
/doc/using @fricklerhandwerk
# NixOS Internals
/nixos/default.nix @nbp @infinisil
/nixos/lib/from-env.nix @nbp @infinisil
/nixos/lib/eval-config.nix @nbp @infinisil
/nixos/doc/manual/configuration/abstractions.xml @nbp
/nixos/doc/manual/configuration/config-file.xml @nbp
/nixos/doc/manual/configuration/config-syntax.xml @nbp
/nixos/doc/manual/configuration/modularity.xml @nbp
/nixos/doc/manual/development/assertions.xml @nbp
/nixos/doc/manual/development/meta-attributes.xml @nbp
/nixos/doc/manual/development/option-declarations.xml @nbp
/nixos/doc/manual/development/option-def.xml @nbp
/nixos/doc/manual/development/option-types.xml @nbp
/nixos/doc/manual/development/replace-modules.xml @nbp
/nixos/doc/manual/development/writing-modules.xml @nbp
/nixos/doc/manual/man-nixos-option.xml @nbp
/nixos/modules/installer/tools/nixos-option.sh @nbp
/nixos/default.nix @infinisil
/nixos/lib/from-env.nix @infinisil
/nixos/lib/eval-config.nix @infinisil
/nixos/modules/system @dasJ
/nixos/modules/system/activation/bootspec.nix @grahamc @cole-h @raitobezarius
/nixos/modules/system/activation/bootspec.cue @grahamc @cole-h @raitobezarius

View file

@ -164,6 +164,26 @@ tests.fetchgit = testers.invalidateFetcherByDrvHash fetchgit {
};
```
## `runNixOSTest` {#tester-runNixOSTest}
A helper function that behaves exactly like the NixOS `runTest`, except it also assigns this Nixpkgs package set as the `pkgs` of the test and makes the `nixpkgs.*` options read-only.
If your test is part of the Nixpkgs repository, or if you need a more general entrypoint, see ["Calling a test" in the NixOS manual](https://nixos.org/manual/nixos/stable/index.html#sec-calling-nixos-tests).
Example:
```nix
pkgs.testers.runNixOSTest ({ lib, ... }: {
name = "hello";
nodes.machine = { pkgs, ... }: {
environment.systemPackages = [ pkgs.hello ];
};
testScript = ''
machine.succeed("hello")
'';
})
```
## `nixosTest` {#tester-nixosTest}
Run a NixOS VM network test using this evaluation of Nixpkgs.

View file

@ -27,7 +27,7 @@ package set to make it the default. This guarantees you get a consistent package
set.
```nix
mypkg = let
cudaPackages = cudaPackages_11_5.overrideScope' (final: prev {
cudaPackages = cudaPackages_11_5.overrideScope' (final: prev: {
cudnn = prev.cudnn_8_3_2;
}});
in callPackage { inherit cudaPackages; };

View file

@ -0,0 +1,65 @@
# Dart {#sec-language-dart}
## Dart applications {#ssec-dart-applications}
The function `buildDartApplication` builds Dart applications managed with pub.
It fetches its Dart dependencies automatically through `fetchDartDeps`, and (through a series of hooks) builds and installs the executables specified in the pubspec file. The hooks can be used in other derivations, if needed. The phases can also be overridden to do something different from installing binaries.
If you are packaging a Flutter desktop application, use [`buildFlutterApplication`](#ssec-dart-flutter) instead.
`vendorHash`: is the hash of the output of the dependency fetcher derivation. To obtain it, simply set it to `lib.fakeHash` (or omit it) and run the build ([more details here](#sec-source-hashes)).
If the upstream source is missing a `pubspec.lock` file, you'll have to vendor one and specify it using `pubspecLockFile`. If it is needed, one will be generated for you and printed when attempting to build the derivation.
The `dart` commands run can be overridden through `pubGetScript` and `dartCompileCommand`, you can also add flags using `dartCompileFlags` or `dartJitFlags`.
Dart supports multiple [outputs types](https://dart.dev/tools/dart-compile#types-of-output), you can choose between them using `dartOutputType` (defaults to `exe`). If you want to override the binaries path or the source path they come from, you can use `dartEntryPoints`. Outputs that require a runtime will automatically be wrapped with the relevant runtime (`dartaotruntime` for `aot-snapshot`, `dart run` for `jit-snapshot` and `kernel`, `node` for `js`), this can be overridden through `dartRuntimeCommand`.
```nix
{ buildDartApplication, fetchFromGitHub }:
buildDartApplication rec {
pname = "dart-sass";
version = "1.62.1";
src = fetchFromGitHub {
owner = "sass";
repo = pname;
rev = version;
hash = "sha256-U6enz8yJcc4Wf8m54eYIAnVg/jsGi247Wy8lp1r1wg4=";
};
pubspecLockFile = ./pubspec.lock;
vendorHash = "sha256-Atm7zfnDambN/BmmUf4BG0yUz/y6xWzf0reDw3Ad41s=";
}
```
## Flutter applications {#ssec-dart-flutter}
The function `buildFlutterApplication` builds Flutter applications.
The deps.json file must always be provided when packaging in Nixpkgs. It will be generated and printed if the derivation is attempted to be built without one. Alternatively, `autoDepsList` may be set to `true` when outside of Nixpkgs, as it relies on import-from-derivation.
A `pubspec.lock` file must be available. See the [Dart documentation](#ssec-dart-applications) for more details.
```nix
{ flutter, fetchFromGitHub }:
flutter.buildFlutterApplication {
pname = "firmware-updater";
version = "unstable-2023-04-30";
src = fetchFromGitHub {
owner = "canonical";
repo = "firmware-updater";
rev = "6e7dbdb64e344633ea62874b54ff3990bd3b8440";
sha256 = "sha256-s5mwtr5MSPqLMN+k851+pFIFFPa0N1hqz97ys050tFA=";
fetchSubmodules = true;
};
pubspecLockFile = ./pubspec.lock;
depsListFile = ./deps.json;
vendorHash = "sha256-cdMO+tr6kYiN5xKXa+uTMAcFf2C75F3wVPrn21G4QPQ=";
}
```

View file

@ -14,6 +14,7 @@
<xi:include href="crystal.section.xml" />
<xi:include href="cuda.section.xml" />
<xi:include href="cuelang.section.xml" />
<xi:include href="dart.section.xml" />
<xi:include href="dhall.section.xml" />
<xi:include href="dotnet.section.xml" />
<xi:include href="emscripten.section.xml" />

View file

@ -118,7 +118,7 @@ ImageExifTool = buildPerlPackage {
hash = "sha256-vOhB/FwQMC8PPvdnjDvxRpU6jAZcC6GMQfc0AH4uwKg=";
};
buildInputs = lib.optional stdenv.isDarwin shortenPerlShebang;
nativeBuildInputs = lib.optional stdenv.isDarwin shortenPerlShebang;
postInstall = lib.optionalString stdenv.isDarwin ''
shortenPerlShebang $out/bin/exiftool
'';

View file

@ -535,7 +535,9 @@ directory of the `tokenizers` project's source archive, we use
```nix
{ fetchFromGitHub
, buildPythonPackage
, cargo
, rustPlatform
, rustc
, setuptools-rust
}:
@ -558,11 +560,12 @@ buildPythonPackage rec {
sourceRoot = "source/bindings/python";
nativeBuildInputs = [ setuptools-rust ] ++ (with rustPlatform; [
cargoSetupHook
rust.cargo
rust.rustc
]);
nativeBuildInputs = [
cargo
rustPlatform.cargoSetupHook
rustc
setuptools-rust
];
# ...
}

View file

@ -57,6 +57,19 @@
nixosModules = {
notDetected = ./nixos/modules/installer/scan/not-detected.nix;
/*
Make the `nixpkgs.*` configuration read-only. Guarantees that `pkgs`
is the way you initialize it.
Example:
{
imports = [ nixpkgs.nixosModules.readOnlyPkgs ];
nixpkgs.pkgs = nixpkgs.legacyPackages.x86_64-linux;
}
*/
readOnlyPkgs = ./nixos/modules/misc/nixpkgs/read-only.nix;
};
};
}

View file

@ -204,6 +204,11 @@ in mkLicense lset) ({
free = false;
};
caossl = {
fullName = "Computer Associates Open Source Licence Version 1.0";
url = "http://jxplorer.org/licence.html";
};
cal10 = {
fullName = "Cryptographic Autonomy License version 1.0 (CAL-1.0)";
url = "https://opensource.org/licenses/CAL-1.0";
@ -230,6 +235,12 @@ in mkLicense lset) ({
free = false;
};
cc-by-nc-nd-40 = {
spdxId = "CC-BY-NC-ND-4.0";
fullName = "Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International";
free = false;
};
cc-by-nc-sa-20 = {
spdxId = "CC-BY-NC-SA-2.0";
fullName = "Creative Commons Attribution Non Commercial Share Alike 2.0";

View file

@ -261,7 +261,7 @@ rec {
concatMap (opt:
let
name = showOption opt.loc;
docOption = rec {
docOption = {
loc = opt.loc;
inherit name;
description = opt.description or null;
@ -280,9 +280,9 @@ rec {
renderOptionValue opt.example
);
}
// optionalAttrs (opt ? default) {
// optionalAttrs (opt ? defaultText || opt ? default) {
default =
builtins.addErrorContext "while evaluating the default value of option `${name}`" (
builtins.addErrorContext "while evaluating the ${if opt?defaultText then "defaultText" else "default value"} of option `${name}`" (
renderOptionValue (opt.defaultText or opt.default)
);
}

View file

@ -50,6 +50,7 @@ rec {
else if final.isFreeBSD then "fblibc"
else if final.isNetBSD then "nblibc"
else if final.isAvr then "avrlibc"
else if final.isGhcjs then null
else if final.isNone then "newlib"
# TODO(@Ericson2314) think more about other operating systems
else "native/impure";
@ -120,7 +121,7 @@ rec {
({
linux-kernel = args.linux-kernel or {};
gcc = args.gcc or {};
rustc = args.rust or {};
rustc = args.rustc or {};
} // platforms.select final)
linux-kernel gcc rustc;
@ -144,6 +145,7 @@ rec {
else if final.isS390 && !final.isS390x then null
else if final.isx86_64 then "x86_64"
else if final.isx86 then "i386"
else if final.isMips64 then "mips64${lib.optionalString final.isLittleEndian "el"}"
else final.uname.processor;
# Name used by UEFI for architectures.

View file

@ -476,6 +476,14 @@ rec {
check = x: isDerivation x && hasAttr "shellPath" x;
};
pkgs = addCheck
(unique { message = "A Nixpkgs pkgs set can not be merged with another pkgs set."; } attrs // {
name = "pkgs";
descriptionClass = "noun";
description = "Nixpkgs package set";
})
(x: (x._type or null) == "pkgs");
path = mkOptionType {
name = "path";
descriptionClass = "noun";
@ -767,9 +775,11 @@ rec {
};
binOp = lhs: rhs: {
class =
if lhs.class == null then rhs.class
else if rhs.class == null then lhs.class
else if lhs.class == rhs.class then lhs.class
# `or null` was added for backwards compatibility only. `class` is
# always set in the current version of the module system.
if lhs.class or null == null then rhs.class or null
else if rhs.class or null == null then lhs.class or null
else if lhs.class or null == rhs.class then lhs.class or null
else throw "A submoduleWith option is declared multiple times with conflicting class values \"${toString lhs.class}\" and \"${toString rhs.class}\".";
modules = lhs.modules ++ rhs.modules;
specialArgs =

View file

@ -579,6 +579,12 @@
githubId = 20405311;
name = "Aksh Gupta";
};
alanpearce = {
email = "alan@alanpearce.eu";
github = "alanpearce";
githubId = 850317;
name = "Alan Pearce";
};
alapshin = {
email = "alapshin@fastmail.com";
github = "alapshin";
@ -990,7 +996,7 @@
name = "Stanislas Lange";
};
AngryAnt = {
name = "Emil Johansen";
name = "Emil \"AngryAnt\" Johansen";
email = "git@eej.dk";
matrix = "@angryant:envs.net";
github = "AngryAnt";
@ -1520,6 +1526,12 @@
githubId = 12958979;
name = "Mika Naylor";
};
autrimpo = {
email = "michal@koutensky.net";
github = "autrimpo";
githubId = 5968483;
name = "Michal Koutenský";
};
autumnal = {
name = "Sven Friedrich";
email = "sven@autumnal.de";
@ -2406,6 +2418,12 @@
githubId = 51231053;
name = "Daniel";
};
cadkin = {
email = "cva@siliconslumber.net";
name = "Cameron Adkins";
github = "cadkin";
githubId = 34077838;
};
cafkafk = {
email = "christina@cafkafk.com";
matrix = "@cafkafk:matrix.cafkafk.com";
@ -3466,6 +3484,12 @@
githubId = 1298344;
name = "Daniel Fullmer";
};
daniyalsuri6 = {
email = "daniyal.suri@gmail.com";
github = "daniyalsuri6";
githubId = 107034852;
name = "Daniyal Suri";
};
dansbandit = {
github = "dansbandit";
githubId = 4530687;
@ -3748,13 +3772,6 @@
githubId = 62989;
name = "Demyan Rogozhin";
};
dennajort = {
email = "gosselinjb@gmail.com";
matrix = "@dennajort:matrix.org";
github = "dennajort";
githubId = 1536838;
name = "Jean-Baptiste Gosselin";
};
derchris = {
email = "derchris@me.com";
github = "derchrisuk";
@ -4946,6 +4963,12 @@
githubId = 25955146;
name = "eyJhb";
};
f2k1de = {
name = "f2k1de";
email = "hi@f2k1.de";
github = "f2k1de";
githubId = 11199213;
};
f4814n = {
email = "me@f4814n.de";
github = "f4814";
@ -6204,6 +6227,12 @@
githubId = 982322;
name = "Henrik Olsson";
};
henrirosten = {
email = "henri.rosten@unikie.com";
github = "henrirosten";
githubId = 49935860;
name = "Henri Rosten";
};
henrytill = {
email = "henrytill@gmail.com";
github = "henrytill";
@ -6274,6 +6303,14 @@
github = "higebu";
githubId = 733288;
};
hikari = {
email = "HikariNee@protonmail.com";
github = "HikariNee";
githubId = 72349937;
name = "Hikari";
};
hiljusti = {
name = "J.R. Hill";
email = "hiljusti@so.dang.cool";
@ -6286,6 +6323,7 @@
githubId = 19825977;
name = "Hiren Shah";
};
hiro98 = {
email = "hiro@protagon.space";
github = "vale981";
@ -6774,6 +6812,15 @@
githubId = 54999;
name = "Ariel Nunez";
};
Intuinewin = {
email = "antoinelabarussias@gmail.com";
github = "Intuinewin";
githubId = 13691729;
name = "Antoine Labarussias";
keys = [{
fingerprint = "5CB5 9AA0 D180 1997 2FB3 E0EC 943A 1DE9 372E BE4E";
}];
};
ionutnechita = {
email = "ionut_n2001@yahoo.com";
github = "ionutnechita";
@ -7040,7 +7087,7 @@
};
jayesh-bhoot = {
name = "Jayesh Bhoot";
email = "jayesh@bhoot.sh";
email = "jb@jayeshbhoot.com";
github = "jayeshbhoot";
githubId = 1915507;
};
@ -7075,6 +7122,13 @@
githubId = 221929;
name = "Jean-Baptiste Giraudeau";
};
jbgosselin = {
email = "gosselinjb@gmail.com";
matrix = "@dennajort:matrix.org";
github = "jbgosselin";
githubId = 1536838;
name = "Jean-Baptiste Gosselin";
};
jboy = {
email = "jboy+nixos@bius.moe";
githubId = 2187261;
@ -7406,6 +7460,12 @@
fingerprint = "B768 6CD7 451A 650D 9C54 4204 6710 CF0C 1CBD 7762";
}];
};
jleightcap = {
email = "jack@leightcap.com";
github = "jleightcap";
githubId = 30168080;
name = "Jack Leightcap";
};
jlesquembre = {
email = "jl@lafuente.me";
github = "jlesquembre";
@ -7887,6 +7947,12 @@
githubId = 2469618;
name = "Junji Hashimoto";
};
jurraca = {
email = "julienu@pm.me";
github = "jurraca";
githubId = 5124422;
name = "Julien Urraca";
};
justinas = {
email = "justinas@justinas.org";
github = "justinas";
@ -8067,6 +8133,13 @@
githubId = 524492;
name = "Sergey Kazenyuk";
};
kbdharun = {
email = "kbdharunkrishna@gmail.com";
matrix = "@kbdk:matrix.org";
github = "kbdharun";
githubId = 26346867;
name = "K.B.Dharun Krishna";
};
kcalvinalvin = {
email = "calvin@kcalvinalvin.info";
github = "kcalvinalvin";
@ -9008,6 +9081,12 @@
fingerprint = "74F5 E5CC 19D3 B5CB 608F 6124 68FF 81E6 A785 0F49";
}];
};
lizelive = {
email = "nixpkgs@lize.live";
github = "lizelive";
githubId = 40217331;
name = "LizeLive";
};
lluchs = {
email = "lukas.werling@gmail.com";
github = "lluchs";
@ -10178,6 +10257,15 @@
github = "michaelgrahamevans";
githubId = 5932424;
};
michaelpachec0 = {
email = "michaelpacheco@protonmail.com";
name = "Michael Pacheco";
github = "MichaelPachec0";
githubId = 48970112;
keys = [ {
fingerprint = "8D12 991F 5558 C501 70B2 779C 7811 46B0 B5F9 5F64";
}];
};
michaelpj = {
email = "michaelpj@gmail.com";
github = "michaelpj";
@ -12580,9 +12668,9 @@
githubId = 17690377;
};
ppom = {
name = "Paco Pompeani";
email = "paco@ecomail.io";
github = "aopom";
name = "ppom";
email = "ppom@ecomail.fr";
github = "ppom0";
githubId = 38916722;
};
pradeepchhetri = {
@ -12938,6 +13026,12 @@
githubId = 903072;
name = "Raghav Sood";
};
ragingpastry = {
email = "senior.crepe@gmail.com";
github = "ragingpastry";
githubId = 6778250;
name = "Nick Wilburn";
};
raitobezarius = {
email = "ryan@lahfa.xyz";
matrix = "@raitobezarius:matrix.org";
@ -14295,6 +14389,12 @@
githubId = 487050;
name = "Shea Levy";
};
shlok = {
email = "sd-nix-maintainer@quant.is";
github = "shlok";
githubId = 3000933;
name = "Shlok Datye";
};
shmish111 = {
email = "shmish111@gmail.com";
github = "shmish111";
@ -14783,7 +14883,7 @@
name = "Christoph Honal";
};
star-szr = {
email = "nixpkgs@scottr.mailworks.org";
email = "nixpkgs@szr.fastmail.com";
github = "star-szr";
githubId = 327943;
name = "Scott Zhu Reeves";
@ -15555,6 +15655,15 @@
githubId = 57180880;
name = "Ansh Tyagi";
};
therealr5 = {
email = "rouven@rfive.de";
github = "therealr5";
githubId = 72568063;
name = "Rouven Seifert";
keys = [{
fingerprint = "1169 87A8 DD3F 78FF 8601 BF4D B95E 8FE6 B11C 4D09";
}];
};
therishidesai = {
email = "desai.rishi1@gmail.com";
github = "therishidesai";
@ -15853,6 +15962,12 @@
githubId = 8577941;
name = "Kevin Rauscher";
};
tomaskala = {
email = "public+nixpkgs@tomaskala.com";
github = "tomaskala";
githubId = 7727887;
name = "Tomas Kala";
};
tomberek = {
email = "tomberek@gmail.com";
matrix = "@tomberek:matrix.org";

View file

@ -50,19 +50,22 @@ while (@ARGV) {
}
}
my $bucket;
# S3 setup.
my $aws_access_key_id = $ENV{'AWS_ACCESS_KEY_ID'} or die "AWS_ACCESS_KEY_ID not set\n";
my $aws_secret_access_key = $ENV{'AWS_SECRET_ACCESS_KEY'} or die "AWS_SECRET_ACCESS_KEY not set\n";
if (not defined $ENV{DEBUG}) {
# S3 setup.
my $aws_access_key_id = $ENV{'AWS_ACCESS_KEY_ID'} or die "AWS_ACCESS_KEY_ID not set\n";
my $aws_secret_access_key = $ENV{'AWS_SECRET_ACCESS_KEY'} or die "AWS_SECRET_ACCESS_KEY not set\n";
my $s3 = Net::Amazon::S3->new(
{ aws_access_key_id => $aws_access_key_id,
aws_secret_access_key => $aws_secret_access_key,
retry => 1,
host => "s3-eu-west-1.amazonaws.com",
});
my $s3 = Net::Amazon::S3->new(
{ aws_access_key_id => $aws_access_key_id,
aws_secret_access_key => $aws_secret_access_key,
retry => 1,
host => "s3-eu-west-1.amazonaws.com",
});
my $bucket = $s3->bucket("nixpkgs-tarballs") or die;
$bucket = $s3->bucket("nixpkgs-tarballs") or die;
}
my $doWrite = 0;
my $cacheFile = ($ENV{"HOME"} or die "\$HOME is not set") . "/.cache/nix/copy-tarballs";
@ -159,13 +162,18 @@ elsif (defined $expr) {
# Check every fetchurl call discovered by find-tarballs.nix.
my $mirrored = 0;
my $have = 0;
foreach my $fetch (sort { $a->{url} cmp $b->{url} } @{$fetches}) {
my $url = $fetch->{url};
foreach my $fetch (sort { $a->{urls}->[0] cmp $b->{urls}->[0] } @{$fetches}) {
my $urls = $fetch->{urls};
my $algo = $fetch->{type};
my $hash = $fetch->{hash};
my $name = $fetch->{name};
my $isPatch = $fetch->{isPatch};
if ($isPatch) {
print STDERR "skipping $urls->[0] (support for patches is missing)\n";
next;
}
if ($hash =~ /^([a-z0-9]+)-([A-Za-z0-9+\/=]+)$/) {
$algo = $1;
$hash = `nix hash to-base16 $hash` or die;
@ -180,62 +188,60 @@ elsif (defined $expr) {
chomp $hash;
}
if (defined $ENV{DEBUG}) {
print "$url $algo $hash\n";
next;
}
if ($url !~ /^http:/ && $url !~ /^https:/ && $url !~ /^ftp:/ && $url !~ /^mirror:/) {
print STDERR "skipping $url (unsupported scheme)\n";
next;
}
if ($isPatch) {
print STDERR "skipping $url (support for patches is missing)\n";
next;
}
next if defined $exclude && $url =~ /$exclude/;
if (alreadyMirrored($algo, $hash)) {
$have++;
next;
}
my $storePath = makeFixedOutputPath(0, $algo, $hash, $name);
print STDERR "mirroring $url ($storePath, $algo, $hash)...\n";
for my $url (@$urls) {
if (defined $ENV{DEBUG}) {
print "$url $algo $hash\n";
next;
}
if ($dryRun) {
if ($url !~ /^http:/ && $url !~ /^https:/ && $url !~ /^ftp:/ && $url !~ /^mirror:/) {
print STDERR "skipping $url (unsupported scheme)\n";
next;
}
next if defined $exclude && $url =~ /$exclude/;
if (alreadyMirrored($algo, $hash)) {
$have++;
last;
}
print STDERR "mirroring $url ($storePath, $algo, $hash)...\n";
if ($dryRun) {
$mirrored++;
last;
}
# Substitute the output.
if (!isValidPath($storePath)) {
system("nix-store", "-r", $storePath);
}
# Otherwise download the file using nix-prefetch-url.
if (!isValidPath($storePath)) {
$ENV{QUIET} = 1;
$ENV{PRINT_PATH} = 1;
my $fh;
my $pid = open($fh, "-|", "nix-prefetch-url", "--type", $algo, $url, $hash) or die;
waitpid($pid, 0) or die;
if ($? != 0) {
print STDERR "failed to fetch $url: $?\n";
next;
}
<$fh>; my $storePath2 = <$fh>; chomp $storePath2;
if ($storePath ne $storePath2) {
warn "strange: $storePath != $storePath2\n";
next;
}
}
uploadFile($storePath, $url);
$mirrored++;
next;
last;
}
# Substitute the output.
if (!isValidPath($storePath)) {
system("nix-store", "-r", $storePath);
}
# Otherwise download the file using nix-prefetch-url.
if (!isValidPath($storePath)) {
$ENV{QUIET} = 1;
$ENV{PRINT_PATH} = 1;
my $fh;
my $pid = open($fh, "-|", "nix-prefetch-url", "--type", $algo, $url, $hash) or die;
waitpid($pid, 0) or die;
if ($? != 0) {
print STDERR "failed to fetch $url: $?\n";
next;
}
<$fh>; my $storePath2 = <$fh>; chomp $storePath2;
if ($storePath ne $storePath2) {
warn "strange: $storePath != $storePath2\n";
next;
}
}
uploadFile($storePath, $url);
$mirrored++;
}
print STDERR "mirrored $mirrored files, already have $have files\n";

View file

@ -9,12 +9,12 @@ let
root = expr;
uniqueUrls = map (x: x.file) (genericClosure {
startSet = map (file: { key = file.url; inherit file; }) urls;
uniqueFiles = map (x: x.file) (genericClosure {
startSet = map (file: { key = with file; (if type == null then "" else type + "+") + hash; inherit file; }) files;
operator = const [ ];
});
urls = map (drv: { url = head (drv.urls or [ drv.url ]); hash = drv.outputHash; isPatch = (drv?postFetch && drv.postFetch != ""); type = drv.outputHashAlgo; name = drv.name; }) fetchurlDependencies;
files = map (drv: { urls = drv.urls or [ drv.url ]; hash = drv.outputHash; isPatch = (drv?postFetch && drv.postFetch != ""); type = drv.outputHashAlgo; name = drv.name; }) fetchurlDependencies;
fetchurlDependencies =
filter
@ -47,4 +47,4 @@ let
canEval = val: (builtins.tryEval val).success;
in uniqueUrls
in uniqueFiles

View file

@ -85,7 +85,8 @@ echo "Updating Stackage..."
echo "Updating Hackage hashes..."
./maintainers/scripts/haskell/update-hackage.sh --do-commit
echo "Regenerating Hackage packages..."
./maintainers/scripts/haskell/regenerate-hackage-packages.sh --do-commit
# Using fast here because after the hackage-update eval errors will likely break the transitive dependencies check.
./maintainers/scripts/haskell/regenerate-hackage-packages.sh --fast --do-commit
# Push these new commits to the haskell-updates branch
echo "Pushing commits just created to the remote haskell-updates branch..."

View file

@ -1,9 +1,18 @@
#! /usr/bin/env nix-shell
#! nix-shell -i bash -p coreutils jq nix -I nixpkgs=.
set -euo pipefail
TMP_TEMPLATE=transitive-broken.XXXXXXX
readonly TMP_TEMPLATE
tmpfile=$(mktemp "$TMP_TEMPLATE")
trap 'rm -f "${tmpfile}"' 0
config_file=pkgs/development/haskell-modules/configuration-hackage2nix/transitive-broken.yaml
cat > $config_file << EOF
cat > $tmpfile << EOF
# This file is automatically generated by
# maintainers/scripts/haskell/regenerate-transitive-broken-packages.sh
# It is supposed to list all haskellPackages that cannot evaluate because they
@ -11,4 +20,6 @@ cat > $config_file << EOF
dont-distribute-packages:
EOF
nix-instantiate --eval --option restrict-eval true -I . --strict --json maintainers/scripts/haskell/transitive-broken-packages.nix | jq -r . | LC_ALL=C.UTF-8 sort -i >> $config_file
nix-instantiate --eval --option restrict-eval true -I . --strict --json maintainers/scripts/haskell/transitive-broken-packages.nix | jq -r . | LC_ALL=C.UTF-8 sort -i >> $tmpfile
mv $tmpfile $config_file

View file

@ -151,6 +151,8 @@ with lib.maintainers; {
cuda = {
members = [
connorbaker
samuela
SomeoneSerge
];
scope = "Maintain CUDA-enabled packages";
@ -521,6 +523,7 @@ with lib.maintainers; {
mate = {
members = [
bobby285271
j03
romildo
];
@ -827,6 +830,7 @@ with lib.maintainers; {
xfce = {
members = [
bobby285271
romildo
muscaln
];

View file

@ -99,6 +99,10 @@ merging is handled.
problems.
:::
`types.pkgs`
: A type for the top level Nixpkgs package set.
### Numeric types {#sec-option-types-numeric}
`types.int`

View file

@ -4,7 +4,7 @@ This manual describes how to install, use and extend NixOS, a Linux distribution
Additional information regarding the Nix package manager and the Nixpkgs project can be found in respectively the [Nix manual](https://nixos.org/nix/manual) and the [Nixpkgs manual](https://nixos.org/nixpkgs/manual).
If you encounter problems, please report them on the [`Discourse`](https://discourse.nixos.org), the [Matrix room](https://matrix.to/#nix:nixos.org), or on the [`#nixos` channel on Libera.Chat](irc://irc.libera.chat/#nixos). Alternatively, consider [contributing to this manual](#chap-contributing). Bugs should be reported in [NixOS GitHub issue tracker](https://github.com/NixOS/nixpkgs/issues).
If you encounter problems, please report them on the [`Discourse`](https://discourse.nixos.org), the [Matrix room](https://matrix.to/#/%23nix:nixos.org), or on the [`#nixos` channel on Libera.Chat](irc://irc.libera.chat/#nixos). Alternatively, consider [contributing to this manual](#chap-contributing). Bugs should be reported in [NixOS GitHub issue tracker](https://github.com/NixOS/nixpkgs/issues).
::: {.note}
Commands prefixed with `#` have to be run as root, either requiring to login as root user or temporarily switching to it using `sudo` for example.

View file

@ -24,6 +24,8 @@ In addition to numerous new and upgraded packages, this release has the followin
- KDE Plasma has been updated to v5.27, see [the release notes](https://kde.org/announcements/plasma/5/5.27.0/) for what is changed.
- Python implements [PEP 668](https://peps.python.org/pep-0668/), providing better feedback to users that try to run `pip install` system-wide.
- `nixos-rebuild` now supports an extra `--specialisation` option that can be used to change specialisation for `switch` and `test` commands.
- `libxcrypt`, the library providing the `crypt(3)` password hashing function, is now built without support for algorithms not flagged [`strong`](https://github.com/besser82/libxcrypt/blob/v4.4.33/lib/hashes.conf#L48). This affects the availability of password hashing algorithms used for system login (`login(1)`, `passwd(1)`), but also Apache2 Basic-Auth, Samba, OpenLDAP, Dovecot, and [many other packages](https://github.com/search?q=repo%3ANixOS%2Fnixpkgs%20libxcrypt&type=code).
@ -36,6 +38,8 @@ In addition to numerous new and upgraded packages, this release has the followin
- [Akkoma](https://akkoma.social), an ActivityPub microblogging server. Available as [services.akkoma](options.html#opt-services.akkoma.enable).
- [Pixelfed](https://pixelfed.org/), an Instagram-like ActivityPub server. Available as [services.pixelfed](options.html#opt-services.pixelfed.enable).
- [blesh](https://github.com/akinomyoga/ble.sh), a line editor written in pure bash. Available as [programs.bash.blesh](#opt-programs.bash.blesh.enable).
- [webhook](https://github.com/adnanh/webhook), a lightweight webhook server. Available as [services.webhook](#opt-services.webhook.enable).
@ -56,8 +60,12 @@ In addition to numerous new and upgraded packages, this release has the followin
- [gemstash](https://github.com/rubygems/gemstash), a RubyGems.org cache and private gem server. Available as [services.gemstash](#opt-services.gemstash.enable).
- [gitea-actions-runner](https://gitea.com/gitea/act_runner), a CI runner for Gitea/Forgejo Actions. Available as [services.gitea-actions-runner](#opt-services.gitea-actions-runner.instances).
- [gmediarender](https://github.com/hzeller/gmrender-resurrect), a simple, headless UPnP/DLNA renderer. Available as [services.gmediarender](options.html#opt-services.gmediarender.enable).
- [harmonia](https://github.com/nix-community/harmonia/), Nix binary cache implemented in rust using libnix-store. Available as [services.harmonia](options.html#opt-services.harmonia.enable).
- [hyprland](https://github.com/hyprwm/hyprland), a dynamic tiling Wayland compositor that doesn't sacrifice on its looks. Available as [programs.hyprland](#opt-programs.hyprland.enable).
- [minipro](https://gitlab.com/DavidGriffith/minipro/), an open source program for controlling the MiniPRO TL866xx series of chip programmers. Available as [programs.minipro](options.html#opt-programs.minipro.enable).
@ -88,6 +96,8 @@ In addition to numerous new and upgraded packages, this release has the followin
- [networkd-dispatcher](https://gitlab.com/craftyguy/networkd-dispatcher), a dispatcher service for systemd-networkd connection status changes. Available as [services.networkd-dispatcher](#opt-services.networkd-dispatcher.enable).
- [gonic](https://github.com/sentriz/gonic), a Subsonic music streaming server. Available as [services.gonic](#opt-services.gonic.enable).
- [mmsd](https://gitlab.com/kop316/mmsd), a lower level daemon that transmits and recieves MMSes. Available as [services.mmsd](#opt-services.mmsd.enable).
- [QDMR](https://dm3mat.darc.de/qdmr/), a GUI application and command line tool for programming DMR radios [programs.qdmr](#opt-programs.qdmr.enable)
@ -98,8 +108,12 @@ In addition to numerous new and upgraded packages, this release has the followin
- [vault-agent](https://developer.hashicorp.com/vault/docs/agent), a template rendering and API auth proxy for HashiCorp Vault, similar to `consul-template`. Available as [services.vault-agent](#opt-services.vault-agent.instances).
- [trippy](https://github.com/fujiapple852/trippy), a network diagnostic tool. Available as [programs.trippy](#opt-programs.trippy.enable).
- [v2rayA](https://v2raya.org), a Linux web GUI client of Project V which supports V2Ray, Xray, SS, SSR, Trojan and Pingtunnel. Available as [services.v2raya](options.html#opt-services.v2raya.enable).
- [rshim](https://github.com/Mellanox/rshim-user-space), the user-space rshim driver for the BlueField SoC. Available as [services.rshim](options.html#opt-services.rshim.enable).
- [wstunnel](https://github.com/erebe/wstunnel), a proxy tunnelling arbitrary TCP or UDP traffic through a WebSocket connection. Instances may be configured via [services.wstunnel](options.html#opt-services.wstunnel.enable).
- [ulogd](https://www.netfilter.org/projects/ulogd/index.html), a userspace logging daemon for netfilter/iptables related logging. Available as [services.ulogd](options.html#opt-services.ulogd.enable).
@ -110,8 +124,14 @@ In addition to numerous new and upgraded packages, this release has the followin
- [stargazer](https://sr.ht/~zethra/stargazer/), a fast and easy to use Gemini server. Available as [services.stargazer](#opt-services.stargazer.enable).
- [sniffnet](https://github.com/GyulyVGC/sniffnet), an application to monitor your network traffic. Available as [programs.sniffnet](#opt-programs.sniffnet.enable).
- [photoprism](https://photoprism.app/), a AI-Powered Photos App for the Decentralized Web. Available as [services.photoprism](options.html#opt-services.photoprism.enable).
- [alice-lg](github.com/alice-lg/alice-lg), a looking-glass for BGP sessions. Available as [services.alice-lg](#opt-services.alice-lg.enable).
- [birdwatcher](github.com/alice-lg/birdwatcher), a small HTTP server meant to provide an API defined by Barry O'Donovan's birds-eye to the BIRD internet routing daemon. Available as [services.birdwatcher](#opt-services.birdwatcher.enable).
- [peroxide](https://github.com/ljanyst/peroxide), a fork of the official [ProtonMail bridge](https://github.com/ProtonMail/proton-bridge) that aims to be similar to [Hydroxide](https://github.com/emersion/hydroxide). Available as [services.peroxide](#opt-services.peroxide.enable).
- [autosuspend](https://github.com/languitar/autosuspend), a python daemon that suspends a system if certain conditions are met, or not met.
@ -138,6 +158,8 @@ In addition to numerous new and upgraded packages, this release has the followin
- [ivpn](https://www.ivpn.net/), a secure, private VPN with fast WireGuard connections. Available as [services.ivpn](#opt-services.ivpn.enable).
- [openvscode-server](https://github.com/gitpod-io/openvscode-server), run VS Code on a remote machine with access through a modern web browser from any device, anywhere. Available as [services.openvscode-server](#opt-services.openvscode-server.enable).
## Backward Incompatibilities {#sec-release-23.05-incompatibilities}
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
@ -154,6 +176,8 @@ In addition to numerous new and upgraded packages, this release has the followin
- The `ssh` client tool now disables the `~C` escape sequence by default. This can be re-enabled by setting `EnableEscapeCommandline yes`
- Many `services.syncthing` options have been moved to `services.syncthing.settings`, as part of [RFC 42](https://github.com/NixOS/rfcs/pull/42)'s implementation, see [#226088](https://github.com/NixOS/nixpkgs/pull/226088).
- The `ssh` module does not read `/etc/ssh/ssh_known_hosts2` anymore since this location is [deprecated since 2001](https://marc.info/?l=openssh-unix-dev&m=100508718416162&w=2).
- The openssh module does not read `~/.ssh/authorized_keys2` anymore since this location is [deprecated since 2001](https://marc.info/?l=openssh-unix-dev&m=100508718416162&w=2).
@ -162,6 +186,8 @@ In addition to numerous new and upgraded packages, this release has the followin
- `git-bug` has been updated to at least version 0.8.0, which includes backwards incompatible changes. The `git-bug-migration` package can be used to upgrade existing repositories.
- `graylog` has been updated to version 5, which can not be upgraded directly from the previously packaged version 3.3. If you had installed the previously packaged version 3.3, please follow the [upgrade path](https://go2docs.graylog.org/5-0/upgrading_graylog/upgrade_path.htm) from 3.3 to 4.0 to 4.3 to 5.0.
- `nushell` has been updated to at least version 0.77.0, which includes potential breaking changes in aliases. The old aliases are now available as `old-alias` but it is recommended you migrate to the new format. See [Reworked aliases](https://www.nushell.sh/blog/2023-03-14-nushell_0_77.html#reworked-aliases-breaking-changes-kubouch).
- `keepassx` and `keepassx2` have been removed, due to upstream [stopping development](https://www.keepassx.org/index.html%3Fp=636.html). Consider [KeePassXC](https://keepassxc.org) as a maintained alternative.
@ -177,6 +203,26 @@ In addition to numerous new and upgraded packages, this release has the followin
- `services.sourcehut.dispatch` and the corresponding package (`sourcehut.dispatchsrht`) have been removed due to [upstream deprecation](https://sourcehut.org/blog/2022-08-01-dispatch-deprecation-plans/).
- The attributes used by `services.snapper.configs.<name>` have changed. Migrate from this:
```nix
services.snapper.configs.example = {
subvolume = "/example";
extraConfig = ''
ALLOW_USERS="alice"
'';
};
```
to this:
```nix
services.snapper.configs.example = {
SUBVOLUME = "/example";
ALLOW_USERS = [ "alice" ];
};
```
- The [services.snapserver.openFirewall](#opt-services.snapserver.openFirewall) module option default value has been changed from `true` to `false`. You will need to explicitly set this option to `true`, or configure your firewall.
- The [services.tmate-ssh-server.openFirewall](#opt-services.tmate-ssh-server.openFirewall) module option default value has been changed from `true` to `false`. You will need to explicitly set this option to `true`, or configure your firewall.
@ -225,7 +271,6 @@ In addition to numerous new and upgraded packages, this release has the followin
- [`services.nextcloud.database.createLocally`](#opt-services.nextcloud.database.createLocally) now uses socket authentication and is no longer compatible with password authentication.
- If you want the module to manage the database for you, unset [`services.nextcloud.config.dbpassFile`](#opt-services.nextcloud.config.dbpassFile) (and [`services.nextcloud.config.dbhost`](#opt-services.nextcloud.config.dbhost), if it's set).
- If your database is external, simply set [`services.nextcloud.database.createLocally`](#opt-services.nextcloud.database.createLocally) to `false`.
- If you want to use password authentication **and** create the database locally, you will have to use [`services.mysql`](#opt-services.mysql.enable) to set it up.
- `protonmail-bridge` package has been updated to major version 3.
@ -259,6 +304,8 @@ In addition to numerous new and upgraded packages, this release has the followin
- [services.xserver.videoDrivers](options.html#opt-services.xserver.videoDrivers) now defaults to the `modesetting` driver over device-specific ones. The `radeon`, `amdgpu` and `nouveau` drivers are still available, but effectively unmaintained and not recommended for use.
- [services.xserver.libinput.enable](options.html#opt-services.xserver.libinput.enable) is now set by default, enabling the more actively maintained and consistently behaved input device driver.
- To enable the HTTP3 (QUIC) protocol for a nginx virtual host, set the `quic` attribute on it to true, e.g. `services.nginx.virtualHosts.<name>.quic = true;`.
- In `services.fail2ban`, `bantime-increment.<name>` options now default to `null` (except `bantime-increment.enable`) and are used to set the corresponding option in `jail.local` only if not `null`. Also, enforce that `bantime-increment.formula` and `bantime-increment.multipliers` are not both specified.
@ -288,6 +335,8 @@ In addition to numerous new and upgraded packages, this release has the followin
- The `zplug` package changes its output path from `$out` to `$out/share/zplug`. Users should update their dependency on `${pkgs.zplug}/init.zsh` to `${pkgs.zplug}/share/zplug/init.zsh`.
- The `pict-rs` package was updated from an 0.3 alpha release to 0.3 stable, and related environment variables now require two underscores instead of one.
## Other Notable Changes {#sec-release-23.05-notable-changes}
<!-- To avoid merge conflicts, consider adding your item at an arbitrary place in the list instead. -->
@ -334,13 +383,15 @@ In addition to numerous new and upgraded packages, this release has the followin
- `services.maddy` got several updates:
- Configuration of users and their credentials using `services.maddy.ensureCredentials`.
- Configuration of TLS key and certificate files using `services.maddy.tls`.
- TLS configuration is now possible via `services.maddy.tls` with two loaders present: ACME and file based.
- The `dnsmasq` service now takes configuration via the
`services.dnsmasq.settings` attribute set. The option
`services.dnsmasq.extraConfig` will be deprecated when NixOS 22.11 reaches
end of life.
- `kube3d` has now been renamed to `k3d` since the 3d editor that originally took that name has been dropped from nixpkgs. `kube3d` will continue to work as an alias for now.
- The `dokuwiki` service is now configured via `services.dokuwiki.sites.<name>.settings` attribute set; `extraConfig` has been removed.
The `{aclUse,superUser,disableActions}` attributes have been renamed accordingly. `pluginsConfig` now only accepts an attribute set of booleans.
Passing plain PHP is no longer possible.
@ -367,6 +418,28 @@ In addition to numerous new and upgraded packages, this release has the followin
- `nextcloud` has an option to enable SSE-C in S3.
- NixOS swap partitions with random encryption can now control the sector size, cipher, and key size used to setup the plain encryption device over the
underlying block device rather than allowing them to be determined by `cryptsetup(8)`. One can use these features like so:
```nix
{
swapDevices = [
{
device = "/dev/disk/by-partlabel/swapspace";
randomEncryption = {
enable = true;
cipher = "aes-xts-plain64";
keySize = 512;
sectorSize = 4096;
};
}
];
}
```
- New option `security.pam.zfs` to enable unlocking and mounting of encrypted ZFS home dataset at login.
- `services.peertube` now requires you to specify the secret file `secrets.secretsFile`. It can be generated by running `openssl rand -hex 32`.
Before upgrading, read the release notes for PeerTube:
- [Release v5.0.0](https://github.com/Chocobozzz/PeerTube/releases/tag/v5.0.0)
@ -385,6 +458,8 @@ In addition to numerous new and upgraded packages, this release has the followin
}
```
- `services.netdata` offers a `deadlineBeforeStopSec` option which enable users who have netdata instance that takes time to initialize to not have systemd kill them for no reason.
- `services.dhcpcd` service now don't solicit or accept IPv6 Router Advertisements on interfaces that use static IPv6 addresses.
If network uses both IPv6 Unique local addresses (ULA) and global IPv6 address auto-configuration with SLAAC, must add the parameter `networking.dhcpcd.IPv6rs = true;`.

View file

@ -38,6 +38,8 @@ let pkgs_ = pkgs;
in
let
inherit (lib) optional;
evalModulesMinimal = (import ./default.nix {
inherit lib;
# Implicit use of feature is noted in implementation.
@ -47,15 +49,19 @@ let
pkgsModule = rec {
_file = ./eval-config.nix;
key = _file;
config = {
# Explicit `nixpkgs.system` or `nixpkgs.localSystem` should override
# this. Since the latter defaults to the former, the former should
# default to the argument. That way this new default could propagate all
# they way through, but has the last priority behind everything else.
nixpkgs.system = lib.mkIf (system != null) (lib.mkDefault system);
_module.args.pkgs = lib.mkIf (pkgs_ != null) (lib.mkForce pkgs_);
};
config = lib.mkMerge (
(optional (system != null) {
# Explicit `nixpkgs.system` or `nixpkgs.localSystem` should override
# this. Since the latter defaults to the former, the former should
# default to the argument. That way this new default could propagate all
# they way through, but has the last priority behind everything else.
nixpkgs.system = lib.mkDefault system;
})
++
(optional (pkgs_ != null) {
_module.args.pkgs = lib.mkForce pkgs_;
})
);
};
withWarnings = x:

View file

@ -511,7 +511,7 @@ let format' = format; in let
${if format == "raw" then ''
mv $diskImage $out/${filename}
'' else ''
${pkgs.qemu}/bin/qemu-img convert -f raw -O ${format} ${compress} $diskImage $out/${filename}
${pkgs.qemu-utils}/bin/qemu-img convert -f raw -O ${format} ${compress} $diskImage $out/${filename}
''}
diskImage=$out/${filename}
'';

View file

@ -261,8 +261,8 @@ let
mv $bootDiskImage $out/${bootFilename}
mv $rootDiskImage $out/${rootFilename}
'' else ''
${pkgs.qemu}/bin/qemu-img convert -f raw -O ${formatOpt} ${compress} $bootDiskImage $out/${bootFilename}
${pkgs.qemu}/bin/qemu-img convert -f raw -O ${formatOpt} ${compress} $rootDiskImage $out/${rootFilename}
${pkgs.qemu_kvm}/bin/qemu-img convert -f raw -O ${formatOpt} ${compress} $bootDiskImage $out/${bootFilename}
${pkgs.qemu_kvm}/bin/qemu-img convert -f raw -O ${formatOpt} ${compress} $rootDiskImage $out/${rootFilename}
''}
bootDiskImage=$out/${bootFilename}
rootDiskImage=$out/${rootFilename}

View file

@ -244,7 +244,7 @@ let
${if formatOpt == "raw" then ''
mv $rootDiskImage $out/${rootFilename}
'' else ''
${pkgs.qemu}/bin/qemu-img convert -f raw -O ${formatOpt} ${compress} $rootDiskImage $out/${rootFilename}
${pkgs.qemu_kvm}/bin/qemu-img convert -f raw -O ${formatOpt} ${compress} $rootDiskImage $out/${rootFilename}
''}
rootDiskImage=$out/${rootFilename}
set -x

View file

@ -7,6 +7,7 @@ import io
import os
import queue
import re
import select
import shlex
import shutil
import socket
@ -99,7 +100,7 @@ def _perform_ocr_on_screenshot(
+ "-blur 1x65535"
)
tess_args = f"-c debug_file=/dev/null --psm 11"
tess_args = "-c debug_file=/dev/null --psm 11"
cmd = f"convert {magick_args} '{screenshot_path}' 'tiff:{screenshot_path}.tiff'"
ret = subprocess.run(cmd, shell=True, capture_output=True)
@ -154,6 +155,7 @@ class StartCommand:
# qemu options
qemu_opts = (
" -device virtio-serial"
# Note: virtconsole will map to /dev/hvc0 in Linux guests
" -device virtconsole,chardev=shell"
" -device virtio-rng-pci"
" -serial stdio"
@ -524,8 +526,10 @@ class Machine:
if timeout is not None:
timeout_str = f"timeout {timeout}"
# While sh is bash on NixOS, this is not the case for every distro.
# We explicitely call bash here to allow for the driver to boot other distros as well.
out_command = (
f"{timeout_str} sh -c {shlex.quote(command)} | (base64 --wrap 0; echo)\n"
f"{timeout_str} bash -c {shlex.quote(command)} | (base64 --wrap 0; echo)\n"
)
assert self.shell
@ -719,6 +723,15 @@ class Machine:
self.wait_for_unit(jobname)
def connect(self) -> None:
def shell_ready(timeout_secs: int) -> bool:
"""We sent some data from the backdoor service running on the guest
to indicate that the backdoor shell is ready.
As soon as we read some data from the socket here, we assume that
our root shell is operational.
"""
(ready, _, _) = select.select([self.shell], [], [], timeout_secs)
return bool(ready)
if self.connected:
return
@ -728,8 +741,11 @@ class Machine:
assert self.shell
tic = time.time()
self.shell.recv(1024)
# TODO: Timeout
# TODO: do we want to bail after a set number of attempts?
while not shell_ready(timeout_secs=30):
self.log("Guest root shell did not produce any data yet...")
self.log(self.shell.recv(1024).decode())
toc = time.time()
self.log("connected to guest root shell")
@ -950,7 +966,7 @@ class Machine:
Prepares the machine to be reconnected which is useful if the
machine was started with `allow_reboot = True`
"""
self.send_key(f"ctrl-alt-delete")
self.send_key("ctrl-alt-delete")
self.connected = False
def wait_for_x(self) -> None:

View file

@ -1,13 +1,22 @@
testModuleArgs@{ config, lib, hostPkgs, nodes, ... }:
let
inherit (lib) mkOption mkForce optional types mapAttrs mkDefault mdDoc;
system = hostPkgs.stdenv.hostPlatform.system;
inherit (lib)
literalExpression
literalMD
mapAttrs
mdDoc
mkDefault
mkIf
mkOption mkForce
optional
optionalAttrs
types
;
baseOS =
import ../eval-config.nix {
inherit system;
system = null; # use modularly defined system
inherit (config.node) specialArgs;
modules = [ config.defaults ];
baseModules = (import ../../modules/module-list.nix) ++
@ -17,11 +26,17 @@ let
({ config, ... }:
{
virtualisation.qemu.package = testModuleArgs.config.qemu.package;
})
(optionalAttrs (!config.node.pkgsReadOnly) {
key = "nodes.nix-pkgs";
config = {
# Ensure we do not use aliases. Ideally this is only set
# when the test framework is used by Nixpkgs NixOS tests.
nixpkgs.config.allowAliases = false;
})
# TODO: switch to nixpkgs.hostPlatform and make sure containers-imperative test still evaluates.
nixpkgs.system = hostPkgs.stdenv.hostPlatform.system;
};
})
testModuleArgs.config.extraBaseModules
];
};
@ -68,6 +83,30 @@ in
default = { };
};
node.pkgs = mkOption {
description = mdDoc ''
The Nixpkgs to use for the nodes.
Setting this will make the `nixpkgs.*` options read-only, to avoid mistakenly testing with a Nixpkgs configuration that diverges from regular use.
'';
type = types.nullOr types.pkgs;
default = null;
defaultText = literalMD ''
`null`, so construct `pkgs` according to the `nixpkgs.*` options as usual.
'';
};
node.pkgsReadOnly = mkOption {
description = mdDoc ''
Whether to make the `nixpkgs.*` options read-only. This is only relevant when [`node.pkgs`](#test-opt-node.pkgs) is set.
Set this to `false` when any of the [`nodes`](#test-opt-nodes) needs to configure any of the `nixpkgs.*` options. This will slow down evaluation of your test a bit.
'';
type = types.bool;
default = config.node.pkgs != null;
defaultText = literalExpression ''node.pkgs != null'';
};
node.specialArgs = mkOption {
type = types.lazyAttrsOf types.raw;
default = { };
@ -100,5 +139,11 @@ in
config.nodes;
passthru.nodes = config.nodesCompat;
defaults = mkIf config.node.pkgsReadOnly {
nixpkgs.pkgs = config.node.pkgs;
imports = [ ../../modules/misc/nixpkgs/read-only.nix ];
};
};
}

View file

@ -2,8 +2,6 @@
{ config, lib, pkgs, ... }:
with lib;
{
imports =
[ ../../../modules/virtualisation/cloudstack-config.nix ];

View file

@ -102,8 +102,8 @@ in {
${pkgs.jq}/bin/jq -n \
--arg system_label ${lib.escapeShellArg config.system.nixos.label} \
--arg system ${lib.escapeShellArg pkgs.stdenv.hostPlatform.system} \
--arg root_logical_bytes "$(${pkgs.qemu}/bin/qemu-img info --output json "$rootDisk" | ${pkgs.jq}/bin/jq '."virtual-size"')" \
--arg boot_logical_bytes "$(${pkgs.qemu}/bin/qemu-img info --output json "$bootDisk" | ${pkgs.jq}/bin/jq '."virtual-size"')" \
--arg root_logical_bytes "$(${pkgs.qemu_kvm}/bin/qemu-img info --output json "$rootDisk" | ${pkgs.jq}/bin/jq '."virtual-size"')" \
--arg boot_logical_bytes "$(${pkgs.qemu_kvm}/bin/qemu-img info --output json "$bootDisk" | ${pkgs.jq}/bin/jq '."virtual-size"')" \
--arg boot_mode "${amiBootMode}" \
--arg root "$rootDisk" \
--arg boot "$bootDisk" \
@ -142,7 +142,7 @@ in {
${pkgs.jq}/bin/jq -n \
--arg system_label ${lib.escapeShellArg config.system.nixos.label} \
--arg system ${lib.escapeShellArg pkgs.stdenv.hostPlatform.system} \
--arg logical_bytes "$(${pkgs.qemu}/bin/qemu-img info --output json "$diskImage" | ${pkgs.jq}/bin/jq '."virtual-size"')" \
--arg logical_bytes "$(${pkgs.qemu_kvm}/bin/qemu-img info --output json "$diskImage" | ${pkgs.jq}/bin/jq '."virtual-size"')" \
--arg boot_mode "${amiBootMode}" \
--arg file "$diskImage" \
'{}

View file

@ -4,8 +4,6 @@
{ config, pkgs, lib, ... }:
with lib;
{
imports =
[ # Include the default lxd configuration.

View file

@ -1,7 +1,5 @@
{ lib, config, pkgs, ... }:
with lib;
{
imports = [
../../../modules/virtualisation/lxc-container.nix

View file

@ -1,7 +1,5 @@
{ lib, config, pkgs, ... }:
with lib;
# WARNING: THIS CONFIGURATION IS AUTOGENERATED AND WILL BE OVERWRITTEN AUTOMATICALLY
{

View file

@ -85,7 +85,7 @@ in
${pkgs.jq}/bin/jq -n \
--arg system_label ${lib.escapeShellArg config.system.nixos.label} \
--arg system ${lib.escapeShellArg pkgs.stdenv.hostPlatform.system} \
--arg root_logical_bytes "$(${pkgs.qemu}/bin/qemu-img info --output json "$rootDisk" | ${pkgs.jq}/bin/jq '."virtual-size"')" \
--arg root_logical_bytes "$(${pkgs.qemu_kvm}/bin/qemu-img info --output json "$rootDisk" | ${pkgs.jq}/bin/jq '."virtual-size"')" \
--arg boot_mode "${imageBootMode}" \
--arg root "$rootDisk" \
'{}

View file

@ -29,7 +29,6 @@
# GNU GRUB, where available.
boot.loader.grub.enable = !pkgs.stdenv.isAarch32;
boot.loader.grub.version = 2;
# GNU lsh.
services.openssh.enable = false;

View file

@ -30,7 +30,7 @@ let
systemPlatform = platformMap.${pkgs.stdenv.hostPlatform.system} or (throw "scudo not supported on ${pkgs.stdenv.hostPlatform.system}");
in {
libPath = "${pkgs.llvmPackages_latest.compiler-rt}/lib/linux/libclang_rt.scudo-${systemPlatform}.so";
libPath = "${pkgs.llvmPackages_14.compiler-rt}/lib/linux/libclang_rt.scudo-${systemPlatform}.so";
description = ''
A user-mode allocator based on LLVM Sanitizers CombinedAllocator,
which aims at providing additional mitigations against heap based

View file

@ -47,7 +47,7 @@ with lib;
libva = super.libva-minimal;
limesuite = super.limesuite.override { withGui = false; };
mc = super.mc.override { x11Support = false; };
mpv-unwrapped = super.mpv-unwrapped.override { sdl2Support = false; x11Support = false; };
mpv-unwrapped = super.mpv-unwrapped.override { sdl2Support = false; x11Support = false; waylandSupport = false; };
msmtp = super.msmtp.override { withKeyring = false; };
neofetch = super.neofetch.override { x11Support = false; };
networkmanager-fortisslvpn = super.networkmanager-fortisslvpn.override { withGnome = false; };
@ -59,6 +59,7 @@ with lib;
networkmanager-vpnc = super.networkmanager-vpnc.override { withGnome = false; };
pango = super.pango.override { x11Support = false; };
pinentry = super.pinentry.override { enabledFlavors = [ "curses" "tty" "emacs" ]; withLibsecret = false; };
pipewire = super.pipewire.override { x11Support = false; };
qemu = super.qemu.override { gtkSupport = false; spiceSupport = false; sdlSupport = false; };
qrencode = super.qrencode.overrideAttrs (_: { doCheck = false; });
qt5 = super.qt5.overrideScope (const (super': {

View file

@ -38,6 +38,34 @@ let
'';
};
keySize = mkOption {
default = null;
example = "512";
type = types.nullOr types.int;
description = lib.mdDoc ''
Set the encryption key size for the plain device.
If not specified, the amount of data to read from `source` will be
determined by cryptsetup.
See `cryptsetup-open(8)` for details.
'';
};
sectorSize = mkOption {
default = null;
example = "4096";
type = types.nullOr types.int;
description = lib.mdDoc ''
Set the sector size for the plain encrypted device type.
If not specified, the default sector size is determined from the
underlying block device.
See `cryptsetup-open(8)` for details.
'';
};
source = mkOption {
default = "/dev/urandom";
example = "/dev/random";
@ -157,11 +185,11 @@ let
};
config = rec {
config = {
device = mkIf options.label.isDefined
"/dev/disk/by-label/${config.label}";
deviceName = lib.replaceStrings ["\\"] [""] (escapeSystemdPath config.device);
realDevice = if config.randomEncryption.enable then "/dev/mapper/${deviceName}" else config.device;
realDevice = if config.randomEncryption.enable then "/dev/mapper/${config.deviceName}" else config.device;
};
};
@ -247,7 +275,11 @@ in
''}
${optionalString sw.randomEncryption.enable ''
cryptsetup plainOpen -c ${sw.randomEncryption.cipher} -d ${sw.randomEncryption.source} \
${optionalString sw.randomEncryption.allowDiscards "--allow-discards"} ${sw.device} ${sw.deviceName}
${concatStringsSep " \\\n" (flatten [
(optional (sw.randomEncryption.sectorSize != null) "--sector-size=${toString sw.randomEncryption.sectorSize}")
(optional (sw.randomEncryption.keySize != null) "--key-size=${toString sw.randomEncryption.keySize}")
(optional sw.randomEncryption.allowDiscards "--allow-discards")
])} ${sw.device} ${sw.deviceName}
mkswap ${sw.realDevice}
''}
'';

View file

@ -473,7 +473,7 @@ in
};
isoImage.squashfsCompression = mkOption {
default = with pkgs.stdenv.targetPlatform; "xz -Xdict-size 100% "
default = with pkgs.stdenv.hostPlatform; "xz -Xdict-size 100% "
+ lib.optionalString isx86 "-Xbcj x86"
# Untested but should also reduce size for these platforms
+ lib.optionalString isAarch "-Xbcj arm"
@ -483,6 +483,7 @@ in
Compression settings to use for the squashfs nix store.
'';
example = "zstd -Xcompression-level 6";
type = types.str;
};
isoImage.edition = mkOption {
@ -693,8 +694,6 @@ in
}
];
boot.loader.grub.version = 2;
# Don't build the GRUB menu builder script, since we don't need it
# here and it causes a cyclic dependency.
boot.loader.grub.enable = false;

View file

@ -8,6 +8,20 @@ with lib;
{
options = {
netboot.squashfsCompression = mkOption {
default = with pkgs.stdenv.hostPlatform; "xz -Xdict-size 100% "
+ lib.optionalString isx86 "-Xbcj x86"
# Untested but should also reduce size for these platforms
+ lib.optionalString isAarch "-Xbcj arm"
+ lib.optionalString (isPower && is32bit && isBigEndian) "-Xbcj powerpc"
+ lib.optionalString (isSparc) "-Xbcj sparc";
description = lib.mdDoc ''
Compression settings to use for the squashfs nix store.
'';
example = "zstd -Xcompression-level 6";
type = types.str;
};
netboot.storeContents = mkOption {
example = literalExpression "[ pkgs.stdenv ]";
description = lib.mdDoc ''
@ -77,6 +91,7 @@ with lib;
# Create the squashfs image that contains the Nix store.
system.build.squashfsStore = pkgs.callPackage ../../../lib/make-squashfs.nix {
storeContents = config.netboot.storeContents;
comp = config.netboot.squashfsCompression;
};

View file

@ -668,7 +668,6 @@ EOF
$bootLoaderConfig = <<EOF;
# Use the GRUB 2 boot loader.
boot.loader.grub.enable = true;
boot.loader.grub.version = 2;
# boot.loader.grub.efiSupport = true;
# boot.loader.grub.efiInstallAsRemovable = true;
# boot.loader.efi.efiSysMountPoint = "/boot/efi";

View file

@ -49,10 +49,10 @@ let
merge = lib.mergeOneOption;
};
pkgsType = mkOptionType {
name = "nixpkgs";
pkgsType = types.pkgs // {
# This type is only used by itself, so let's elaborate the description a bit
# for the purpose of documentation.
description = "An evaluation of Nixpkgs; the top level attribute set of packages";
check = builtins.isAttrs;
};
# Whether `pkgs` was constructed by this module - not if nixpkgs.pkgs or

View file

@ -0,0 +1,74 @@
# A replacement for the traditional nixpkgs module, such that none of the modules
# can add their own configuration. This ensures that the Nixpkgs configuration is
# exactly as the user intends.
# This may also be used as a performance optimization when evaluating multiple
# configurations at once, with a shared `pkgs`.
# This is a separate module, because merging this logic into the nixpkgs module
# is too burdensome, considering that it is already burdened with legacy.
# Moving this logic into a module does not lose any composition benefits, because
# its purpose is not something that composes anyway.
{ lib, config, ... }:
let
cfg = config.nixpkgs;
inherit (lib) mkOption types;
in
{
disabledModules = [
../nixpkgs.nix
];
options = {
nixpkgs = {
pkgs = mkOption {
type = lib.types.pkgs;
description = lib.mdDoc ''The pkgs module argument.'';
};
config = mkOption {
internal = true;
type = types.unique { message = "nixpkgs.config is set to read-only"; } types.anything;
description = lib.mdDoc ''
The Nixpkgs `config` that `pkgs` was initialized with.
'';
};
overlays = mkOption {
internal = true;
type = types.unique { message = "nixpkgs.overlays is set to read-only"; } types.anything;
description = lib.mdDoc ''
The Nixpkgs overlays that `pkgs` was initialized with.
'';
};
hostPlatform = mkOption {
internal = true;
readOnly = true;
description = lib.mdDoc ''
The platform of the machine that is running the NixOS configuration.
'';
};
buildPlatform = mkOption {
internal = true;
readOnly = true;
description = lib.mdDoc ''
The platform of the machine that built the NixOS configuration.
'';
};
# NOTE: do not add the legacy options such as localSystem here. Let's keep
# this module simple and let module authors upgrade their code instead.
};
};
config = {
_module.args.pkgs =
# find mistaken definitions
builtins.seq cfg.config
builtins.seq cfg.overlays
builtins.seq cfg.hostPlatform
builtins.seq cfg.buildPlatform
cfg.pkgs;
nixpkgs.config = cfg.pkgs.config;
nixpkgs.overlays = cfg.pkgs.overlays;
nixpkgs.hostPlatform = cfg.pkgs.stdenv.hostPlatform;
nixpkgs.buildPlatform = cfg.pkgs.stdenv.buildPlatform;
};
}

View file

@ -1,3 +1,5 @@
# [nixpkgs]$ nix-build -A nixosTests.nixpkgs --show-trace
{ evalMinimalConfig, pkgs, lib, stdenv }:
let
eval = mod: evalMinimalConfig {
@ -27,6 +29,47 @@ let
let
uncheckedEval = lib.evalModules { modules = [ ../nixpkgs.nix module ]; };
in map (ass: ass.message) (lib.filter (ass: !ass.assertion) uncheckedEval.config.assertions);
readOnlyUndefined = evalMinimalConfig {
imports = [ ./read-only.nix ];
};
readOnlyBad = evalMinimalConfig {
imports = [ ./read-only.nix ];
nixpkgs.pkgs = { };
};
readOnly = evalMinimalConfig {
imports = [ ./read-only.nix ];
nixpkgs.pkgs = pkgs;
};
readOnlyBadConfig = evalMinimalConfig {
imports = [ ./read-only.nix ];
nixpkgs.pkgs = pkgs;
nixpkgs.config.allowUnfree = true; # do in pkgs instead!
};
readOnlyBadOverlays = evalMinimalConfig {
imports = [ ./read-only.nix ];
nixpkgs.pkgs = pkgs;
nixpkgs.overlays = [ (_: _: {}) ]; # do in pkgs instead!
};
readOnlyBadHostPlatform = evalMinimalConfig {
imports = [ ./read-only.nix ];
nixpkgs.pkgs = pkgs;
nixpkgs.hostPlatform = "foo-linux"; # do in pkgs instead!
};
readOnlyBadBuildPlatform = evalMinimalConfig {
imports = [ ./read-only.nix ];
nixpkgs.pkgs = pkgs;
nixpkgs.buildPlatform = "foo-linux"; # do in pkgs instead!
};
throws = x: ! (builtins.tryEval x).success;
in
lib.recurseIntoAttrs {
invokeNixpkgsSimple =
@ -65,5 +108,21 @@ lib.recurseIntoAttrs {
nixpkgs.pkgs = pkgs;
} == [];
# Tests for the read-only.nix module
assert readOnly._module.args.pkgs.stdenv.hostPlatform.system == pkgs.stdenv.hostPlatform.system;
assert throws readOnlyBad._module.args.pkgs.stdenv;
assert throws readOnlyUndefined._module.args.pkgs.stdenv;
assert throws readOnlyBadConfig._module.args.pkgs.stdenv;
assert throws readOnlyBadOverlays._module.args.pkgs.stdenv;
assert throws readOnlyBadHostPlatform._module.args.pkgs.stdenv;
assert throws readOnlyBadBuildPlatform._module.args.pkgs.stdenv;
# read-only.nix does not provide legacy options, for the sake of simplicity
# If you're bothered by this, upgrade your configs to use the new *Platform
# options.
assert !readOnly.options.nixpkgs?system;
assert !readOnly.options.nixpkgs?localSystem;
assert !readOnly.options.nixpkgs?crossSystem;
pkgs.emptyFile;
}

View file

@ -153,6 +153,7 @@
./programs/cnping.nix
./programs/command-not-found/command-not-found.nix
./programs/criu.nix
./programs/darling.nix
./programs/dconf.nix
./programs/digitalbitbox/default.nix
./programs/dmrconfig.nix
@ -234,6 +235,7 @@
./programs/singularity.nix
./programs/skim.nix
./programs/slock.nix
./programs/sniffnet.nix
./programs/spacefm.nix
./programs/ssh.nix
./programs/starship.nix
@ -247,6 +249,7 @@
./programs/thunar.nix
./programs/tmux.nix
./programs/traceroute.nix
./programs/trippy.nix
./programs/tsm-client.nix
./programs/turbovnc.nix
./programs/udevil.nix
@ -306,6 +309,7 @@
./services/audio/alsa.nix
./services/audio/botamusique.nix
./services/audio/gmediarender.nix
./services/audio/gonic.nix
./services/audio/hqplayerd.nix
./services/audio/icecast.nix
./services/audio/jack.nix
@ -371,6 +375,7 @@
./services/continuous-integration/buildbot/master.nix
./services/continuous-integration/buildbot/worker.nix
./services/continuous-integration/buildkite-agents.nix
./services/continuous-integration/gitea-actions-runner.nix
./services/continuous-integration/github-runner.nix
./services/continuous-integration/github-runners.nix
./services/continuous-integration/gitlab-runner.nix
@ -684,6 +689,7 @@
./services/misc/ripple-data-api.nix
./services/misc/rippled.nix
./services/misc/rmfakecloud.nix
./services/misc/rshim.nix
./services/misc/safeeyes.nix
./services/misc/sdrplay.nix
./services/misc/serviio.nix
@ -801,6 +807,7 @@
./services/network-filesystems/yandex-disk.nix
./services/networking/3proxy.nix
./services/networking/adguardhome.nix
./services/networking/alice-lg.nix
./services/networking/amuled.nix
./services/networking/antennas.nix
./services/networking/aria2.nix
@ -815,6 +822,7 @@
./services/networking/bind.nix
./services/networking/bird-lg.nix
./services/networking/bird.nix
./services/networking/birdwatcher.nix
./services/networking/bitcoind.nix
./services/networking/bitlbee.nix
./services/networking/blockbook-frontend.nix
@ -873,6 +881,7 @@
./services/networking/gobgpd.nix
./services/networking/gvpe.nix
./services/networking/hans.nix
./services/networking/harmonia.nix
./services/networking/haproxy.nix
./services/networking/headscale.nix
./services/networking/hostapd.nix
@ -1173,6 +1182,7 @@
./services/web-apps/gerrit.nix
./services/web-apps/gotify-server.nix
./services/web-apps/grocy.nix
./services/web-apps/pixelfed.nix
./services/web-apps/healthchecks.nix
./services/web-apps/hedgedoc.nix
./services/web-apps/hledger-web.nix
@ -1189,6 +1199,7 @@
./services/web-apps/komga.nix
./services/web-apps/lemmy.nix
./services/web-apps/limesurvey.nix
./services/web-apps/mainsail.nix
./services/web-apps/mastodon.nix
./services/web-apps/matomo.nix
./services/web-apps/mattermost.nix
@ -1203,6 +1214,7 @@
./services/web-apps/nifi.nix
./services/web-apps/node-red.nix
./services/web-apps/onlyoffice.nix
./services/web-apps/openvscode-server.nix
./services/web-apps/openwebrx.nix
./services/web-apps/outline.nix
./services/web-apps/peering-manager.nix
@ -1368,6 +1380,7 @@
./tasks/filesystems/cifs.nix
./tasks/filesystems/ecryptfs.nix
./tasks/filesystems/envfs.nix
./tasks/filesystems/erofs.nix
./tasks/filesystems/exfat.nix
./tasks/filesystems/ext.nix
./tasks/filesystems/f2fs.nix

View file

@ -0,0 +1,21 @@
{ config, lib, pkgs, ... }:
let
cfg = config.programs.darling;
in {
options = {
programs.darling = {
enable = lib.mkEnableOption (lib.mdDoc "Darling, a Darwin/macOS compatibility layer for Linux");
package = lib.mkPackageOptionMD pkgs "darling" {};
};
};
config = lib.mkIf cfg.enable {
security.wrappers.darling = {
source = lib.getExe cfg.package;
owner = "root";
group = "root";
setuid = true;
};
};
}

View file

@ -26,7 +26,7 @@ in
source ${pkgs.fzf}/share/fzf/key-bindings.zsh
'');
programs.zsh.ohMyZsh.plugins = optional (cfg.keybindings || cfg.fuzzyCompletion) [ "fzf" ];
programs.zsh.ohMyZsh.plugins = lib.mkIf (cfg.keybindings || cfg.fuzzyCompletion) [ "fzf" ];
};
meta.maintainers = with maintainers; [ laalsaas ];
}

View file

@ -8,7 +8,7 @@ in {
Miriway, a Mir based Wayland compositor. You can manually launch Miriway by
executing "exec miriway" on a TTY, or launch it from a display manager. Copy
/etc/xdg/xdg-miriway/miriway-shell.config to ~/.config/miriway-shell.config
to modify the default configuration. See <https://github.com/Miriway/Miriway>,
to modify the system-wide configuration on a per-user basis. See <https://github.com/Miriway/Miriway>,
and "miriway --help" for more information'');
config = lib.mkOption {
@ -19,6 +19,15 @@ in {
ctrl-alt=t:miriway-terminal # Default "terminal emulator finder"
shell-component=dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY
meta=Left:@dock-left
meta=Right:@dock-right
meta=Space:@toggle-maximized
meta=Home:@workspace-begin
meta=End:@workspace-end
meta=Page_Up:@workspace-up
meta=Page_Down:@workspace-down
ctrl-alt=BackSpace:@exit
'';
example = ''
idle-timeout=300
@ -31,6 +40,15 @@ in {
shell-component=wbg Pictures/wallpaper
shell-meta=a:synapse
meta=Left:@dock-left
meta=Right:@dock-right
meta=Space:@toggle-maximized
meta=Home:@workspace-begin
meta=End:@workspace-end
meta=Page_Up:@workspace-up
meta=Page_Down:@workspace-down
ctrl-alt=BackSpace:@exit
'';
description = lib.mdDoc ''
Miriway's config. This will be installed system-wide.

View file

@ -138,7 +138,8 @@ in
};
source = mkOption {
type = types.path;
default = null;
type = types.nullOr types.path;
description = lib.mdDoc "Path of the source file.";
};
@ -160,9 +161,11 @@ in
environment.etc = listToAttrs (attrValues (mapAttrs
(name: value: {
name = "xdg/nvim/${name}";
value = value // {
target = "xdg/nvim/${value.target}";
};
value = removeAttrs
(value // {
target = "xdg/nvim/${value.target}";
})
(optionals (isNull value.source) [ "source" ]);
})
cfg.runtime));

View file

@ -41,6 +41,8 @@ let
# This should be made configurable.
#CHFN_RESTRICT frwh
# The default crypt() method, keep in sync with the PAM default
ENCRYPT_METHOD YESCRYPT
'';
mkSetuidRoot = source:

View file

@ -0,0 +1,24 @@
{ config, lib, pkgs, ... }:
let
cfg = config.programs.sniffnet;
in
{
options = {
programs.sniffnet = {
enable = lib.mkEnableOption (lib.mdDoc "sniffnet");
};
};
config = lib.mkIf cfg.enable {
security.wrappers.sniffnet = {
owner = "root";
group = "root";
capabilities = "cap_net_raw,cap_net_admin=eip";
source = "${pkgs.sniffnet}/bin/sniffnet";
};
};
meta.maintainers = with lib.maintainers; [ figsoda ];
}

View file

@ -0,0 +1,24 @@
{ lib, config, pkgs, ... }:
let
cfg = config.programs.trippy;
in
{
options = {
programs.trippy = {
enable = lib.mkEnableOption (lib.mdDoc "trippy");
};
};
config = lib.mkIf cfg.enable {
security.wrappers.trip = {
owner = "root";
group = "root";
capabilities = "cap_net_raw+p";
source = lib.getExe pkgs.trippy;
};
};
meta.maintainers = with lib.maintainers; [ figsoda ];
}

View file

@ -1,7 +1,10 @@
{ lib, pkgs, ... }:
with lib;
let
inherit (lib)
mkAliasOptionModuleMD
mkRemovedOptionModule;
in
{
imports = [
/*

View file

@ -323,7 +323,7 @@ let
}
fi
'');
} // optionalAttrs (data.listenHTTP != null && toInt (elemAt (splitString ":" data.listenHTTP) 1) < 1024) {
} // optionalAttrs (data.listenHTTP != null && toInt (last (splitString ":" data.listenHTTP)) < 1024) {
CapabilityBoundingSet = [ "CAP_NET_BIND_SERVICE" ];
AmbientCapabilities = [ "CAP_NET_BIND_SERVICE" ];
};

View file

@ -22,7 +22,7 @@ in
# some may even be completely useless.
config.security.apparmor.includes = {
# This one is included by <tunables/global>
# which is usualy included before any profile.
# which is usually included before any profile.
"abstractions/tunables/alias" = ''
alias /bin -> /run/current-system/sw/bin,
alias /lib/modules -> /run/current-system/kernel/lib/modules,

View file

@ -446,6 +446,15 @@ let
};
};
zfs = mkOption {
default = config.security.pam.zfs.enable;
defaultText = literalExpression "config.security.pam.zfs.enable";
type = types.bool;
description = lib.mdDoc ''
Enable unlocking and mounting of encrypted ZFS home dataset at login.
'';
};
text = mkOption {
type = types.nullOr types.lines;
description = lib.mdDoc "Contents of the PAM service file.";
@ -556,7 +565,8 @@ let
|| cfg.googleAuthenticator.enable
|| cfg.gnupg.enable
|| cfg.failDelay.enable
|| cfg.duoSecurity.enable))
|| cfg.duoSecurity.enable
|| cfg.zfs))
(
optionalString config.services.homed.enable ''
auth optional ${config.systemd.package}/lib/security/pam_systemd_home.so
@ -570,6 +580,9 @@ let
optionalString config.security.pam.enableFscrypt ''
auth optional ${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so
'' +
optionalString cfg.zfs ''
auth optional ${config.boot.zfs.package}/lib/security/pam_zfs_key.so homes=${config.security.pam.zfs.homes}
'' +
optionalString cfg.pamMount ''
auth optional ${pkgs.pam_mount}/lib/security/pam_mount.so disable_interactive
'' +
@ -628,6 +641,9 @@ let
optionalString config.security.pam.enableFscrypt ''
password optional ${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so
'' +
optionalString cfg.zfs ''
password optional ${config.boot.zfs.package}/lib/security/pam_zfs_key.so homes=${config.security.pam.zfs.homes}
'' +
optionalString cfg.pamMount ''
password optional ${pkgs.pam_mount}/lib/security/pam_mount.so
'' +
@ -638,7 +654,7 @@ let
password sufficient ${pkgs.pam_mysql}/lib/security/pam_mysql.so config_file=/etc/security/pam_mysql.conf
'' +
optionalString config.services.sssd.enable ''
password sufficient ${pkgs.sssd}/lib/security/pam_sss.so use_authtok
password sufficient ${pkgs.sssd}/lib/security/pam_sss.so
'' +
optionalString config.security.pam.krb5.enable ''
password sufficient ${pam_krb5}/lib/security/pam_krb5.so use_first_pass
@ -685,6 +701,10 @@ let
session [success=1 default=ignore] pam_succeed_if.so service = systemd-user
session optional ${pkgs.fscrypt-experimental}/lib/security/pam_fscrypt.so
'' +
optionalString cfg.zfs ''
session [success=1 default=ignore] pam_succeed_if.so service = systemd-user
session optional ${config.boot.zfs.package}/lib/security/pam_zfs_key.so homes=${config.security.pam.zfs.homes} ${optionalString config.security.pam.zfs.noUnmount "nounmount"}
'' +
optionalString cfg.pamMount ''
session optional ${pkgs.pam_mount}/lib/security/pam_mount.so disable_interactive
'' +
@ -1202,6 +1222,34 @@ in
};
};
security.pam.zfs = {
enable = mkOption {
default = false;
type = types.bool;
description = lib.mdDoc ''
Enable unlocking and mounting of encrypted ZFS home dataset at login.
'';
};
homes = mkOption {
example = "rpool/home";
default = "rpool/home";
type = types.str;
description = lib.mdDoc ''
Prefix of home datasets. This value will be concatenated with
`"/" + <username>` in order to determine the home dataset to unlock.
'';
};
noUnmount = mkOption {
default = false;
type = types.bool;
description = lib.mdDoc ''
Do not unmount home dataset on logout.
'';
};
};
security.pam.enableEcryptfs = mkEnableOption (lib.mdDoc "eCryptfs PAM module (mounting ecryptfs home directory on login)");
security.pam.enableFscrypt = mkEnableOption (lib.mdDoc ''
Enables fscrypt to automatically unlock directories with the user's login password.
@ -1238,6 +1286,12 @@ in
Only one of users.motd and users.motdFile can be set.
'';
}
{
assertion = config.security.pam.zfs.enable -> (config.boot.zfs.enabled || config.boot.zfs.enableUnstable);
message = ''
`security.pam.zfs.enable` requires enabling ZFS (`boot.zfs.enabled` or `boot.zfs.enableUnstable`).
'';
}
];
environment.systemPackages =
@ -1378,7 +1432,10 @@ in
mr ${pkgs.plasma5Packages.kwallet-pam}/lib/security/pam_kwallet5.so,
'' +
optionalString config.virtualisation.lxc.lxcfs.enable ''
mr ${pkgs.lxc}/lib/security/pam_cgfs.so
mr ${pkgs.lxc}/lib/security/pam_cgfs.so,
'' +
optionalString (isEnabled (cfg: cfg.zfs)) ''
mr ${config.boot.zfs.package}/lib/security/pam_zfs_key.so,
'' +
optionalString config.services.homed.enable ''
mr ${config.systemd.package}/lib/security/pam_systemd_home.so

View file

@ -3,7 +3,7 @@ let
cfg = config.security.tpm2;
# This snippet is taken from tpm2-tss/dist/tpm-udev.rules, but modified to allow custom user/groups
# The idea is that the tssUser is allowed to acess the TPM and kernel TPM resource manager, while
# The idea is that the tssUser is allowed to access the TPM and kernel TPM resource manager, while
# the tssGroup is only allowed to access the kernel resource manager
# Therefore, if either of the two are null, the respective part isn't generated
udevRules = tssUser: tssGroup: ''

View file

@ -283,7 +283,7 @@ in
'';
###### wrappers consistency checks
system.extraDependencies = lib.singleton (pkgs.runCommandLocal
system.checks = lib.singleton (pkgs.runCommandLocal
"ensure-all-wrappers-paths-exist" { }
''
# make sure we produce output

View file

@ -0,0 +1,89 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.gonic;
settingsFormat = pkgs.formats.keyValue {
mkKeyValue = lib.generators.mkKeyValueDefault { } " ";
listsAsDuplicateKeys = true;
};
in
{
options = {
services.gonic = {
enable = mkEnableOption (lib.mdDoc "Gonic music server");
settings = mkOption rec {
type = settingsFormat.type;
apply = recursiveUpdate default;
default = {
listen-addr = "127.0.0.1:4747";
cache-path = "/var/cache/gonic";
tls-cert = null;
tls-key = null;
};
example = {
music-path = [ "/mnt/music" ];
podcast-path = "/mnt/podcasts";
};
description = lib.mdDoc ''
Configuration for Gonic, see <https://github.com/sentriz/gonic#configuration-options> for supported values.
'';
};
};
};
config = mkIf cfg.enable {
systemd.services.gonic = {
description = "Gonic Media Server";
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart =
let
# these values are null by default but should not appear in the final config
filteredSettings = filterAttrs (n: v: !((n == "tls-cert" || n == "tls-key") && v == null)) cfg.settings;
in
"${pkgs.gonic}/bin/gonic -config-path ${settingsFormat.generate "gonic" filteredSettings}";
DynamicUser = true;
StateDirectory = "gonic";
CacheDirectory = "gonic";
WorkingDirectory = "/var/lib/gonic";
RuntimeDirectory = "gonic";
RootDirectory = "/run/gonic";
ReadWritePaths = "";
BindReadOnlyPaths = [
# gonic can access scrobbling services
"-/etc/ssl/certs/ca-certificates.crt"
builtins.storeDir
cfg.settings.podcast-path
] ++ cfg.settings.music-path
++ lib.optional (cfg.settings.tls-cert != null) cfg.settings.tls-cert
++ lib.optional (cfg.settings.tls-key != null) cfg.settings.tls-key;
CapabilityBoundingSet = "";
RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
RestrictNamespaces = true;
PrivateDevices = true;
PrivateUsers = true;
ProtectClock = true;
ProtectControlGroups = true;
ProtectHome = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
ProtectKernelTunables = true;
SystemCallArchitectures = "native";
SystemCallFilter = [ "@system-service" "~@privileged" ];
RestrictRealtime = true;
LockPersonality = true;
MemoryDenyWriteExecute = true;
UMask = "0066";
ProtectHostname = true;
};
};
};
meta.maintainers = [ maintainers.autrimpo ];
}

View file

@ -3,7 +3,7 @@
let
inherit (lib) concatMapStringsSep concatStringsSep isInt isList literalExpression;
inherit (lib) mapAttrs mapAttrsToList mkDefault mkEnableOption mkIf mkOption optional types;
inherit (lib) mapAttrs mapAttrsToList mkDefault mkEnableOption mkIf mkOption mkRenamedOptionModule optional types;
cfg = config.services.automysqlbackup;
pkg = pkgs.automysqlbackup;
@ -26,6 +26,10 @@ let
in
{
imports = [
(mkRenamedOptionModule [ "services" "automysqlbackup" "config" ] [ "services" "automysqlbackup" "settings" ])
];
# interface
options = {
services.automysqlbackup = {
@ -40,7 +44,7 @@ in
'';
};
config = mkOption {
settings = mkOption {
type = with types; attrsOf (oneOf [ str int bool (listOf str) ]);
default = {};
description = lib.mdDoc ''
@ -112,7 +116,18 @@ in
services.mysql.ensureUsers = optional (config.services.mysql.enable && cfg.config.mysql_dump_host == "localhost") {
name = user;
ensurePermissions = { "*.*" = "SELECT, SHOW VIEW, TRIGGER, LOCK TABLES, EVENT"; };
ensurePermissions = {
"*.*" = "SELECT, SHOW VIEW, TRIGGER, LOCK TABLES, EVENT";
# https://forums.mysql.com/read.php?10,668311,668315#msg-668315
"function sys.extract_table_from_file_name" = "execute";
"function sys.format_path" = "execute";
"function sys.format_statement" = "execute";
"function sys.extract_schema_from_file_name" = "execute";
"function sys.ps_thread_account" = "execute";
"function sys.format_time" = "execute";
"function sys.format_bytes" = "execute";
};
};
};

View file

@ -109,7 +109,7 @@ let
};
environment = {
BORG_REPO = cfg.repo;
inherit (cfg) extraArgs extraInitArgs extraCreateArgs extraPruneArgs;
inherit (cfg) extraArgs extraInitArgs extraCreateArgs extraPruneArgs extraCompactArgs;
} // (mkPassEnv cfg) // cfg.environment;
};

View file

@ -145,6 +145,7 @@ in
type = types.attrsOf unitOption;
default = {
OnCalendar = "daily";
Persistent = true;
};
description = lib.mdDoc ''
When to run the backup. See {manpage}`systemd.timer(5)` for details.
@ -152,6 +153,7 @@ in
example = {
OnCalendar = "00:05";
RandomizedDelaySec = "5h";
Persistent = true;
};
};

View file

@ -0,0 +1,237 @@
{ config
, lib
, pkgs
, utils
, ...
}:
let
inherit (lib)
any
attrValues
concatStringsSep
escapeShellArg
hasInfix
hasSuffix
optionalAttrs
optionals
literalExpression
mapAttrs'
mkEnableOption
mkOption
mkPackageOptionMD
mkIf
nameValuePair
types
;
inherit (utils)
escapeSystemdPath
;
cfg = config.services.gitea-actions-runner;
# Check whether any runner instance label requires a container runtime
# Empty label strings result in the upstream defined defaultLabels, which require docker
# https://gitea.com/gitea/act_runner/src/tag/v0.1.5/internal/app/cmd/register.go#L93-L98
hasDockerScheme = instance:
instance.labels == [] || any (label: hasInfix ":docker:" label) instance.labels;
wantsContainerRuntime = any hasDockerScheme (attrValues cfg.instances);
hasHostScheme = instance: any (label: hasSuffix ":host" label) instance.labels;
# provide shorthands for whether container runtimes are enabled
hasDocker = config.virtualisation.docker.enable;
hasPodman = config.virtualisation.podman.enable;
tokenXorTokenFile = instance:
(instance.token == null && instance.tokenFile != null) ||
(instance.token != null && instance.tokenFile == null);
in
{
meta.maintainers = with lib.maintainers; [
hexa
];
options.services.gitea-actions-runner = with types; {
package = mkPackageOptionMD pkgs "gitea-actions-runner" { };
instances = mkOption {
default = {};
description = lib.mdDoc ''
Gitea Actions Runner instances.
'';
type = attrsOf (submodule {
options = {
enable = mkEnableOption (lib.mdDoc "Gitea Actions Runner instance");
name = mkOption {
type = str;
example = literalExpression "config.networking.hostName";
description = lib.mdDoc ''
The name identifying the runner instance towards the Gitea/Forgejo instance.
'';
};
url = mkOption {
type = str;
example = "https://forge.example.com";
description = lib.mdDoc ''
Base URL of your Gitea/Forgejo instance.
'';
};
token = mkOption {
type = nullOr str;
default = null;
description = lib.mdDoc ''
Plain token to register at the configured Gitea/Forgejo instance.
'';
};
tokenFile = mkOption {
type = nullOr (either str path);
default = null;
description = lib.mdDoc ''
Path to an environment file, containing the `TOKEN` environment
variable, that holds a token to register at the configured
Gitea/Forgejo instance.
'';
};
labels = mkOption {
type = listOf str;
example = literalExpression ''
[
# provide a debian base with nodejs for actions
"debian-latest:docker://node:18-bullseye"
# fake the ubuntu name, because node provides no ubuntu builds
"ubuntu-latest:docker://node:18-bullseye"
# provide native execution on the host
#"native:host"
]
'';
description = lib.mdDoc ''
Labels used to map jobs to their runtime environment. Changing these
labels currently requires a new registration token.
Many common actions require bash, git and nodejs, as well as a filesystem
that follows the filesystem hierarchy standard.
'';
};
hostPackages = mkOption {
type = listOf package;
default = with pkgs; [
bash
coreutils
curl
gawk
gitMinimal
gnused
nodejs
wget
];
defaultText = literalExpression ''
with pkgs; [
bash
coreutils
curl
gawk
gitMinimal
gnused
nodejs
wget
]
'';
description = lib.mdDoc ''
List of packages, that are available to actions, when the runner is configured
with a host execution label.
'';
};
};
});
};
};
config = mkIf (cfg.instances != {}) {
assertions = [ {
assertion = any tokenXorTokenFile (attrValues cfg.instances);
message = "Instances of gitea-actions-runner can have `token` or `tokenFile`, not both.";
} {
assertion = wantsContainerRuntime -> hasDocker || hasPodman;
message = "Label configuration on gitea-actions-runner instance requires either docker or podman.";
} ];
systemd.services = let
mkRunnerService = name: instance: let
wantsContainerRuntime = hasDockerScheme instance;
wantsHost = hasHostScheme instance;
wantsDocker = wantsContainerRuntime && config.virtualisation.docker.enable;
wantsPodman = wantsContainerRuntime && config.virtualisation.podman.enable;
in
nameValuePair "gitea-runner-${escapeSystemdPath name}" {
inherit (instance) enable;
description = "Gitea Actions Runner";
after = [
"network-online.target"
] ++ optionals (wantsDocker) [
"docker.service"
] ++ optionals (wantsPodman) [
"podman.service"
];
wantedBy = [
"multi-user.target"
];
environment = optionalAttrs (instance.token != null) {
TOKEN = "${instance.token}";
} // optionalAttrs (wantsPodman) {
DOCKER_HOST = "unix:///run/podman/podman.sock";
};
path = with pkgs; [
coreutils
] ++ lib.optionals wantsHost instance.hostPackages;
serviceConfig = {
DynamicUser = true;
User = "gitea-runner";
StateDirectory = "gitea-runner";
WorkingDirectory = "-/var/lib/gitea-runner/${name}";
ExecStartPre = pkgs.writeShellScript "gitea-register-runner-${name}" ''
export INSTANCE_DIR="$STATE_DIRECTORY/${name}"
mkdir -vp "$INSTANCE_DIR"
cd "$INSTANCE_DIR"
# force reregistration on changed labels
export LABELS_FILE="$INSTANCE_DIR/.labels"
export LABELS_WANTED="$(echo ${escapeShellArg (concatStringsSep "\n" instance.labels)} | sort)"
export LABELS_CURRENT="$(cat $LABELS_FILE 2>/dev/null || echo 0)"
if [ ! -e "$INSTANCE_DIR/.runner" ] || [ "$LABELS_WANTED" != "$LABELS_CURRENT" ]; then
# remove existing registration file, so that changing the labels forces a re-registation
rm -v "$INSTANCE_DIR/.runner" || true
# perform the registration
${cfg.package}/bin/act_runner register --no-interactive \
--instance ${escapeShellArg instance.url} \
--token "$TOKEN" \
--name ${escapeShellArg instance.name} \
--labels ${escapeShellArg (concatStringsSep "," instance.labels)}
# and write back the configured labels
echo "$LABELS_WANTED" > "$LABELS_FILE"
fi
'';
ExecStart = "${cfg.package}/bin/act_runner daemon";
SupplementaryGroups = optionals (wantsDocker) [
"docker"
] ++ optionals (wantsPodman) [
"podman"
];
} // optionalAttrs (instance.tokenFile != null) {
EnvironmentFile = instance.tokenFile;
};
};
in mapAttrs' mkRunnerService cfg.instances;
};
}

View file

@ -489,7 +489,7 @@ in
"/share/postgresql"
];
system.extraDependencies = lib.optional (cfg.checkConfig && pkgs.stdenv.hostPlatform == pkgs.stdenv.buildPlatform) configFileCheck;
system.checks = lib.optional (cfg.checkConfig && pkgs.stdenv.hostPlatform == pkgs.stdenv.buildPlatform) configFileCheck;
systemd.services.postgresql =
{ description = "PostgreSQL Server";

View file

@ -254,7 +254,7 @@ in
preStart = ''
# Blindly copy the whole project here.
chmod -R +w .
rm -rf ./public/assets/*
rm -rf ./public/assets/
rm -rf ./tmp/*
rm -rf ./log/*
cp -r --no-preserve=owner ${cfg.package}/* .

View file

@ -245,7 +245,7 @@ in
rm -f www
${optionalString cfg.web-ui.enable ''
ln -s ${cfg.web-ui.package}/lib/dist www
ln -s ${cfg.web-ui.package}/ www
''}
'';
};

View file

@ -76,7 +76,9 @@ in
ExecStart = "${pkgs.keyd}/bin/keyd";
Restart = "always";
DynamicUser = true;
# TODO investigate why it doesn't work propeprly with DynamicUser
# See issue: https://github.com/NixOS/nixpkgs/issues/226346
# DynamicUser = true;
SupplementaryGroups = [
config.users.groups.input.name
config.users.groups.uinput.name
@ -96,6 +98,7 @@ in
ProtectHostname = true;
PrivateUsers = true;
PrivateMounts = true;
PrivateTmp = true;
RestrictNamespaces = true;
ProtectKernelLogs = true;
ProtectKernelModules = true;
@ -104,7 +107,18 @@ in
MemoryDenyWriteExecute = true;
RestrictRealtime = true;
LockPersonality = true;
ProtectProc = "noaccess";
ProtectProc = "invisible";
SystemCallFilter = [
"@system-service"
"~@privileged"
"~@resources"
];
RestrictAddressFamilies = [ "AF_UNIX" ];
RestrictSUIDSGID = true;
IPAddressDeny = [ "any" ];
NoNewPrivileges = true;
ProtectSystem = "strict";
ProcSubset = "pid";
UMask = "0077";
};
};

View file

@ -37,8 +37,8 @@ in
package = mkOption {
type = types.package;
default = pkgs.graylog;
defaultText = literalExpression "pkgs.graylog";
default = if versionOlder config.system.stateVersion "23.05" then pkgs.graylog-3_3 else pkgs.graylog-5_0;
defaultText = literalExpression (if versionOlder config.system.stateVersion "23.05" then "pkgs.graylog-3_3" else "pkgs.graylog-5_0");
description = lib.mdDoc "Graylog package to use.";
};

View file

@ -8,6 +8,8 @@ in
options.services.vector = {
enable = mkEnableOption (lib.mdDoc "Vector");
package = mkPackageOptionMD pkgs "vector" { };
journaldAccess = mkOption {
type = types.bool;
default = false;
@ -47,7 +49,7 @@ in
'';
in
{
ExecStart = "${pkgs.vector}/bin/vector --config ${validateConfig conf}";
ExecStart = "${getExe cfg.package} --config ${validateConfig conf}";
DynamicUser = true;
Restart = "no";
StateDirectory = "vector";

View file

@ -206,7 +206,7 @@ in {
Server configuration, see
[https://maddy.email](https://maddy.email) for
more information. The default configuration of this module will setup
minimal maddy instance for mail transfer without TLS encryption.
minimal Maddy instance for mail transfer without TLS encryption.
::: {.note}
This should not be used in a production environment.
@ -216,13 +216,24 @@ in {
tls = {
loader = mkOption {
type = with types; nullOr (enum [ "file" "off" ]);
type = with types; nullOr (enum [ "off" "file" "acme" ]);
default = "off";
description = lib.mdDoc ''
TLS certificates are obtained by modules called "certificate
loaders". Currently only the file loader is supported which reads
certificates from files specifying the options `keyPaths` and
`certPaths`.
loaders".
The `file` loader module reads certificates from files specified by
the `certificates` option.
Alternatively the `acme` module can be used to automatically obtain
certificates using the ACME protocol.
Module configuration is done via the `tls.extraConfig` option.
Secrets such as API keys or passwords should not be supplied in
plaintext. Instead the `secrets` option can be used to read secrets
at runtime as environment variables. Secrets can be referenced with
`{env:VAR}`.
'';
};
@ -261,11 +272,13 @@ in {
extraConfig = mkOption {
type = with types; nullOr lines;
description = lib.mdDoc ''
Arguments for the specific certificate loader. Note that Maddy uses
secure defaults for the TLS configuration so there is no need to
change anything in most cases.
See [upstream manual](https://maddy.email/reference/tls/) for
available options.
Arguments for the specified certificate loader.
In case the `tls` loader is set, the defaults are considered secure
and there is no need to change anything in most cases.
For available options see [upstream manual](https://maddy.email/reference/tls/).
For ACME configuration, see [following page](https://maddy.email/reference/tls-acme).
'';
default = "";
};
@ -321,20 +334,41 @@ in {
});
};
secrets = lib.mkOption {
type = lib.types.path;
description = lib.mdDoc ''
A file containing the various secrets. Should be in the format
expected by systemd's `EnvironmentFile` directory. Secrets can be
referenced in the format `{env:VAR}`.
'';
};
};
};
config = mkIf cfg.enable {
assertions = [{
assertion = cfg.tls.loader == "file" -> cfg.tls.certificates != [];
message = ''
If maddy is configured to use TLS, tls.certificates with attribute sets
of certPath and keyPath must be provided.
Read more about obtaining TLS certificates here:
https://maddy.email/tutorials/setting-up/#tls-certificates
'';
}];
assertions = [
{
assertion = cfg.tls.loader == "file" -> cfg.tls.certificates != [];
message = ''
If Maddy is configured to use TLS, tls.certificates with attribute sets
of certPath and keyPath must be provided.
Read more about obtaining TLS certificates here:
https://maddy.email/tutorials/setting-up/#tls-certificates
'';
}
{
assertion = cfg.tls.loader == "acme" -> cfg.tls.extraConfig != "";
message = ''
If Maddy is configured to obtain TLS certificates using the ACME
loader, extra configuration options must be supplied via
tls.extraConfig option.
See upstream documentation for more details:
https://maddy.email/reference/tls-acme
'';
}
];
systemd = {
@ -345,6 +379,7 @@ in {
User = cfg.user;
Group = cfg.group;
StateDirectory = [ "maddy" ];
EnvironmentFile = lib.mkIf (cfg.secrets != null) "${cfg.secrets}";
};
restartTriggers = [ config.environment.etc."maddy/maddy.conf".source ];
wantedBy = [ "multi-user.target" ];
@ -391,6 +426,12 @@ in {
) cfg.tls.certificates)} ${optionalString (cfg.tls.extraConfig != "") ''
{ ${cfg.tls.extraConfig} }
''}
'' else if (cfg.tls.loader == "acme") then ''
tls {
loader acme {
${cfg.tls.extraConfig}
}
}
'' else if (cfg.tls.loader == "off") then ''
tls off
'' else ""}

View file

@ -30,7 +30,7 @@ let
# these config files will be merged one after the other to build the final config
configFiles = [
"${pkgs.mjolnir}/share/mjolnir/config/default.yaml"
"${pkgs.mjolnir}/libexec/mjolnir/deps/mjolnir/config/default.yaml"
moduleConfigFile
];
@ -200,7 +200,7 @@ in
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = ''${pkgs.mjolnir}/bin/mjolnir'';
ExecStart = ''${pkgs.mjolnir}/bin/mjolnir --mjolnir-config ./config/default.yaml'';
ExecStartPre = [ generateConfig ];
WorkingDirectory = cfg.dataPath;
StateDirectory = "mjolnir";

View file

@ -167,10 +167,11 @@ in {
ETCD_LISTEN_CLIENT_URLS = concatStringsSep "," cfg.listenClientUrls;
ETCD_LISTEN_PEER_URLS = concatStringsSep "," cfg.listenPeerUrls;
ETCD_INITIAL_ADVERTISE_PEER_URLS = concatStringsSep "," cfg.initialAdvertisePeerUrls;
ETCD_PEER_CLIENT_CERT_AUTH = toString cfg.peerClientCertAuth;
ETCD_PEER_TRUSTED_CA_FILE = cfg.peerTrustedCaFile;
ETCD_PEER_CERT_FILE = cfg.peerCertFile;
ETCD_PEER_KEY_FILE = cfg.peerKeyFile;
ETCD_CLIENT_CERT_AUTH = toString cfg.peerClientCertAuth;
ETCD_CLIENT_CERT_AUTH = toString cfg.clientCertAuth;
ETCD_TRUSTED_CA_FILE = cfg.trustedCaFile;
ETCD_CERT_FILE = cfg.certFile;
ETCD_KEY_FILE = cfg.keyFile;

View file

@ -23,6 +23,16 @@ in
description = lib.mdDoc "The Klipper package.";
};
logFile = mkOption {
type = types.nullOr types.path;
default = null;
example = "/var/lib/klipper/klipper.log";
description = lib.mdDoc ''
Path of the file Klipper should log to.
If `null`, it logs to stdout, which is not recommended by upstream.
'';
};
inputTTY = mkOption {
type = types.path;
default = "/run/klipper/tty";
@ -151,7 +161,9 @@ in
systemd.services.klipper =
let
klippyArgs = "--input-tty=${cfg.inputTTY}"
+ optionalString (cfg.apiSocket != null) " --api-server=${cfg.apiSocket}";
+ optionalString (cfg.apiSocket != null) " --api-server=${cfg.apiSocket}"
+ optionalString (cfg.logFile != null) " --logfile=${cfg.logFile}"
;
printerConfigPath =
if cfg.mutableConfig
then cfg.mutableConfigFolder + "/printer.cfg"
@ -177,7 +189,7 @@ in
'';
serviceConfig = {
ExecStart = "${cfg.package}/lib/klipper/klippy.py ${klippyArgs} ${printerConfigPath}";
ExecStart = "${cfg.package}/bin/klippy ${klippyArgs} ${printerConfigPath}";
RuntimeDirectory = "klipper";
StateDirectory = "klipper";
SupplementaryGroups = [ "dialout" ];

View file

@ -72,7 +72,7 @@ in {
example = {
authorization = {
trusted_clients = [ "10.0.0.0/24" ];
cors_domains = [ "https://app.fluidd.xyz" ];
cors_domains = [ "https://app.fluidd.xyz" "https://my.mainsail.xyz" ];
};
};
description = lib.mdDoc ''

View file

@ -0,0 +1,99 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.rshim;
rshimCommand = [ "${cfg.package}/bin/rshim" ]
++ lib.optionals (cfg.backend != null) [ "--backend ${cfg.backend}" ]
++ lib.optionals (cfg.device != null) [ "--device ${cfg.device}" ]
++ lib.optionals (cfg.index != null) [ "--index ${builtins.toString cfg.index}" ]
++ [ "--log-level ${builtins.toString cfg.log-level}" ]
;
in
{
options.services.rshim = {
enable = lib.mkEnableOption (lib.mdDoc "User-space rshim driver for the BlueField SoC");
package = lib.mkPackageOptionMD pkgs "rshim-user-space" { };
backend = lib.mkOption {
type = with lib.types; nullOr (enum [ "usb" "pcie" "pcie_lf" ]);
description = lib.mdDoc ''
Specify the backend to attach. If not specified, the driver will scan
all rshim backends unless the `device` option is given with a device
name specified.
'';
default = null;
example = "pcie";
};
device = lib.mkOption {
type = with lib.types; nullOr str;
description = lib.mdDoc ''
Specify the device name to attach. The backend driver can be deduced
from the device name, thus the `backend` option is not needed.
'';
default = null;
example = "pcie-04:00.2";
};
index = lib.mkOption {
type = with lib.types; nullOr int;
description = lib.mdDoc ''
Specify the index to create device path `/dev/rshim<index>`. It's also
used to create network interface name `tmfifo_net<index>`. This option
is needed when multiple rshim instances are running.
'';
default = null;
example = 1;
};
log-level = lib.mkOption {
type = lib.types.int;
description = lib.mdDoc ''
Specify the log level (0:none, 1:error, 2:warning, 3:notice, 4:debug).
'';
default = 2;
example = 4;
};
config = lib.mkOption {
type = with lib.types; attrsOf (oneOf [ int str ]);
description = lib.mdDoc ''
Structural setting for the rshim configuration file
(`/etc/rshim.conf`). It can be used to specify the static mapping
between rshim devices and rshim names. It can also be used to ignore
some rshim devices.
'';
default = { };
example = {
DISPLAY_LEVEL = 0;
rshim0 = "usb-2-1.7";
none = "usb-1-1.4";
};
};
};
config = lib.mkIf cfg.enable {
environment.etc = lib.mkIf (cfg.config != { }) {
"rshim.conf".text = lib.generators.toKeyValue
{ mkKeyValue = lib.generators.mkKeyValueDefault { } " "; }
cfg.config;
};
systemd.services.rshim = {
after = [ "network.target" ];
serviceConfig = {
Restart = "always";
Type = "forking";
ExecStart = [
(lib.concatStringsSep " \\\n" rshimCommand)
];
KillMode = "control-group";
};
wantedBy = [ "multi-user.target" ];
};
};
meta.maintainers = with lib.maintainers; [ nikstur ];
}

View file

@ -4,6 +4,81 @@ with lib;
let
cfg = config.services.snapper;
mkValue = v:
if isList v then "\"${concatMapStringsSep " " (escape [ "\\" " " ]) v}\""
else if v == true then "yes"
else if v == false then "no"
else if isString v then "\"${v}\""
else builtins.toJSON v;
mkKeyValue = k: v: "${k}=${mkValue v}";
# "it's recommended to always specify the filesystem type" -- man snapper-configs
defaultOf = k: if k == "FSTYPE" then null else configOptions.${k}.default or null;
safeStr = types.strMatching "[^\n\"]*" // {
description = "string without line breaks or quotes";
descriptionClass = "conjunction";
};
configOptions = {
SUBVOLUME = mkOption {
type = types.path;
description = lib.mdDoc ''
Path of the subvolume or mount point.
This path is a subvolume and has to contain a subvolume named
.snapshots.
See also man:snapper(8) section PERMISSIONS.
'';
};
FSTYPE = mkOption {
type = types.enum [ "btrfs" ];
default = "btrfs";
description = lib.mdDoc ''
Filesystem type. Only btrfs is stable and tested.
'';
};
ALLOW_GROUPS = mkOption {
type = types.listOf safeStr;
default = [];
description = lib.mdDoc ''
List of groups allowed to operate with the config.
Also see the PERMISSIONS section in man:snapper(8).
'';
};
ALLOW_USERS = mkOption {
type = types.listOf safeStr;
default = [];
example = [ "alice" ];
description = lib.mdDoc ''
List of users allowed to operate with the config. "root" is always
implicitly included.
Also see the PERMISSIONS section in man:snapper(8).
'';
};
TIMELINE_CLEANUP = mkOption {
type = types.bool;
default = false;
description = lib.mdDoc ''
Defines whether the timeline cleanup algorithm should be run for the config.
'';
};
TIMELINE_CREATE = mkOption {
type = types.bool;
default = false;
description = lib.mdDoc ''
Defines whether hourly snapshots should be created.
'';
};
};
in
{
@ -52,49 +127,23 @@ in
example = literalExpression ''
{
home = {
subvolume = "/home";
extraConfig = '''
ALLOW_USERS="alice"
TIMELINE_CREATE=yes
TIMELINE_CLEANUP=yes
''';
SUBVOLUME = "/home";
ALLOW_USERS = [ "alice" ];
TIMELINE_CREATE = true;
TIMELINE_CLEANUP = true;
};
}
'';
description = lib.mdDoc ''
Subvolume configuration
Subvolume configuration. Any option mentioned in man:snapper-configs(5)
is valid here, even if NixOS doesn't document it.
'';
type = types.attrsOf (types.submodule {
options = {
subvolume = mkOption {
type = types.path;
description = lib.mdDoc ''
Path of the subvolume or mount point.
This path is a subvolume and has to contain a subvolume named
.snapshots.
See also man:snapper(8) section PERMISSIONS.
'';
};
freeformType = types.attrsOf (types.oneOf [ (types.listOf safeStr) types.bool safeStr types.number ]);
fstype = mkOption {
type = types.enum [ "btrfs" ];
default = "btrfs";
description = lib.mdDoc ''
Filesystem type. Only btrfs is stable and tested.
'';
};
extraConfig = mkOption {
type = types.lines;
default = "";
description = lib.mdDoc ''
Additional configuration next to SUBVOLUME and FSTYPE.
See man:snapper-configs(5).
'';
};
};
options = configOptions;
});
};
};
@ -117,11 +166,7 @@ in
}
// (mapAttrs' (name: subvolume: nameValuePair "snapper/configs/${name}" ({
text = ''
${subvolume.extraConfig}
FSTYPE="${subvolume.fstype}"
SUBVOLUME="${subvolume.subvolume}"
'';
text = lib.generators.toKeyValue { inherit mkKeyValue; } (filterAttrs (k: v: v != defaultOf k) subvolume);
})) cfg.configs)
// (lib.optionalAttrs (cfg.filters != null) {
"snapper/filters/default.txt".text = cfg.filters;
@ -181,5 +226,28 @@ in
unitConfig.ConditionPathExists = "/etc/snapper/configs/root";
};
assertions =
concatMap
(name:
let
sub = cfg.configs.${name};
in
[ { assertion = !(sub ? extraConfig);
message = ''
The option definition `services.snapper.configs.${name}.extraConfig' no longer has any effect; please remove it.
The contents of this option should be migrated to attributes on `services.snapper.configs.${name}'.
'';
}
] ++
map
(attr: {
assertion = !(hasAttr attr sub);
message = ''
The option definition `services.snapper.configs.${name}.${attr}' has been renamed to `services.snapper.configs.${name}.${toUpper attr}'.
'';
})
[ "fstype" "subvolume" ]
)
(attrNames cfg.configs);
});
}

View file

@ -65,7 +65,6 @@ in
agent.enabled = true;
agent.scrape_integration = true;
node_exporter.enabled = true;
replace_instance_label = true;
};
}
'';
@ -122,7 +121,6 @@ in
agent.enabled = mkDefault true;
agent.scrape_integration = mkDefault true;
node_exporter.enabled = mkDefault true;
replace_instance_label = mkDefault true;
};
};

View file

@ -169,6 +169,20 @@ in {
See: <https://learn.netdata.cloud/docs/agent/anonymous-statistics>
'';
};
deadlineBeforeStopSec = mkOption {
type = types.int;
default = 120;
description = lib.mdDoc ''
In order to detect when netdata is misbehaving, we run a concurrent task pinging netdata (wait-for-netdata-up)
in the systemd unit.
If after a while, this task does not succeed, we stop the unit and mark it as failed.
You can control this deadline in seconds with this option, it's useful to bump it
if you have (1) a lot of data (2) doing upgrades (3) have low IOPS/throughput.
'';
};
};
};
@ -205,7 +219,7 @@ in {
while [ "$(${pkgs.netdata}/bin/netdatacli ping)" != pong ]; do sleep 0.5; done
'';
TimeoutStopSec = 60;
TimeoutStopSec = cfg.deadlineBeforeStopSec;
Restart = "on-failure";
# User and group
User = cfg.user;

View file

@ -6,10 +6,12 @@ let
cfg = config.services.prometheus.alertmanager;
mkConfigFile = pkgs.writeText "alertmanager.yml" (builtins.toJSON cfg.configuration);
checkedConfig = file: pkgs.runCommand "checked-config" { buildInputs = [ cfg.package ]; } ''
ln -s ${file} $out
amtool check-config $out
'';
checkedConfig = file:
if cfg.checkConfig then
pkgs.runCommand "checked-config" { buildInputs = [ cfg.package ]; } ''
ln -s ${file} $out
amtool check-config $out
'' else file;
alertmanagerYml = let
yml = if cfg.configText != null then
@ -70,6 +72,20 @@ in {
'';
};
checkConfig = mkOption {
type = types.bool;
default = true;
description = lib.mdDoc ''
Check configuration with `amtool check-config`. The call to `amtool` is
subject to sandboxing by Nix.
If you use credentials stored in external files
(`environmentFile`, etc),
they will not be visible to `amtool`
and it will report errors, despite a correct configuration.
'';
};
logFormat = mkOption {
type = types.nullOr types.str;
default = null;

View file

@ -76,7 +76,7 @@ example:
directory, which will be called postfix.nix and contains all exporter
specific options and configuration:
```
# nixpgs/nixos/modules/services/prometheus/exporters/postfix.nix
# nixpkgs/nixos/modules/services/prometheus/exporters/postfix.nix
{ config, lib, pkgs, options }:
with lib;

View file

@ -43,6 +43,8 @@ in
services.uptime-kuma.settings = {
DATA_DIR = "/var/lib/uptime-kuma/";
NODE_ENV = mkDefault "production";
HOST = mkDefault "127.0.0.1";
PORT = mkDefault "3001";
};
systemd.services.uptime-kuma = {

View file

@ -28,6 +28,12 @@ in
description = lib.mdDoc "Group to run under when setuid is not enabled.";
};
debug = mkOption {
type = types.bool;
default = false;
description = lib.mdDoc "Enable debug mode.";
};
settings = mkOption {
type = format.type;
default = { };
@ -111,7 +117,7 @@ in
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = "${pkgs.webdav-server-rs}/bin/webdav-server -c ${cfg.configFile}";
ExecStart = "${pkgs.webdav-server-rs}/bin/webdav-server ${lib.optionalString cfg.debug "--debug"} -c ${cfg.configFile}";
CapabilityBoundingSet = [
"CAP_SETUID"

View file

@ -0,0 +1,101 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.alice-lg;
settingsFormat = pkgs.formats.ini { };
in
{
options = {
services.alice-lg = {
enable = mkEnableOption (lib.mdDoc "Alice Looking Glass");
package = mkPackageOptionMD pkgs "alice-lg" { };
settings = mkOption {
type = settingsFormat.type;
default = { };
description = lib.mdDoc ''
alice-lg configuration, for configuration options see the example on [github](https://github.com/alice-lg/alice-lg/blob/main/etc/alice-lg/alice.example.conf)
'';
example = literalExpression ''
{
server = {
# configures the built-in webserver and provides global application settings
listen_http = "127.0.0.1:7340";
enable_prefix_lookup = true;
asn = 9033;
store_backend = postgres;
routes_store_refresh_parallelism = 5;
neighbors_store_refresh_parallelism = 10000;
routes_store_refresh_interval = 5;
neighbors_store_refresh_interval = 5;
};
postgres = {
url = "postgres://postgres:postgres@localhost:5432/alice";
min_connections = 2;
max_connections = 128;
};
pagination = {
routes_filtered_page_size = 250;
routes_accepted_page_size = 250;
routes_not_exported_page_size = 250;
};
}
'';
};
};
};
config = lib.mkIf cfg.enable {
environment = {
etc."alice-lg/alice.conf".source = settingsFormat.generate "alice-lg.conf" cfg.settings;
};
systemd.services = {
alice-lg = {
wants = [ "network.target" ];
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
description = "Alice Looking Glass";
serviceConfig = {
DynamicUser = true;
Type = "simple";
Restart = "on-failure";
RestartSec = 15;
ExecStart = "${cfg.package}/bin/alice-lg";
StateDirectoryMode = "0700";
UMask = "0007";
CapabilityBoundingSet = "";
NoNewPrivileges = true;
ProtectSystem = "strict";
PrivateTmp = true;
PrivateDevices = true;
PrivateUsers = true;
ProtectHostname = true;
ProtectClock = true;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectKernelLogs = true;
ProtectControlGroups = true;
RestrictAddressFamilies = [ "AF_INET AF_INET6" ];
LockPersonality = true;
MemoryDenyWriteExecute = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
PrivateMounts = true;
SystemCallArchitectures = "native";
SystemCallFilter = "~@clock @privileged @cpu-emulation @debug @keyring @module @mount @obsolete @raw-io @reboot @setuid @swap";
BindReadOnlyPaths = [
"-/etc/resolv.conf"
"-/etc/nsswitch.conf"
"-/etc/ssl/certs"
"-/etc/static/ssl/certs"
"-/etc/hosts"
"-/etc/localtime"
];
};
};
};
};
}

View file

@ -0,0 +1,129 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.birdwatcher;
in
{
options = {
services.birdwatcher = {
package = mkOption {
type = types.package;
default = pkgs.birdwatcher;
defaultText = literalExpression "pkgs.birdwatcher";
description = lib.mdDoc "The Birdwatcher package to use.";
};
enable = mkEnableOption (lib.mdDoc "Birdwatcher");
flags = mkOption {
default = [ ];
type = types.listOf types.str;
example = [ "-worker-pool-size 16" "-6" ];
description = lib.mdDoc ''
Flags to append to the program call
'';
};
settings = mkOption {
type = types.lines;
default = { };
description = lib.mdDoc ''
birdwatcher configuration, for configuration options see the example on [github](https://github.com/alice-lg/birdwatcher/blob/master/etc/birdwatcher/birdwatcher.conf)
'';
example = literalExpression ''
[server]
allow_from = []
allow_uncached = false
modules_enabled = ["status",
"protocols",
"protocols_bgp",
"protocols_short",
"routes_protocol",
"routes_peer",
"routes_table",
"routes_table_filtered",
"routes_table_peer",
"routes_filtered",
"routes_prefixed",
"routes_noexport",
"routes_pipe_filtered_count",
"routes_pipe_filtered"
]
[status]
reconfig_timestamp_source = "bird"
reconfig_timestamp_match = "# created: (.*)"
filter_fields = []
[bird]
listen = "0.0.0.0:29184"
config = "/etc/bird/bird2.conf"
birdc = "''${pkgs.bird}/bin/birdc"
ttl = 5 # time to live (in minutes) for caching of cli output
[parser]
filter_fields = []
[cache]
use_redis = false # if not using redis cache, activate housekeeping to save memory!
[housekeeping]
interval = 5
force_release_memory = true
'';
};
};
};
config =
let flagsStr = escapeShellArgs cfg.flags;
in lib.mkIf cfg.enable {
environment.etc."birdwatcher/birdwatcher.conf".source = pkgs.writeTextFile {
name = "birdwatcher.conf";
text = cfg.settings;
};
systemd.services = {
birdwatcher = {
wants = [ "network.target" ];
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
description = "Birdwatcher";
serviceConfig = {
Type = "simple";
Restart = "on-failure";
RestartSec = 15;
ExecStart = "${cfg.package}/bin/birdwatcher";
StateDirectoryMode = "0700";
UMask = "0117";
NoNewPrivileges = true;
ProtectSystem = "strict";
PrivateTmp = true;
PrivateDevices = true;
ProtectHostname = true;
ProtectClock = true;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectKernelLogs = true;
ProtectControlGroups = true;
RestrictAddressFamilies = [ "AF_UNIX AF_INET AF_INET6" ];
LockPersonality = true;
MemoryDenyWriteExecute = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
PrivateMounts = true;
SystemCallArchitectures = "native";
SystemCallFilter = "~@clock @privileged @cpu-emulation @debug @keyring @module @mount @obsolete @raw-io @reboot @setuid @swap";
BindReadOnlyPaths = [
"-/etc/resolv.conf"
"-/etc/nsswitch.conf"
"-/etc/ssl/certs"
"-/etc/static/ssl/certs"
"-/etc/hosts"
"-/etc/localtime"
];
};
};
};
};
}

View file

@ -0,0 +1,88 @@
{ config, pkgs, lib, ... }:
let
cfg = config.services.harmonia;
format = pkgs.formats.toml { };
in
{
options = {
services.harmonia = {
enable = lib.mkEnableOption (lib.mdDoc "Harmonia: Nix binary cache written in Rust");
signKeyPath = lib.mkOption {
type = lib.types.nullOr lib.types.path;
default = null;
description = lib.mdDoc "Path to the signing key that will be used for signing the cache";
};
package = lib.mkPackageOptionMD pkgs "harmonia" { };
settings = lib.mkOption {
inherit (format) type;
default = { };
description = lib.mdDoc ''
Settings to merge with the default configuration.
For the list of the default configuration, see <https://github.com/nix-community/harmonia/tree/master#configuration>.
'';
};
};
};
config = lib.mkIf cfg.enable {
systemd.services.harmonia = {
description = "harmonia binary cache service";
requires = [ "nix-daemon.socket" ];
after = [ "network.target" ];
wantedBy = [ "multi-user.target" ];
environment = {
CONFIG_FILE = format.generate "harmonia.toml" cfg.settings;
SIGN_KEY_PATH = lib.mkIf (cfg.signKeyPath != null) "%d/sign-key";
# Note: it's important to set this for nix-store, because it wants to use
# $HOME in order to use a temporary cache dir. bizarre failures will occur
# otherwise
HOME = "/run/harmonia";
};
serviceConfig = {
ExecStart = lib.getExe cfg.package;
User = "harmonia";
Group = "harmonia";
DynamicUser = true;
PrivateUsers = true;
DeviceAllow = [ "" ];
UMask = "0066";
RuntimeDirectory = "harmonia";
LoadCredential = lib.mkIf (cfg.signKeyPath != null) [ "sign-key:${cfg.signKeyPath}" ];
SystemCallFilter = [
"@system-service"
"~@privileged"
"~@resources"
];
CapabilityBoundingSet = "";
ProtectKernelModules = true;
ProtectKernelTunables = true;
ProtectControlGroups = true;
ProtectKernelLogs = true;
ProtectHostname = true;
ProtectClock = true;
RestrictRealtime = true;
MemoryDenyWriteExecute = true;
ProcSubset = "pid";
ProtectProc = "invisible";
RestrictNamespaces = true;
SystemCallArchitectures = "native";
PrivateNetwork = false;
PrivateTmp = true;
PrivateDevices = true;
PrivateMounts = true;
NoNewPrivileges = true;
ProtectSystem = "strict";
ProtectHome = true;
LockPersonality = true;
RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
LimitNOFILE = 65536;
};
};
};
}

View file

@ -365,9 +365,6 @@ in
"hmac-sha2-512-etm@openssh.com"
"hmac-sha2-256-etm@openssh.com"
"umac-128-etm@openssh.com"
"hmac-sha2-512"
"hmac-sha2-256"
"umac-128@openssh.com"
];
description = lib.mdDoc ''
Allowed MACs

View file

@ -8,7 +8,8 @@ let
cmdArgs =
[ "--port" cfg.port ]
++ optionals (cfg.salt != null) [ "--salt" cfg.salt ]
++ optionals (cfg.certDir != null) [ "--tls" cfg.certDir ];
++ optionals (cfg.certDir != null) [ "--tls" cfg.certDir ]
++ cfg.extraArgs;
in
{
@ -33,7 +34,22 @@ in
default = null;
description = lib.mdDoc ''
Salt to allow room operator passwords generated by this server
instance to still work when the server is restarted.
instance to still work when the server is restarted. The salt will be
readable in the nix store and the processlist. If this is not
intended use `saltFile` instead. Mutually exclusive with
<option>services.syncplay.saltFile</option>.
'';
};
saltFile = mkOption {
type = types.nullOr types.path;
default = null;
description = lib.mdDoc ''
Path to the file that contains the server salt. This allows room
operator passwords generated by this server instance to still work
when the server is restarted. `null`, the server doesn't load the
salt from a file. Mutually exclusive with
<option>services.syncplay.salt</option>.
'';
};
@ -46,6 +62,14 @@ in
'';
};
extraArgs = mkOption {
type = types.listOf types.str;
default = [ ];
description = lib.mdDoc ''
Additional arguments to be passed to the service.
'';
};
user = mkOption {
type = types.str;
default = "nobody";
@ -74,21 +98,31 @@ in
};
config = mkIf cfg.enable {
assertions = [
{
assertion = cfg.salt == null || cfg.saltFile == null;
message = "services.syncplay.salt and services.syncplay.saltFile are mutually exclusive.";
}
];
systemd.services.syncplay = {
description = "Syncplay Service";
wantedBy = [ "multi-user.target" ];
after = [ "network-online.target" ];
wantedBy = [ "multi-user.target" ];
after = [ "network-online.target" ];
serviceConfig = {
User = cfg.user;
Group = cfg.group;
LoadCredential = lib.mkIf (cfg.passwordFile != null) "password:${cfg.passwordFile}";
LoadCredential = lib.optional (cfg.passwordFile != null) "password:${cfg.passwordFile}"
++ lib.optional (cfg.saltFile != null) "salt:${cfg.saltFile}";
};
script = ''
${lib.optionalString (cfg.passwordFile != null) ''
export SYNCPLAY_PASSWORD=$(cat "''${CREDENTIALS_DIRECTORY}/password")
''}
${lib.optionalString (cfg.saltFile != null) ''
export SYNCPLAY_SALT=$(cat "''${CREDENTIALS_DIRECTORY}/salt")
''}
exec ${pkgs.syncplay-nogui}/bin/syncplay-server ${escapeShellArgs cmdArgs}
'';
};

View file

@ -7,25 +7,24 @@ let
opt = options.services.syncthing;
defaultUser = "syncthing";
defaultGroup = defaultUser;
settingsFormat = pkgs.formats.json { };
devices = mapAttrsToList (name: device: {
devices = mapAttrsToList (_: device: device // {
deviceID = device.id;
inherit (device) name addresses introducer autoAcceptFolders;
}) cfg.devices;
}) cfg.settings.devices;
folders = mapAttrsToList ( _: folder: {
inherit (folder) path id label type;
devices = map (device: { deviceId = cfg.devices.${device}.id; }) folder.devices;
rescanIntervalS = folder.rescanInterval;
fsWatcherEnabled = folder.watch;
fsWatcherDelayS = folder.watchDelay;
ignorePerms = folder.ignorePerms;
ignoreDelete = folder.ignoreDelete;
versioning = folder.versioning;
}) (filterAttrs (
_: folder:
folder.enable
) cfg.folders);
folders = mapAttrsToList (_: folder: folder //
throwIf (folder?rescanInterval || folder?watch || folder?watchDelay) ''
The options services.syncthing.settings.folders.<name>.{rescanInterval,watch,watchDelay}
were removed. Please use, respectively, {rescanIntervalS,fsWatcherEnabled,fsWatcherDelayS} instead.
'' {
devices = map (device:
if builtins.isString device then
{ deviceId = cfg.settings.devices.${device}.id; }
else
device
) folder.devices;
}) cfg.settings.folders;
updateConfig = pkgs.writers.writeDash "merge-syncthing-config" ''
set -efu
@ -54,10 +53,10 @@ let
old_cfg=$(curl ${cfg.guiAddress}/rest/config)
# generate the new config by merging with the NixOS config options
new_cfg=$(printf '%s\n' "$old_cfg" | ${pkgs.jq}/bin/jq -c '. * {
"devices": (${builtins.toJSON devices}${optionalString (cfg.devices == {} || ! cfg.overrideDevices) " + .devices"}),
"folders": (${builtins.toJSON folders}${optionalString (cfg.folders == {} || ! cfg.overrideFolders) " + .folders"})
} * ${builtins.toJSON cfg.extraOptions}')
new_cfg=$(printf '%s\n' "$old_cfg" | ${pkgs.jq}/bin/jq -c ${escapeShellArg ''. * ${builtins.toJSON cfg.settings} * {
"devices": (${builtins.toJSON devices}${optionalString (cfg.settings.devices == {} || ! cfg.overrideDevices) " + .devices"}),
"folders": (${builtins.toJSON folders}${optionalString (cfg.settings.folders == {} || ! cfg.overrideFolders) " + .folders"})
}''})
# send the new config
curl -X PUT -d "$new_cfg" ${cfg.guiAddress}/rest/config
@ -99,287 +98,282 @@ in {
default = true;
description = mdDoc ''
Whether to delete the devices which are not configured via the
[devices](#opt-services.syncthing.devices) option.
[devices](#opt-services.syncthing.settings.devices) option.
If set to `false`, devices added via the web
interface will persist and will have to be deleted manually.
'';
};
devices = mkOption {
default = {};
description = mdDoc ''
Peers/devices which Syncthing should communicate with.
Note that you can still add devices manually, but those changes
will be reverted on restart if [overrideDevices](#opt-services.syncthing.overrideDevices)
is enabled.
'';
example = {
bigbox = {
id = "7CFNTQM-IMTJBHJ-3UWRDIU-ZGQJFR6-VCXZ3NB-XUH3KZO-N52ITXR-LAIYUAU";
addresses = [ "tcp://192.168.0.10:51820" ];
};
};
type = types.attrsOf (types.submodule ({ name, ... }: {
options = {
name = mkOption {
type = types.str;
default = name;
description = lib.mdDoc ''
The name of the device.
'';
};
addresses = mkOption {
type = types.listOf types.str;
default = [];
description = lib.mdDoc ''
The addresses used to connect to the device.
If this is left empty, dynamic configuration is attempted.
'';
};
id = mkOption {
type = types.str;
description = mdDoc ''
The device ID. See <https://docs.syncthing.net/dev/device-ids.html>.
'';
};
introducer = mkOption {
type = types.bool;
default = false;
description = mdDoc ''
Whether the device should act as an introducer and be allowed
to add folders on this computer.
See <https://docs.syncthing.net/users/introducer.html>.
'';
};
autoAcceptFolders = mkOption {
type = types.bool;
default = false;
description = mdDoc ''
Automatically create or share folders that this device advertises at the default path.
See <https://docs.syncthing.net/users/config.html?highlight=autoaccept#config-file-format>.
'';
};
};
}));
};
overrideFolders = mkOption {
type = types.bool;
default = true;
description = mdDoc ''
Whether to delete the folders which are not configured via the
[folders](#opt-services.syncthing.folders) option.
[folders](#opt-services.syncthing.settings.folders) option.
If set to `false`, folders added via the web
interface will persist and will have to be deleted manually.
'';
};
folders = mkOption {
default = {};
description = mdDoc ''
Folders which should be shared by Syncthing.
Note that you can still add folders manually, but those changes
will be reverted on restart if [overrideFolders](#opt-services.syncthing.overrideFolders)
is enabled.
'';
example = literalExpression ''
{
"/home/user/sync" = {
id = "syncme";
devices = [ "bigbox" ];
};
}
'';
type = types.attrsOf (types.submodule ({ name, ... }: {
settings = mkOption {
type = types.submodule {
freeformType = settingsFormat.type;
options = {
enable = mkOption {
type = types.bool;
default = true;
description = lib.mdDoc ''
Whether to share this folder.
This option is useful when you want to define all folders
in one place, but not every machine should share all folders.
'';
};
path = mkOption {
# TODO for release 23.05: allow relative paths again and set
# working directory to cfg.dataDir
type = types.str // {
check = x: types.str.check x && (substring 0 1 x == "/" || substring 0 2 x == "~/");
description = types.str.description + " starting with / or ~/";
};
default = name;
description = lib.mdDoc ''
The path to the folder which should be shared.
Only absolute paths (starting with `/`) and paths relative to
the [user](#opt-services.syncthing.user)'s home directory
(starting with `~/`) are allowed.
'';
};
id = mkOption {
type = types.str;
default = name;
description = lib.mdDoc ''
The ID of the folder. Must be the same on all devices.
'';
};
label = mkOption {
type = types.str;
default = name;
description = lib.mdDoc ''
The label of the folder.
'';
};
devices = mkOption {
type = types.listOf types.str;
default = [];
# global options
options = mkOption {
default = {};
description = mdDoc ''
The devices this folder should be shared with. Each device must
be defined in the [devices](#opt-services.syncthing.devices) option.
The options element contains all other global configuration options
'';
};
versioning = mkOption {
default = null;
description = mdDoc ''
How to keep changed/deleted files with Syncthing.
There are 4 different types of versioning with different parameters.
See <https://docs.syncthing.net/users/versioning.html>.
'';
example = literalExpression ''
[
{
versioning = {
type = "simple";
params.keep = "10";
};
}
{
versioning = {
type = "trashcan";
params.cleanoutDays = "1000";
};
}
{
versioning = {
type = "staggered";
fsPath = "/syncthing/backup";
params = {
cleanInterval = "3600";
maxAge = "31536000";
};
};
}
{
versioning = {
type = "external";
params.versionsPath = pkgs.writers.writeBash "backup" '''
folderpath="$1"
filepath="$2"
rm -rf "$folderpath/$filepath"
''';
};
}
]
'';
type = with types; nullOr (submodule {
type = types.submodule ({ name, ... }: {
freeformType = settingsFormat.type;
options = {
type = mkOption {
type = enum [ "external" "simple" "staggered" "trashcan" ];
description = mdDoc ''
The type of versioning.
See <https://docs.syncthing.net/users/versioning.html>.
localAnnounceEnabled = mkOption {
type = types.bool;
default = true;
description = lib.mdDoc ''
Whether to send announcements to the local LAN, also use such announcements to find other devices.
'';
};
fsPath = mkOption {
default = "";
type = either str path;
description = mdDoc ''
Path to the versioning folder.
See <https://docs.syncthing.net/users/versioning.html>.
localAnnouncePort = mkOption {
type = types.int;
default = 21027;
description = lib.mdDoc ''
The port on which to listen and send IPv4 broadcast announcements to.
'';
};
params = mkOption {
type = attrsOf (either str path);
description = mdDoc ''
The parameters for versioning. Structure depends on
[versioning.type](#opt-services.syncthing.folders._name_.versioning.type).
See <https://docs.syncthing.net/users/versioning.html>.
relaysEnabled = mkOption {
type = types.bool;
default = true;
description = lib.mdDoc ''
When true, relays will be connected to and potentially used for device to device connections.
'';
};
urAccepted = mkOption {
type = types.int;
default = 0;
description = lib.mdDoc ''
Whether the user has accepted to submit anonymous usage data.
The default, 0, mean the user has not made a choice, and Syncthing will ask at some point in the future.
"-1" means no, a number above zero means that that version of usage reporting has been accepted.
'';
};
limitBandwidthInLan = mkOption {
type = types.bool;
default = false;
description = lib.mdDoc ''
Whether to apply bandwidth limits to devices in the same broadcast domain as the local device.
'';
};
maxFolderConcurrency = mkOption {
type = types.int;
default = 0;
description = lib.mdDoc ''
This option controls how many folders may concurrently be in I/O-intensive operations such as syncing or scanning.
The mechanism is described in detail in a [separate chapter](https://docs.syncthing.net/advanced/option-max-concurrency.html).
'';
};
};
});
};
rescanInterval = mkOption {
type = types.int;
default = 3600;
description = lib.mdDoc ''
How often the folder should be rescanned for changes.
'';
};
type = mkOption {
type = types.enum [ "sendreceive" "sendonly" "receiveonly" "receiveencrypted" ];
default = "sendreceive";
description = lib.mdDoc ''
Whether to only send changes for this folder, only receive them
or both. `receiveencrypted` can be used for untrusted devices. See
<https://docs.syncthing.net/users/untrusted.html> for reference.
'';
};
watch = mkOption {
type = types.bool;
default = true;
description = lib.mdDoc ''
Whether the folder should be watched for changes by inotify.
'';
};
watchDelay = mkOption {
type = types.int;
default = 10;
description = lib.mdDoc ''
The delay after an inotify event is triggered.
'';
};
ignorePerms = mkOption {
type = types.bool;
default = true;
description = lib.mdDoc ''
Whether to ignore permission changes.
'';
};
ignoreDelete = mkOption {
type = types.bool;
default = false;
# device settings
devices = mkOption {
default = {};
description = mdDoc ''
Whether to skip deleting files that are deleted by peers.
See <https://docs.syncthing.net/advanced/folder-ignoredelete.html>.
'';
};
};
}));
};
Peers/devices which Syncthing should communicate with.
extraOptions = mkOption {
type = types.addCheck (pkgs.formats.json {}).type isAttrs;
Note that you can still add devices manually, but those changes
will be reverted on restart if [overrideDevices](#opt-services.syncthing.overrideDevices)
is enabled.
'';
example = {
bigbox = {
id = "7CFNTQM-IMTJBHJ-3UWRDIU-ZGQJFR6-VCXZ3NB-XUH3KZO-N52ITXR-LAIYUAU";
addresses = [ "tcp://192.168.0.10:51820" ];
};
};
type = types.attrsOf (types.submodule ({ name, ... }: {
freeformType = settingsFormat.type;
options = {
name = mkOption {
type = types.str;
default = name;
description = lib.mdDoc ''
The name of the device.
'';
};
id = mkOption {
type = types.str;
description = mdDoc ''
The device ID. See <https://docs.syncthing.net/dev/device-ids.html>.
'';
};
autoAcceptFolders = mkOption {
type = types.bool;
default = false;
description = mdDoc ''
Automatically create or share folders that this device advertises at the default path.
See <https://docs.syncthing.net/users/config.html?highlight=autoaccept#config-file-format>.
'';
};
};
}));
};
# folder settings
folders = mkOption {
default = {};
description = mdDoc ''
Folders which should be shared by Syncthing.
Note that you can still add folders manually, but those changes
will be reverted on restart if [overrideFolders](#opt-services.syncthing.overrideFolders)
is enabled.
'';
example = literalExpression ''
{
"/home/user/sync" = {
id = "syncme";
devices = [ "bigbox" ];
};
}
'';
type = types.attrsOf (types.submodule ({ name, ... }: {
freeformType = settingsFormat.type;
options = {
enable = mkOption {
type = types.bool;
default = true;
description = lib.mdDoc ''
Whether to share this folder.
This option is useful when you want to define all folders
in one place, but not every machine should share all folders.
'';
};
path = mkOption {
# TODO for release 23.05: allow relative paths again and set
# working directory to cfg.dataDir
type = types.str // {
check = x: types.str.check x && (substring 0 1 x == "/" || substring 0 2 x == "~/");
description = types.str.description + " starting with / or ~/";
};
default = name;
description = lib.mdDoc ''
The path to the folder which should be shared.
Only absolute paths (starting with `/`) and paths relative to
the [user](#opt-services.syncthing.user)'s home directory
(starting with `~/`) are allowed.
'';
};
id = mkOption {
type = types.str;
default = name;
description = lib.mdDoc ''
The ID of the folder. Must be the same on all devices.
'';
};
label = mkOption {
type = types.str;
default = name;
description = lib.mdDoc ''
The label of the folder.
'';
};
devices = mkOption {
type = types.listOf types.str;
default = [];
description = mdDoc ''
The devices this folder should be shared with. Each device must
be defined in the [devices](#opt-services.syncthing.settings.devices) option.
'';
};
versioning = mkOption {
default = null;
description = mdDoc ''
How to keep changed/deleted files with Syncthing.
There are 4 different types of versioning with different parameters.
See <https://docs.syncthing.net/users/versioning.html>.
'';
example = literalExpression ''
[
{
versioning = {
type = "simple";
params.keep = "10";
};
}
{
versioning = {
type = "trashcan";
params.cleanoutDays = "1000";
};
}
{
versioning = {
type = "staggered";
fsPath = "/syncthing/backup";
params = {
cleanInterval = "3600";
maxAge = "31536000";
};
};
}
{
versioning = {
type = "external";
params.versionsPath = pkgs.writers.writeBash "backup" '''
folderpath="$1"
filepath="$2"
rm -rf "$folderpath/$filepath"
''';
};
}
]
'';
type = with types; nullOr (submodule {
freeformType = settingsFormat.type;
options = {
type = mkOption {
type = enum [ "external" "simple" "staggered" "trashcan" ];
description = mdDoc ''
The type of versioning.
See <https://docs.syncthing.net/users/versioning.html>.
'';
};
};
});
};
copyOwnershipFromParent = mkOption {
type = types.bool;
default = false;
description = mdDoc ''
On Unix systems, tries to copy file/folder ownership from the parent directory (the directory its located in).
Requires running Syncthing as a privileged user, or granting it additional capabilities (e.g. CAP_CHOWN on Linux).
'';
};
};
}));
};
};
};
default = {};
description = mdDoc ''
Extra configuration options for Syncthing.
@ -530,6 +524,10 @@ in {
This option was removed because Syncthing now has the inotify functionality included under the name "fswatcher".
It can be enabled on a per-folder basis through the web interface.
'')
(mkRenamedOptionModule [ "services" "syncthing" "extraOptions" ] [ "services" "syncthing" "settings" ])
(mkRenamedOptionModule [ "services" "syncthing" "folders" ] [ "services" "syncthing" "settings" "folders" ])
(mkRenamedOptionModule [ "services" "syncthing" "devices" ] [ "services" "syncthing" "settings" "devices" ])
(mkRenamedOptionModule [ "services" "syncthing" "options" ] [ "services" "syncthing" "settings" "options" ])
] ++ map (o:
mkRenamedOptionModule [ "services" "syncthing" "declarative" o ] [ "services" "syncthing" o ]
) [ "cert" "key" "devices" "folders" "overrideDevices" "overrideFolders" "extraOptions"];
@ -615,9 +613,7 @@ in {
];
};
};
syncthing-init = mkIf (
cfg.devices != {} || cfg.folders != {} || cfg.extraOptions != {}
) {
syncthing-init = mkIf (cfg.settings != {}) {
description = "Syncthing configuration updater";
requisite = [ "syncthing.service" ];
after = [ "syncthing.service" ];

View file

@ -170,10 +170,22 @@ let
# peer options
peerOpts = {
peerOpts = self: {
options = {
name = mkOption {
default =
replaceStrings
[ "/" "-" " " "+" "=" ]
[ "-" "\\x2d" "\\x20" "\\x2b" "\\x3d" ]
self.config.publicKey;
defaultText = literalExpression "publicKey";
example = "bernd";
type = types.str;
description = lib.mdDoc "Name used to derive peer unit name.";
};
publicKey = mkOption {
example = "xTIBA5rboUvnH4htodjb6e697QjLERt1NAB4mZqp8Dg=";
type = types.singleLineStr;
@ -313,15 +325,11 @@ let
'';
};
peerUnitServiceName = interfaceName: publicKey: dynamicRefreshEnabled:
peerUnitServiceName = interfaceName: peerName: dynamicRefreshEnabled:
let
keyToUnitName = replaceStrings
[ "/" "-" " " "+" "=" ]
[ "-" "\\x2d" "\\x20" "\\x2b" "\\x3d" ];
unitName = keyToUnitName publicKey;
refreshSuffix = optionalString dynamicRefreshEnabled "-refresh";
in
"wireguard-${interfaceName}-peer-${unitName}${refreshSuffix}";
"wireguard-${interfaceName}-peer-${peerName}${refreshSuffix}";
generatePeerUnit = { interfaceName, interfaceCfg, peer }:
let
@ -337,10 +345,11 @@ let
# We generate a different name (a `-refresh` suffix) when `dynamicEndpointRefreshSeconds`
# to avoid that the same service switches `Type` (`oneshot` vs `simple`),
# with the intent to make scripting more obvious.
serviceName = peerUnitServiceName interfaceName peer.publicKey dynamicRefreshEnabled;
serviceName = peerUnitServiceName interfaceName peer.name dynamicRefreshEnabled;
in nameValuePair serviceName
{
description = "WireGuard Peer - ${interfaceName} - ${peer.publicKey}";
description = "WireGuard Peer - ${interfaceName} - ${peer.name}"
+ optionalString (peer.name != peer.publicKey) " (${peer.publicKey})";
requires = [ "wireguard-${interfaceName}.service" ];
wants = [ "network-online.target" ];
after = [ "wireguard-${interfaceName}.service" "network-online.target" ];
@ -418,7 +427,7 @@ let
# the target is required to start new peer units when they are added
generateInterfaceTarget = name: values:
let
mkPeerUnit = peer: (peerUnitServiceName name peer.publicKey (peer.dynamicEndpointRefreshSeconds != 0)) + ".service";
mkPeerUnit = peer: (peerUnitServiceName name peer.name (peer.dynamicEndpointRefreshSeconds != 0)) + ".service";
in
nameValuePair "wireguard-${name}"
rec {

View file

@ -90,7 +90,7 @@ in
};
config = {
config = mkIf cfg.enable {
services.cloud-init.settings = {
system_info = mkDefault {
distro = "nixos";
@ -142,7 +142,6 @@ in
"power-state-change"
];
};
} // (mkIf cfg.enable {
environment.etc."cloud/cloud.cfg" =
if cfg.config == "" then
@ -225,5 +224,7 @@ in
description = "Cloud-config availability";
requires = [ "cloud-init-local.service" "cloud-init.service" ];
};
});
};
meta.maintainers = [ maintainers.zimbatm ];
}

View file

@ -93,7 +93,7 @@ in {
`true`.
It does NOT apply to the daemon port nor the web UI port. To access those
ports secuerly check the documentation
ports securely check the documentation
<https://dev.deluge-torrent.org/wiki/UserGuide/ThinClient#CreateSSHTunnel>
or use a VPN or configure certificates for deluge.
'';

View file

@ -0,0 +1,66 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.mainsail;
moonraker = config.services.moonraker;
in
{
options.services.mainsail = {
enable = mkEnableOption (lib.mdDoc "a modern and responsive user interface for Klipper");
package = mkOption {
type = types.package;
description = lib.mdDoc "Mainsail package to be used in the module";
default = pkgs.mainsail;
defaultText = literalExpression "pkgs.mainsail";
};
hostName = mkOption {
type = types.str;
default = "localhost";
description = lib.mdDoc "Hostname to serve mainsail on";
};
nginx = mkOption {
type = types.submodule
(import ../web-servers/nginx/vhost-options.nix { inherit config lib; });
default = { };
example = literalExpression ''
{
serverAliases = [ "mainsail.''${config.networking.domain}" ];
}
'';
description = lib.mdDoc "Extra configuration for the nginx virtual host of mainsail.";
};
};
config = mkIf cfg.enable {
services.nginx = {
enable = true;
upstreams.mainsail-apiserver.servers."${moonraker.address}:${toString moonraker.port}" = { };
virtualHosts."${cfg.hostName}" = mkMerge [
cfg.nginx
{
root = mkForce "${cfg.package}/share/mainsail";
locations = {
"/" = {
index = "index.html";
tryFiles = "$uri $uri/ /index.html";
};
"/index.html".extraConfig = ''
add_header Cache-Control "no-store, no-cache, must-revalidate";
'';
"/websocket" = {
proxyWebsockets = true;
proxyPass = "http://mainsail-apiserver/websocket";
};
"~ ^/(printer|api|access|machine|server)/" = {
proxyWebsockets = true;
proxyPass = "http://mainsail-apiserver$request_uri";
};
};
}
];
};
};
}

View file

@ -588,11 +588,12 @@ in {
'';
}
{
assertion = 1 == builtins.length
(lib.mapAttrsToList
(_: v: builtins.elem "scheduler" v.jobClasses || v.jobClasses == [ ])
cfg.sidekiqProcesses);
message = "There must be one and only one Sidekiq queue in services.mastodon.sidekiqProcesses with jobClass \"scheduler\".";
assertion = 1 ==
(lib.count (x: x)
(lib.mapAttrsToList
(_: v: builtins.elem "scheduler" v.jobClasses || v.jobClasses == [ ])
cfg.sidekiqProcesses));
message = "There must be exactly one Sidekiq queue in services.mastodon.sidekiqProcesses with jobClass \"scheduler\".";
}
];

View file

@ -3,7 +3,7 @@
Matomo is a real-time web analytics application. This module configures
php-fpm as backend for Matomo, optionally configuring an nginx vhost as well.
An automatic setup is not suported by Matomo, so you need to configure Matomo
An automatic setup is not supported by Matomo, so you need to configure Matomo
itself in the browser-based Matomo setup.
## Database Setup {#module-services-matomo-database-setup}

View file

@ -2,6 +2,7 @@
let
cfg = config.services.nextcloud.notify_push;
cfgN = config.services.nextcloud;
in
{
options.services.nextcloud.notify_push = {
@ -25,6 +26,16 @@ in
default = "error";
description = lib.mdDoc "Log level";
};
bendDomainToLocalhost = lib.mkOption {
type = lib.types.bool;
default = false;
description = lib.mdDoc ''
Wether to add an entry to `/etc/hosts` for the configured nextcloud domain to point to `localhost` and add `localhost `to nextcloud's `trusted_proxies` config option.
This is useful when nextcloud's domain is not a static IP address and when the reverse proxy cannot be bypassed because the backend connection is done via unix socket.
'';
};
} // (
lib.genAttrs [
"dbtype"
@ -44,11 +55,14 @@ in
config = lib.mkIf cfg.enable {
systemd.services.nextcloud-notify_push = let
nextcloudUrl = "http${lib.optionalString config.services.nextcloud.https "s"}://${config.services.nextcloud.hostName}";
nextcloudUrl = "http${lib.optionalString cfgN.https "s"}://${cfgN.hostName}";
in {
description = "Push daemon for Nextcloud clients";
documentation = [ "https://github.com/nextcloud/notify_push" ];
after = [ "phpfpm-nextcloud.service" ];
after = [
"phpfpm-nextcloud.service"
"redis-nextcloud.service"
];
wantedBy = [ "multi-user.target" ];
environment = {
NEXTCLOUD_URL = nextcloudUrl;
@ -57,7 +71,7 @@ in
LOG = cfg.logLevel;
};
postStart = ''
${config.services.nextcloud.occ}/bin/nextcloud-occ notify_push:setup ${nextcloudUrl}/push
${cfgN.occ}/bin/nextcloud-occ notify_push:setup ${nextcloudUrl}/push
'';
script = let
dbType = if cfg.dbtype == "pgsql" then "postgresql" else cfg.dbtype;
@ -76,7 +90,7 @@ in
export DATABASE_PASSWORD="$(<"${cfg.dbpassFile}")"
'' + ''
export DATABASE_URL="${dbUrl}"
${cfg.package}/bin/notify_push '${config.services.nextcloud.datadir}/config/config.php'
${cfg.package}/bin/notify_push '${cfgN.datadir}/config/config.php'
'';
serviceConfig = {
User = "nextcloud";
@ -87,10 +101,23 @@ in
};
};
services.nginx.virtualHosts.${config.services.nextcloud.hostName}.locations."^~ /push/" = {
proxyPass = "http://unix:${cfg.socketPath}";
proxyWebsockets = true;
recommendedProxySettings = true;
networking.hosts = lib.mkIf cfg.bendDomainToLocalhost {
"127.0.0.1" = [ cfgN.hostName ];
"::1" = [ cfgN.hostName ];
};
services = lib.mkMerge [
{
nginx.virtualHosts.${cfgN.hostName}.locations."^~ /push/" = {
proxyPass = "http://unix:${cfg.socketPath}";
proxyWebsockets = true;
recommendedProxySettings = true;
};
}
(lib.mkIf cfg.bendDomainToLocalhost {
nextcloud.extraOptions.trusted_proxies = [ "127.0.0.1" "::1" ];
})
];
};
}

View file

@ -17,11 +17,12 @@ and optionally supports
For the database, you can set
[`services.nextcloud.config.dbtype`](#opt-services.nextcloud.config.dbtype) to
either `sqlite` (the default), `mysql`, or `pgsql`. For the last two, by
default, a local database will be created and nextcloud will connect to it via
socket; this can be disabled by setting
either `sqlite` (the default), `mysql`, or `pgsql`. The simplest is `sqlite`,
which will be automatically created and managed by the application. For the
last two, you can easily create a local database by setting
[`services.nextcloud.database.createLocally`](#opt-services.nextcloud.database.createLocally)
to `false`.
to `true`, Nextcloud will automatically be configured to connect to it through
socket.
A very basic configuration may look like this:
```
@ -30,6 +31,7 @@ A very basic configuration may look like this:
services.nextcloud = {
enable = true;
hostName = "nextcloud.tld";
database.createLocally = true;
config = {
dbtype = "pgsql";
adminpassFile = "/path/to/admin-pass-file";

View file

@ -317,7 +317,7 @@ in {
createLocally = mkOption {
type = types.bool;
default = true;
default = false;
description = lib.mdDoc ''
Create the database and database user locally.
'';
@ -551,6 +551,19 @@ in {
default = true;
};
configureRedis = lib.mkOption {
type = lib.types.bool;
default = config.services.nextcloud.notify_push.enable;
defaultText = literalExpression "config.services.nextcloud.notify_push.enable";
description = lib.mdDoc ''
Wether to configure nextcloud to use the recommended redis settings for small instances.
::: {.note}
The `notify_push` app requires redis to be configured. If this option is turned off, this must be configured manually.
:::
'';
};
caching = {
apcu = mkOption {
type = types.bool;
@ -741,9 +754,8 @@ in {
{ assertions = [
{ assertion = cfg.database.createLocally -> cfg.config.dbpassFile == null;
message = ''
Using `services.nextcloud.database.createLocally` (that now defaults
to true) with database password authentication is no longer
supported.
Using `services.nextcloud.database.createLocally` with database
password authentication is no longer supported.
If you use an external database (or want to use password auth for any
other reason), set `services.nextcloud.database.createLocally` to
@ -1044,6 +1056,25 @@ in {
}];
};
services.redis.servers.nextcloud = lib.mkIf cfg.configureRedis {
enable = true;
user = "nextcloud";
};
services.nextcloud = lib.mkIf cfg.configureRedis {
caching.redis = true;
extraOptions = {
memcache = {
distributed = ''\OC\Memcache\Redis'';
locking = ''\OC\Memcache\Redis'';
};
redis = {
host = config.services.redis.servers.nextcloud.unixSocket;
port = 0;
};
};
};
services.nginx.enable = mkDefault true;
services.nginx.virtualHosts.${cfg.hostName} = {

View file

@ -0,0 +1,211 @@
{ config, lib, pkgs, ... }:
let
cfg = config.services.openvscode-server;
defaultUser = "openvscode-server";
defaultGroup = defaultUser;
in {
options = {
services.openvscode-server = {
enable = lib.mkEnableOption (lib.mdDoc "openvscode-server");
package = lib.mkPackageOptionMD pkgs "openvscode-server" { };
extraPackages = lib.mkOption {
default = [ ];
description = lib.mdDoc ''
Additional packages to add to the openvscode-server {env}`PATH`.
'';
example = lib.literalExpression "[ pkgs.go ]";
type = lib.types.listOf lib.types.package;
};
extraEnvironment = lib.mkOption {
type = lib.types.attrsOf lib.types.str;
description = lib.mdDoc ''
Additional environment variables to pass to openvscode-server.
'';
default = { };
example = { PKG_CONFIG_PATH = "/run/current-system/sw/lib/pkgconfig"; };
};
extraArguments = lib.mkOption {
default = [ ];
description = lib.mdDoc ''
Additional arguments to pass to openvscode-server.
'';
example = lib.literalExpression ''[ "--log=info" ]'';
type = lib.types.listOf lib.types.str;
};
host = lib.mkOption {
default = "localhost";
description = lib.mdDoc ''
The host name or IP address the server should listen to.
'';
type = lib.types.str;
};
port = lib.mkOption {
default = 3000;
description = lib.mdDoc ''
The port the server should listen to. If 0 is passed a random free port is picked. If a range in the format num-num is passed, a free port from the range (end inclusive) is selected.
'';
type = lib.types.port;
};
user = lib.mkOption {
default = defaultUser;
example = "yourUser";
description = lib.mdDoc ''
The user to run openvscode-server as.
By default, a user named `${defaultUser}` will be created.
'';
type = lib.types.str;
};
group = lib.mkOption {
default = defaultGroup;
example = "yourGroup";
description = lib.mdDoc ''
The group to run openvscode-server under.
By default, a group named `${defaultGroup}` will be created.
'';
type = lib.types.str;
};
extraGroups = lib.mkOption {
default = [ ];
description = lib.mdDoc ''
An array of additional groups for the `${defaultUser}` user.
'';
example = [ "docker" ];
type = lib.types.listOf lib.types.str;
};
withoutConnectionToken = lib.mkOption {
default = false;
description = lib.mdDoc ''
Run without a connection token. Only use this if the connection is secured by other means.
'';
example = true;
type = lib.types.bool;
};
socketPath = lib.mkOption {
default = null;
example = "/run/openvscode/socket";
description = lib.mdDoc ''
The path to a socket file for the server to listen to.
'';
type = lib.types.nullOr lib.types.str;
};
userDataDir = lib.mkOption {
default = null;
description = lib.mdDoc ''
Specifies the directory that user data is kept in. Can be used to open multiple distinct instances of Code.
'';
type = lib.types.nullOr lib.types.str;
};
serverDataDir = lib.mkOption {
default = null;
description = lib.mdDoc ''
Specifies the directory that server data is kept in.
'';
type = lib.types.nullOr lib.types.str;
};
extensionsDir = lib.mkOption {
default = null;
description = lib.mdDoc ''
Set the root path for extensions.
'';
type = lib.types.nullOr lib.types.str;
};
telemetryLevel = lib.mkOption {
default = "off";
example = "crash";
description = lib.mdDoc ''
Sets the initial telemetry level. Valid levels are: 'off', 'crash', 'error' and 'all'.
'';
type = lib.types.str;
};
connectionToken = lib.mkOption {
default = null;
example = "secret-token";
description = lib.mdDoc ''
A secret that must be included with all requests.
'';
type = lib.types.nullOr lib.types.str;
};
connectionTokenFile = lib.mkOption {
default = null;
description = lib.mdDoc ''
Path to a file that contains the connection token.
'';
type = lib.types.nullOr lib.types.str;
};
};
};
config = lib.mkIf cfg.enable {
systemd.services.openvscode-server = {
description = "OpenVSCode server";
wantedBy = [ "multi-user.target" ];
after = [ "network-online.target" ];
path = cfg.extraPackages;
environment = cfg.extraEnvironment;
serviceConfig = {
ExecStart = ''
${lib.getExe cfg.package} \
--accept-server-license-terms \
--host=${cfg.host} \
--port=${toString cfg.port} \
'' + lib.optionalString (cfg.telemetryLevel == true) ''
--telemetry-level=${cfg.telemetryLevel} \
'' + lib.optionalString (cfg.withoutConnectionToken == true) ''
--without-connection-token \
'' + lib.optionalString (cfg.socketPath != null) ''
--socket-path=${cfg.socketPath} \
'' + lib.optionalString (cfg.userDataDir != null) ''
--user-data-dir=${cfg.userDataDir} \
'' + lib.optionalString (cfg.serverDataDir != null) ''
--server-data-dir=${cfg.serverDataDir} \
'' + lib.optionalString (cfg.extensionsDir != null) ''
--extensions-dir=${cfg.extensionsDir} \
'' + lib.optionalString (cfg.connectionToken != null) ''
--connection-token=${cfg.connectionToken} \
'' + lib.optionalString (cfg.connectionTokenFile != null) ''
--connection-token-file=${cfg.connectionTokenFile} \
'' + lib.escapeShellArgs cfg.extraArguments;
ExecReload = "${pkgs.coreutils}/bin/kill -HUP $MAINPID";
RuntimeDirectory = cfg.user;
User = cfg.user;
Group = cfg.group;
Restart = "on-failure";
};
};
users.users."${cfg.user}" = lib.mkMerge [
(lib.mkIf (cfg.user == defaultUser) {
isNormalUser = true;
description = "openvscode-server user";
inherit (cfg) group;
})
{
packages = cfg.extraPackages;
inherit (cfg) extraGroups;
}
];
users.groups."${defaultGroup}" = lib.mkIf (cfg.group == defaultGroup) { };
};
meta.maintainers = [ lib.maintainers.drupol ];
}

View file

@ -429,7 +429,7 @@ in {
environment = env;
path = with pkgs; [ bashInteractive ffmpeg nodejs_16 openssl yarn python3 ];
path = with pkgs; [ bashInteractive ffmpeg nodejs_18 openssl yarn python3 ];
script = ''
#!/bin/sh
@ -490,7 +490,7 @@ in {
services.nginx = lib.mkIf cfg.configureNginx {
enable = true;
virtualHosts."${cfg.localDomain}" = {
root = "/var/lib/peertube";
root = "/var/lib/peertube/www";
# Application
locations."/" = {
@ -593,7 +593,7 @@ in {
# Bypass PeerTube for performance reasons.
locations."~ ^/client/(assets/images/(icons/icon-36x36\.png|icons/icon-48x48\.png|icons/icon-72x72\.png|icons/icon-96x96\.png|icons/icon-144x144\.png|icons/icon-192x192\.png|icons/icon-512x512\.png|logo\.svg|favicon\.png|default-playlist\.jpg|default-avatar-account\.png|default-avatar-account-48x48\.png|default-avatar-video-channel\.png|default-avatar-video-channel-48x48\.png))$" = {
tryFiles = "/www/client-overrides/$1 /www/client/$1 $1";
tryFiles = "/client-overrides/$1 /client/$1 $1";
priority = 1310;
};
@ -859,7 +859,7 @@ in {
home = cfg.package;
};
})
(lib.attrsets.setAttrByPath [ cfg.user "packages" ] [ cfg.package peertubeEnv peertubeCli pkgs.ffmpeg pkgs.nodejs_16 pkgs.yarn ])
(lib.attrsets.setAttrByPath [ cfg.user "packages" ] [ cfg.package peertubeEnv peertubeCli pkgs.ffmpeg pkgs.nodejs_18 pkgs.yarn ])
(lib.mkIf cfg.redis.enableUnixSocket {${config.services.peertube.user}.extraGroups = [ "redis-peertube" ];})
];

View file

@ -34,8 +34,8 @@ in
config = lib.mkIf cfg.enable {
systemd.services.pict-rs = {
environment = {
PICTRS_PATH = cfg.dataDir;
PICTRS_ADDR = "${cfg.address}:${toString cfg.port}";
PICTRS__PATH = cfg.dataDir;
PICTRS__ADDR = "${cfg.address}:${toString cfg.port}";
};
wantedBy = [ "multi-user.target" ];
serviceConfig = {

View file

@ -0,0 +1,478 @@
{ config, lib, pkgs, ... }:
with lib;
let
cfg = config.services.pixelfed;
user = cfg.user;
group = cfg.group;
pixelfed = cfg.package.override { inherit (cfg) dataDir runtimeDir; };
# https://github.com/pixelfed/pixelfed/blob/dev/app/Console/Commands/Installer.php#L185-L190
extraPrograms = with pkgs; [ jpegoptim optipng pngquant gifsicle ffmpeg ];
# Ensure PHP extensions: https://github.com/pixelfed/pixelfed/blob/dev/app/Console/Commands/Installer.php#L135-L147
phpPackage = cfg.phpPackage.buildEnv {
extensions = { enabled, all }:
enabled
++ (with all; [ bcmath ctype curl mbstring gd intl zip redis imagick ]);
};
configFile =
pkgs.writeText "pixelfed-env" (lib.generators.toKeyValue { } cfg.settings);
# Management script
pixelfed-manage = pkgs.writeShellScriptBin "pixelfed-manage" ''
cd ${pixelfed}
sudo=exec
if [[ "$USER" != ${user} ]]; then
sudo='exec /run/wrappers/bin/sudo -u ${user}'
fi
$sudo ${cfg.phpPackage}/bin/php artisan "$@"
'';
dbSocket = {
"pgsql" = "/run/postgresql";
"mysql" = "/run/mysqld/mysqld.sock";
}.${cfg.database.type};
dbService = {
"pgsql" = "postgresql.service";
"mysql" = "mysql.service";
}.${cfg.database.type};
redisService = "redis-pixelfed.service";
in {
options.services = {
pixelfed = {
enable = mkEnableOption (lib.mdDoc "a Pixelfed instance");
package = mkPackageOptionMD pkgs "pixelfed" { };
phpPackage = mkPackageOptionMD pkgs "php81" { };
user = mkOption {
type = types.str;
default = "pixelfed";
description = lib.mdDoc ''
User account under which pixelfed runs.
::: {.note}
If left as the default value this user will automatically be created
on system activation, otherwise you are responsible for
ensuring the user exists before the pixelfed application starts.
:::
'';
};
group = mkOption {
type = types.str;
default = "pixelfed";
description = lib.mdDoc ''
Group account under which pixelfed runs.
::: {.note}
If left as the default value this group will automatically be created
on system activation, otherwise you are responsible for
ensuring the group exists before the pixelfed application starts.
:::
'';
};
domain = mkOption {
type = types.str;
description = lib.mdDoc ''
FQDN for the Pixelfed instance.
'';
};
secretFile = mkOption {
type = types.path;
description = lib.mdDoc ''
A secret file to be sourced for the .env settings.
Place `APP_KEY` and other settings that should not end up in the Nix store here.
'';
};
settings = mkOption {
type = with types; (attrsOf (oneOf [ bool int str ]));
description = lib.mdDoc ''
.env settings for Pixelfed.
Secrets should use `secretFile` option instead.
'';
};
nginx = mkOption {
type = types.nullOr (types.submodule
(import ../web-servers/nginx/vhost-options.nix {
inherit config lib;
}));
default = null;
example = lib.literalExpression ''
{
serverAliases = [
"pics.''${config.networking.domain}"
];
enableACME = true;
forceHttps = true;
}
'';
description = lib.mdDoc ''
With this option, you can customize an nginx virtual host which already has sensible defaults for Dolibarr.
Set to {} if you do not need any customization to the virtual host.
If enabled, then by default, the {option}`serverName` is
`''${domain}`,
If this is set to null (the default), no nginx virtualHost will be configured.
'';
};
redis.createLocally = mkEnableOption
(lib.mdDoc "a local Redis database using UNIX socket authentication")
// {
default = true;
};
database = {
createLocally = mkEnableOption
(lib.mdDoc "a local database using UNIX socket authentication") // {
default = true;
};
automaticMigrations = mkEnableOption
(lib.mdDoc "automatic migrations for database schema and data") // {
default = true;
};
type = mkOption {
type = types.enum [ "mysql" "pgsql" ];
example = "pgsql";
default = "mysql";
description = lib.mdDoc ''
Database engine to use.
Note that PGSQL is not well supported: https://github.com/pixelfed/pixelfed/issues/2727
'';
};
name = mkOption {
type = types.str;
default = "pixelfed";
description = lib.mdDoc "Database name.";
};
};
maxUploadSize = mkOption {
type = types.str;
default = "8M";
description = lib.mdDoc ''
Max upload size with units.
'';
};
poolConfig = mkOption {
type = with types; attrsOf (oneOf [ int str bool ]);
default = { };
description = lib.mdDoc ''
Options for Pixelfed's PHP-FPM pool.
'';
};
dataDir = mkOption {
type = types.str;
default = "/var/lib/pixelfed";
description = lib.mdDoc ''
State directory of the `pixelfed` user which holds
the application's state and data.
'';
};
runtimeDir = mkOption {
type = types.str;
default = "/run/pixelfed";
description = lib.mdDoc ''
Ruutime directory of the `pixelfed` user which holds
the application's caches and temporary files.
'';
};
schedulerInterval = mkOption {
type = types.str;
default = "1d";
description = lib.mdDoc "How often the Pixelfed cron task should run";
};
};
};
config = mkIf cfg.enable {
users.users.pixelfed = mkIf (cfg.user == "pixelfed") {
isSystemUser = true;
group = cfg.group;
extraGroups = lib.optional cfg.redis.createLocally "redis-pixelfed";
};
users.groups.pixelfed = mkIf (cfg.group == "pixelfed") { };
services.redis.servers.pixelfed.enable = lib.mkIf cfg.redis.createLocally true;
services.pixelfed.settings = mkMerge [
({
APP_ENV = mkDefault "production";
APP_DEBUG = mkDefault false;
# https://github.com/pixelfed/pixelfed/blob/dev/app/Console/Commands/Installer.php#L312-L316
APP_URL = mkDefault "https://${cfg.domain}";
ADMIN_DOMAIN = mkDefault cfg.domain;
APP_DOMAIN = mkDefault cfg.domain;
SESSION_DOMAIN = mkDefault cfg.domain;
SESSION_SECURE_COOKIE = mkDefault true;
OPEN_REGISTRATION = mkDefault false;
# ActivityPub: https://github.com/pixelfed/pixelfed/blob/dev/app/Console/Commands/Installer.php#L360-L364
ACTIVITY_PUB = mkDefault true;
AP_REMOTE_FOLLOW = mkDefault true;
AP_INBOX = mkDefault true;
AP_OUTBOX = mkDefault true;
AP_SHAREDINBOX = mkDefault true;
# Image optimization: https://github.com/pixelfed/pixelfed/blob/dev/app/Console/Commands/Installer.php#L367-L404
PF_OPTIMIZE_IMAGES = mkDefault true;
IMAGE_DRIVER = mkDefault "imagick";
# Mobile APIs
OAUTH_ENABLED = mkDefault true;
# https://github.com/pixelfed/pixelfed/blob/dev/app/Console/Commands/Installer.php#L351
EXP_EMC = mkDefault true;
# Defer to systemd
LOG_CHANNEL = mkDefault "stderr";
# TODO: find out the correct syntax?
# TRUST_PROXIES = mkDefault "127.0.0.1/8, ::1/128";
})
(mkIf (cfg.redis.createLocally) {
BROADCAST_DRIVER = mkDefault "redis";
CACHE_DRIVER = mkDefault "redis";
QUEUE_DRIVER = mkDefault "redis";
SESSION_DRIVER = mkDefault "redis";
WEBSOCKET_REPLICATION_MODE = mkDefault "redis";
# Suppport phpredis and predis configuration-style.
REDIS_SCHEME = "unix";
REDIS_HOST = config.services.redis.servers.pixelfed.unixSocket;
REDIS_PATH = config.services.redis.servers.pixelfed.unixSocket;
})
(mkIf (cfg.database.createLocally) {
DB_CONNECTION = cfg.database.type;
DB_SOCKET = dbSocket;
DB_DATABASE = cfg.database.name;
DB_USERNAME = user;
# No TCP/IP connection.
DB_PORT = 0;
})
];
environment.systemPackages = [ pixelfed-manage ];
services.mysql =
mkIf (cfg.database.createLocally && cfg.database.type == "mysql") {
enable = mkDefault true;
package = mkDefault pkgs.mariadb;
ensureDatabases = [ cfg.database.name ];
ensureUsers = [{
name = user;
ensurePermissions = { "${cfg.database.name}.*" = "ALL PRIVILEGES"; };
}];
};
services.postgresql =
mkIf (cfg.database.createLocally && cfg.database.type == "pgsql") {
enable = mkDefault true;
ensureDatabases = [ cfg.database.name ];
ensureUsers = [{
name = user;
ensurePermissions = { };
}];
};
# Make each individual option overridable with lib.mkDefault.
services.pixelfed.poolConfig = lib.mapAttrs' (n: v: lib.nameValuePair n (lib.mkDefault v)) {
"pm" = "dynamic";
"php_admin_value[error_log]" = "stderr";
"php_admin_flag[log_errors]" = true;
"catch_workers_output" = true;
"pm.max_children" = "32";
"pm.start_servers" = "2";
"pm.min_spare_servers" = "2";
"pm.max_spare_servers" = "4";
"pm.max_requests" = "500";
};
services.phpfpm.pools.pixelfed = {
inherit user group;
inherit phpPackage;
phpOptions = ''
post_max_size = ${toString cfg.maxUploadSize}
upload_max_filesize = ${toString cfg.maxUploadSize}
max_execution_time = 600;
'';
settings = {
"listen.owner" = user;
"listen.group" = group;
"listen.mode" = "0660";
"catch_workers_output" = "yes";
} // cfg.poolConfig;
};
systemd.services.phpfpm-pixelfed.after = [ "pixelfed-data-setup.service" ];
systemd.services.phpfpm-pixelfed.requires =
[ "pixelfed-horizon.service" "pixelfed-data-setup.service" ]
++ lib.optional cfg.database.createLocally dbService
++ lib.optional cfg.redis.createLocally redisService;
# Ensure image optimizations programs are available.
systemd.services.phpfpm-pixelfed.path = extraPrograms;
systemd.services.pixelfed-horizon = {
description = "Pixelfed task queueing via Laravel Horizon framework";
after = [ "network.target" "pixelfed-data-setup.service" ];
requires = [ "pixelfed-data-setup.service" ]
++ (lib.optional cfg.database.createLocally dbService)
++ (lib.optional cfg.redis.createLocally redisService);
wantedBy = [ "multi-user.target" ];
# Ensure image optimizations programs are available.
path = extraPrograms;
serviceConfig = {
Type = "simple";
ExecStart = "${pixelfed-manage}/bin/pixelfed-manage horizon";
StateDirectory =
lib.mkIf (cfg.dataDir == "/var/lib/pixelfed") "pixelfed";
User = user;
Group = group;
Restart = "on-failure";
};
};
systemd.timers.pixelfed-cron = {
description = "Pixelfed periodic tasks timer";
after = [ "pixelfed-data-setup.service" ];
requires = [ "phpfpm-pixelfed.service" ];
wantedBy = [ "timers.target" ];
timerConfig = {
OnBootSec = cfg.schedulerInterval;
OnUnitActiveSec = cfg.schedulerInterval;
};
};
systemd.services.pixelfed-cron = {
description = "Pixelfed periodic tasks";
# Ensure image optimizations programs are available.
path = extraPrograms;
serviceConfig = {
ExecStart = "${pixelfed-manage}/bin/pixelfed-manage schedule:run";
User = user;
Group = group;
StateDirectory = cfg.dataDir;
};
};
systemd.services.pixelfed-data-setup = {
description =
"Pixelfed setup: migrations, environment file update, cache reload, data changes";
wantedBy = [ "multi-user.target" ];
after = lib.optional cfg.database.createLocally dbService;
requires = lib.optional cfg.database.createLocally dbService;
path = with pkgs; [ bash pixelfed-manage rsync ] ++ extraPrograms;
serviceConfig = {
Type = "oneshot";
User = user;
Group = group;
StateDirectory =
lib.mkIf (cfg.dataDir == "/var/lib/pixelfed") "pixelfed";
LoadCredential = "env-secrets:${cfg.secretFile}";
UMask = "077";
};
script = ''
# Concatenate non-secret .env and secret .env
rm -f ${cfg.dataDir}/.env
cp --no-preserve=all ${configFile} ${cfg.dataDir}/.env
echo -e '\n' >> ${cfg.dataDir}/.env
cat "$CREDENTIALS_DIRECTORY/env-secrets" >> ${cfg.dataDir}/.env
# Link the static storage (package provided) to the runtime storage
# Necessary for cities.json and static images.
mkdir -p ${cfg.dataDir}/storage
rsync -av --no-perms ${pixelfed}/storage-static/ ${cfg.dataDir}/storage
chmod -R +w ${cfg.dataDir}/storage
# Link the app.php in the runtime folder.
# We cannot link the cache folder only because bootstrap folder needs to be writeable.
ln -sf ${pixelfed}/bootstrap-static/app.php ${cfg.runtimeDir}/app.php
# https://laravel.com/docs/10.x/filesystem#the-public-disk
# Creating the public/storage → storage/app/public link
# is unnecessary as it's part of the installPhase of pixelfed.
# Install Horizon
# FIXME: require write access to public/ — should be done as part of install — pixelfed-manage horizon:publish
# Before running any PHP program, cleanup the bootstrap.
# It's necessary if you upgrade the application otherwise you might
# try to import non-existent modules.
rm -rf ${cfg.runtimeDir}/bootstrap/*
# Perform the first migration.
[[ ! -f ${cfg.dataDir}/.initial-migration ]] && pixelfed-manage migrate --force && touch ${cfg.dataDir}/.initial-migration
${lib.optionalString cfg.database.automaticMigrations ''
# Force migrate the database.
pixelfed-manage migrate --force
''}
# Import location data
pixelfed-manage import:cities
${lib.optionalString cfg.settings.ACTIVITY_PUB ''
# ActivityPub federation bookkeeping
[[ ! -f ${cfg.dataDir}/.instance-actor-created ]] && pixelfed-manage instance:actor && touch ${cfg.dataDir}/.instance-actor-created
''}
${lib.optionalString cfg.settings.OAUTH_ENABLED ''
# Generate Passport encryption keys
[[ ! -f ${cfg.dataDir}/.passport-keys-generated ]] && pixelfed-manage passport:keys && touch ${cfg.dataDir}/.passport-keys-generated
''}
pixelfed-manage route:cache
pixelfed-manage view:cache
pixelfed-manage config:cache
'';
};
systemd.tmpfiles.rules = [
# Cache must live across multiple systemd units runtimes.
"d ${cfg.runtimeDir}/ 0700 ${user} ${group} - -"
"d ${cfg.runtimeDir}/cache 0700 ${user} ${group} - -"
];
# Enable NGINX to access our phpfpm-socket.
users.users."${config.services.nginx.group}".extraGroups = [ cfg.group ];
services.nginx = mkIf (cfg.nginx != null) {
enable = true;
virtualHosts."${cfg.domain}" = mkMerge [
cfg.nginx
{
root = lib.mkForce "${pixelfed}/public/";
locations."/".tryFiles = "$uri $uri/ /index.php?query_string";
locations."/favicon.ico".extraConfig = ''
access_log off; log_not_found off;
'';
locations."/robots.txt".extraConfig = ''
access_log off; log_not_found off;
'';
locations."~ \\.php$".extraConfig = ''
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:${config.services.phpfpm.pools.pixelfed.socket};
fastcgi_index index.php;
'';
locations."~ /\\.(?!well-known).*".extraConfig = ''
deny all;
'';
extraConfig = ''
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header X-Content-Type-Options "nosniff";
index index.html index.htm index.php;
error_page 404 /index.php;
client_max_body_size ${toString cfg.maxUploadSize};
'';
}
];
};
};
}

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